事务管理
事务回顾:
原子性:要么全成功,要么全失败
一致性:事务前后,数据总数不变
隔离性:事务隔离,避免脏读,重复读等等
持久性:只要事务完成,数据就会持久化到数据库中
事务问题
脏读(必须杜绝):在一个事务中,读取到了另一个事务还没有提交的数据
重复读(可以允许):一个事务,两次读取到的数据内容不同(update)
虚读(可以允许):一个事务,两次读取的数据不同(insert)
回顾:硬编码方式
setAutoConmmit(false):取消自动提交
commit():提交事务
rollback():回滚事务
Spring事务
Spring已经给我们封装好了事务管理,以往我们使用的是硬编码方式,
然而实际开发中很少这么使用,但是为了理解xml和注解方式,还是需要了解
硬编码(api)
1.接口:PlatformTransactionManager:平台事务管理器(封装事务的方法)
—-实现类:DataSourceTransactionManager
dbutils,jdbcTempalte 使用DataSourceTransactionManager
—-实现类:HibernateTransactionManager
hibernate 使用HibernateTransactionManager
2.TransactionDefinition:事务的定义信息对象
设定/获取:事务的隔离级别(默认获取的就是数据库的隔离级别)
事务的超时时间(默认 time = -1 永不超时)
事务的是否只读(默认 rederOnly = false 可以做任何的CRUD操作)
事务的传播行为(解决:事务嵌套事务的问题)
应用场景:A方法中有事务,B方法也有事务
问:用谁的事务???
REQUIRED(默认值):让所有方法在一个事务中
a方法调用b方法,b先看看a有没有事务,
如果a没有事务,就为a创建一个事务,然后加入a中,
如果a有事务,就放弃自己的事务,然后加入a中。
SUPPORT:查看当前是否有事务,如果有事务就使用当前的事务,如果没事务就使用非事务。
a方法调用b方法,b先看看a有没有事务,
如果a有事务,加入到a。
如果a没事务,全部放弃事务,使用非事务。
3.TransactionStatus 运行状态对象
查看事务的运行状态
查看事务当前是否完成
查看是否为新的事务
查看是否回滚.....
Spring声明式事务
配置文件的方式–xml方式
接下来就要使用xml配置的方式来使用事务了
导包
spring-tx.jar
以及AOP联盟
spring-aop.jar
aspectj.jar
spring-aspects.jar
applicationContext.xml的配置如下
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--c3p0:-->
<bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--Spring配置jdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="c3p0"></property>
</bean>
<!--配置bean-->
<bean id="dao" class="test.daoTest">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<bean id="service" class="test.serviceTest">
<property name="dao" ref="dao"></property>
</bean>
<!--配置事务管理器-->
<bean id="transaction" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="c3p0"></property>
</bean>
<tx:advice transaction-manager="transaction" id="txadvice">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--织入-->
<aop:config>
<aop:pointcut id="point" expression="execution(public void test.serviceTest.*(..))"/>
<aop:advisor advice-ref="txadvice" pointcut-ref="point"/>
</aop:config>
</beans>
Spring 注解式事务
需要添加
<context:component-scan base-package = “包名”></context:component-scan>
<tx:annotation-driven transaction-manager = “transactionManager”/>
然后在需要代理的方法或类上添加
@Transactional
写在最后的心得体会
以上是我的测试内容及结果,实际上遇到了很多问题
特意记录在此:
首先,java动态代理需要一个被代理类所实现的接口类,
Proxy始终无法摆脱仅支持 interface 代理的桎梏,
因为它的设计注定了这个遗憾。
java 的继承机制注定了这些动态代理类们无法实现对 class 的动态代理,
原因是多继承在 Java 中本质上就行不通。
总结
Spring的事务实际上就是spring 在启动的时候会去解析生成相关的bean,
就是为了在Spring容器中创建一个切面类的对象,
这时候会查看拥有相关注解的类和方法,并且为这些类和方法生成代理,
并根据相关参数进行相关配置注入,这样就在代理中为我们把相关的事务处理掉了(开启正常提交事务,异常回滚事务)
所以我之所以之前产生了很多问题的原因就是因为我对于AOP思想还是似懂非懂,经此一役,希望自己能够融会贯通。