Spring事务管理
事务的特性:一致性、原子性、隔离性、持久性
Spring事务管理相关接口:PlatformTransactionManager(事务管理器)、TransactionDefinition(事务定义信息,隔离、传播、超时、只读)、TransactionStatus(事务具体运行状态)
1、事务管理器
相关的PlatformTransactionManager接口
2、事务隔离级别
当不考虑隔离性会引起一下问题:
(1)脏读:一个事务读取了另一个事务改写但未提交的数据,如果这些数据被回滚则读到的数据是无效的。A进行update、insert时候,B读取了中间状态不知道对不对的值。
(2)不可重复读:在同一事务中,多次读取同一数据返回的结果不同。B在A 的update操作前后,读到的数据不一致。
(3)幻读:一个事务读取了几行记录后,另一个事务插入一些记录,再后来查询中第一个事务就会发现有些原来没有的记录。B在A的insert操作前后,读到了的数据不一致。
事务的四种隔离级别,Mysql默认使用REPEATABLE_READ隔离级别,orcale默认使用READ_COMMOTTED
3、事务传播行为
事务传播行为:解决业务层方法之间的相互调用的问题
七种事务传播行为,其中分为三类。
第一类:PROPAGATION_REQUIRED(重点)、PROPAGATION_SUPPORTS、PROPAGATION_MANDATORY
第二类:PROPAGATION_REQUIRES_NEW(重点)、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER
第三类:PROPAGATION_NESTED(重点)
4、Spring事务管理的实现方式
(1)编码式事务管理:
手动编写代码进行事务管理(很少使用)
(2)声明式事务管理:
基于TransactionProxyFactoryBean的方式(很少使用):需要为每一个进行事务管理的类,配置一个TransactionProxyFactoryBean进行增强。
基于AspectJ的XML方式(经常使用):一旦配置好后,类不需要加任何东西。
基于注解的方式(经常使用):配置简单,需要在业务层类上或方法上加上一个注解@Transactional。
1、 手动编写代码进行事务管理
applicationContext.xml文件。(主要transactionManager和transactionTemplate)
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> bean> <bean id="accountDao" class="cn.muke.spring.demo1.AccountDaoImpl"> <property name="dataSource" ref="dataSource"/> bean> <bean id="accountService" class="cn.muke.spring.demo1.AccountServiceImpl"> <property name="accountDao" ref="accountDao"/> <property name="transactionTemplate" ref="transactionTemplate" /> bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> bean> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"/> bean>
业务类
实现transactionTemplate的execute
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; public class AccountServiceImpl implements AccountService { private AccountDao accountDao; private TransactionTemplate transactionTemplate; @Override public void transfer(final String out, final String in, Double money) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { accountDao.outMoney(out, money); int i = 1/0; accountDao.inMoney(in, money); } }); } public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } }
2、基于TransactionProxyFactoryBean的方式
applicationContext.xml(需要为每个类配置TransactionProxyFactoryBean)
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
bean>
<bean id="accountDao" class="cn.muke.spring.demo2.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
bean>
<bean id="accountService" class="cn.muke.spring.demo2.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target" ref="accountService"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticExceptionprop>
props>
property>
bean>
业务层(不需做任何代码改动)
public class AccountServiceImpl implements AccountService { private AccountDao accountDao; @Override public void transfer(String out, String in, Double money) { accountDao.outMoney(out, money); int i = 1 / 0; accountDao.inMoney(in, money); } public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } }
3、基于AspectJ的XML方式
applicationContext.xml(txAdvice,切面编程)
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
bean>
<bean id="accountDao" class="cn.muke.spring.demo3.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
bean>
<bean id="accountService" class="cn.muke.spring.demo3.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource">property>
bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer" propagation="REQUIRED" no-rollback-for="java.lang.ArithmeticException" />
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut expression="execution(* cn.muke.spring.demo3.AccountService+.*(..))" id="pointcut1"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
aop:config>
业务层(不需做任何代码改动)
public class AccountServiceImpl implements AccountService { private AccountDao accountDao; @Override public void transfer(String out, String in, Double money) { accountDao.outMoney(out, money); int i = 1 / 0; accountDao.inMoney(in, money); } public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } }
4、基于注解的方式
applicationContext.xml(开启注解事务)
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
bean>
<bean id="accountDao" class="cn.muke.spring.demo4.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
bean>
<bean id="accountService" class="cn.muke.spring.demo4.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource">property>
bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
业务层(增加注解@Transactional)
public class AccountServiceImpl implements AccountService { private AccountDao accountDao; /** * propagation :事务的传播行为 * isolation :事务的隔离级别 * readOnly :只读 * noRollbackFor :发生哪些异常事务不回滚 * noRollbackForClassName :发生哪些异常事务不回滚 * rollbackFor :发生哪些异常回滚事务 * rollbackForClassName :发生哪些异常回滚事务 */ @Override @Transactional(propagation = Propagation.REQUIRED) public void transfer(String out, String in, Double money) { accountDao.outMoney(out, money); try { int i = 1 / 0; } catch (Exception e) { throw new RuntimeException(); } accountDao.inMoney(in, money); } public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } }
项目代码在文件中