事务管理可以分为编程式事务管理和声明式事务管理。 编程式事务管理:类似命令式的事务管理,只是把涉及到事务操作的逻辑抽取成目标类,使用者只需要关注数据库操作;
声明式事务管理:声明式编程的事务管理方式,通过响应的配置,告诉让框架来我们需要达到什么样的效果,让框架来管理事务,而不需要使用者手动管理;
编程式事务管理 手动编写 不使用框架,纯粹开发者自己编写,可以使用Connection接口的commit,rollback方法,自行判断异常等逻辑进行手动事务管理;
Spring 事务模板 纯粹的开发自己编写,会存在大量的样板代码,比如Connection,statement的关闭等;Spring 提供和很多模板代码,可以解决这些问题,其中 Spring 就提供了事务的模板代码;
Spring 内部封装了一个事务管理的TransactionTemplate模板类,其内部的transactionManager专门负责事务管理,其最终也是调用Connection的commit,rollback方法进行事务管理;
下面的代码用到了Spring 依赖注入,注入了一个TransactionTemplate的实例;要执行的数据库操作,都在模板类中执行;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class AccountServiceImplPragram implements AccountService { private AccountDao accountDao; private TransactionTemplate transactionTemplate; public void transfer(final String out, final String in, final Double money) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { accountDao.inMoney(in, money); // int i = 1 / 0; accountDao.outMoney(out, money); } }); } public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } }
声明式事务管理 即使Spring 提供了事务管理的模板,当时事务管理还是有点繁琐,而且这种事务管理方式有一定的侵入性;
能否有一种方式,可以让Service只是普通的Service,在调用DAO层的时候无需关心其事务问题;
有! Spring 提供了如下三中方式,解决这个问题,其中基于注解的方式,和基于AspectJ xml,虽然还是有一定的侵入性,但是这种方式极其简单,是日常开发常用的事务管理方式;
基于TransactionProxyFactoryBean代理的方式,使用不方便,而且还具有侵入性,通常不使用;
基于 TransactionProxyFactoryBean代理的Service方式事务管理 这种基于 TransactionProxyFactoryBean代理的Service方式,每次增加一个Service就必须增加一个相对的TransactionProxyFactoryBean用于增强对应的Service类,使用起来不方便;然后将这个TransactionProxyFactoryBean注入到Controller中,具有侵入性;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:springconfig_statement1.xml") public class TestTransactionManagerStatement1 { @Resource(name = "transactionProxyFactoryBean") private AccountService accountService; @Test public void testTransactionManagerStatement1() { accountService.transfer("aaa", "bbb", 200d); } } <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="transactionProxyFactoryBean" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!--配置注入要增强的类--> <property name="target" ref="accountService"/> <!--配置注入transactionManager--> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <props> <!--key 可以是 instert update transfer --> <!--value 格式 PROPAGATION:事务的传播级别 ISOLATION :事务的隔离级别 readOnly : 只读 (不可以进行 instert update delete) -Exception : 发生哪些异常执行回滚 +Exception : 发生哪些异常 不执行回滚 <prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop> --> <prop key="transfer">PROPAGATION_REQUIRED</prop> </props> </property> </bean>
基于AspectJ xml 配置声明式的事务管理 通过Spring AOP 织入的方式给需要添加事务管理的方法增加事务管理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:springconfig_statement2.xml") public class TestTransactionManagerStatement2 { @Resource(name = "accountService") private AccountService accountService; @Test public void testTransactionManagerStatement2() { accountService.transfer("aaa", "bbb", 200d); } } <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="transfer" propagation="REQUIRED" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="pointcut1" expression="execution(* com.conan.springtransaction.service.AccountService.transfer(..))"/> </aop:config> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/> </aop:config>
基于注解方式的声明式事务管理 如下代码Spring是采用xml的配置方式,如果采用Java config配置方式,会更加简洁,只需要关注Service类上的@Transactional就好; 通过设置@Transactional的属性就能达到事务管理的目的;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:springconfig_statement3.xml") public class TestTransactionManagerStatement3 { @Resource(name = "accountService") private AccountService accountService; @Test public void testTransactionManagerStatement3() { accountService.transfer("aaa", "bbb", 200d); } } @Transactional(propagation = Propagation.REQUIRED) public class AccountServiceImplStatement3 implements AccountService { private AccountDaoImplStatement1 accountDao; public void transfer(String out, String in, Double money) { accountDao.inMoney(in, money); int i = 1 / 0; accountDao.outMoney(out, money); } public void setAccountDao(AccountDaoImplStatement1 accountDao) { this.accountDao = accountDao; } } <!--引入实现文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--C3P0 连接池--> <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="com.conan.springtransaction.dao.AccountDaoImplStatement1"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="accountService" class="com.conan.springtransaction.service.AccountServiceImplStatement3"> <property name="accountDao" ref="accountDao"/> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> //激活注解
GitHub登录不了 ?信任该网站之后再登录。