Spring之事务管理
Connection conn = null; try{ conn = getConnection(); conn.setAutoCommit(false); //关闭事务的自动提交 A B C D conn.commit(); }catch(){ conn.rollback(); }
Connection conn = null; Savepoint savepoint = null; try{ conn = getConnection(); conn.setAutoCommit(false); //关闭事务的自动提交 A B savepoint = conn.setSavepoint(); C D conn.commit(); }catch(){ if(savepoint != null){ //savepoint不为空,说明已经执行到了C或者D conn.rollback(savepoint); //回滚到保存点 }else{ conn.rollback(); //savepoing为空,说明在执行A或者B的时候就抛了异常 } }
1. dao层
package cn.african.dao; public interface BankDao { boolean transfer(Long fromId, Long toId, double amount); } package cn.african.dao; import org.springframework.jdbc.core.support.JdbcDaoSupport; public class BankDaoImpl extends JdbcDaoSupport implements BankDao { @Override public boolean transfer(Long fromId, Long toId, double amount) { int f = this.getJdbcTemplate().update("update account set money = money - ? where id = ?", amount, fromId); //异常 int i = 1 / 0; int t = this.getJdbcTemplate().update("update account set money = money + ? where id = ?", amount, toId); if(f > 0 && t > 0) { return true; } return false; } }
2. service层
package cn.african.service; public interface BankService { public boolean transfer(Long fromId, Long toId, double amount); } package cn.african.service; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import cn.african.dao.BankDao; public class BankServiceImpl implements BankService { private BankDao bankDao; //事务详情 private TransactionDefinition txDefinition; //事务管理器 private PlatformTransactionManager txManager; @Override public boolean transfer(Long fromId, Long toId, double amount) { TransactionStatus txStatus = txManager.getTransaction(txDefinition); boolean result = false; try { result = bankDao.transfer(fromId, toId, amount); txManager.commit(txStatus); } catch (Exception e) { result = false; txManager.rollback(txStatus); System.out.println("转账失败"); } return result; } public void setBankDao(BankDao bankDao) { this.bankDao = bankDao; } public void setTxDefinition(TransactionDefinition txDefinition) { this.txDefinition = txDefinition; } public void setTxManager(PlatformTransactionManager txManager) { this.txManager = txManager; } }
3. applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/txdemo" /> <property name="user" value="root" /> <property name="password" value="123456" /> </bean> <bean id="bankDao" class="cn.african.dao.BankDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="bankService" class="cn.african.service.BankServiceImpl"> <property name="bankDao" ref="bankDao" /> <property name="txManager" ref="txManager" /> <!-- 定义事务详情 --> <property name="txDefinition"> <bean class="org.springframework.transaction.support.DefaultTransactionDefinition"> <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED" /> </bean> </property> </bean> </beans>
4. 测试类
package cn.african.test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.african.service.BankService; public class TestApp { @Test public void demo01() throws Exception { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); BankService bankService = context.getBean("bankService", BankService.class); bankService.transfer(1L, 2L, 1000D); context.getClass().getMethod("close").invoke(context); } }
package cn.african.service; public interface BankService { public boolean transfer(Long fromId, Long toId, double amount); } package cn.african.service; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; import cn.african.dao.BankDao; public class BankServiceImpl implements BankService { private BankDao bankDao; private TransactionTemplate transactionTemplate; @Override public boolean transfer(Long fromId, Long toId, double amount) { return transactionTemplate.execute(new TransactionCallback<Boolean>() { boolean result = false; @Override public Boolean doInTransaction(TransactionStatus status) { try { bankDao.transfer(fromId, toId, amount); result = true; } catch (Exception e) { //设置回滚 status.setRollbackOnly(); System.out.println("转账失败"); } return result; } }); } public void setBankDao(BankDao bankDao) { this.bankDao = bankDao; } public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } }
3. applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/txdemo" /> <property name="user" value="root" /> <property name="password" value="123456" /> </bean> <bean id="bankDao" class="cn.african.dao.BankDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="bankService" class="cn.african.service.BankServiceImpl"> <property name="bankDao" ref="bankDao"></property> <property name="transactionTemplate" ref="txTemplate"></property> </bean> <bean id="txTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="txManager"></property> </bean> </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ee19_spring_day03" /> <property name="user" value="root" /> <property name="password" value="123456" /> </bean> <bean id="bankDao" class="cn.african.dao.BankDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--这个事务拦截器就是切面--> <bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager" ref="txManager"/> <property name="transactionAttributes"> <props> <prop key="transfer">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <bean id="bankServiceTarget" class="cn.african.service.BankServiceImpl"> <property name="bankDao" ref="bankDao"/> </bean> <bean id="bankService" class="org.springframework.aop.framework.ProxyFactoryBean"> <!--目标类--> <property name="target" ref="bankServiceTarget"/> <!--配置切面--> <property name="interceptorNames"> <list> <idref bean="txInterceptor"/> </list> </property> </bean> </beans>
传播行为 [,隔离级别] [,只读属性] [,超时属性] [不影响提交的异常] [,导致回滚的异常]
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED,TIMEOUT_20,+AException,+BException,-CException</prop>
package cn.african.service; import cn.african.dao.BankDao; public class BankServiceImpl implements BankService { private BankDao bankDao; @Override public boolean transfer(Long fromId, Long toId, double amount) { //这种方式,在这里不能自己去捕获异常,这个异常必须由spring感知 return bankDao.transfer(fromId, toId, amount); } public void setBankDao(BankDao bankDao) { this.bankDao = bankDao; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ee19_spring_day03" /> <property name="user" value="root" /> <property name="password" value="123456" /> </bean> <bean id="bankDao" class="cn.african.dao.BankDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="bankServiceTarget" class="cn.african.service.BankServiceImpl"> <property name="bankDao" ref="bankDao"/> </bean> <bean id="bankService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="target" ref="bankServiceTarget"/> <property name="transactionManager" ref="txManager"/> <property name="transactionAttributes"> <props> <prop key="transfer">PROPAGATION_REQUIRED</prop> </props> </property> </bean> </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ee19_spring_day03" /> <property name="user" value="root" /> <property name="password" value="123456" /> </bean> <bean id="bankDao" class="cn.african.dao.BankDaoImpl"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="bankService" class="cn.african.service.BankServiceImpl"> <property name="bankDao" ref="bankDao"/> </bean> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="transfer" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--如果事务的默认配置就能满足需求,上面元素的配置可以简化为以下方式--> <!-- <tx:advice id="txAdvice" transaction-manager="txManager" /> --> <aop:config> <aop:pointcut expression="execution(* cn.african.service..*.*(..))" id="txPointcut"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> </aop:config> </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ee19_spring_day03" /> <property name="user" value="root" /> <property name="password" value="123456" /> </bean> <bean id="bankDao" class="cn.african.dao.BankDaoImpl"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="bankService" class="cn.african.service.BankServiceImpl"> <property name="bankDao" ref="bankDao"/> </bean> <!-- 使用事务注解时,必须要开启注解驱动 --> <tx:annotation-driven transaction-manager="txManager"/> </beans>