spring事务相关资料

编程式事务

编码方式实现事务管理(代码演示为JDBC事务管理)

Spring实现编程式事务,依赖于2大类,分别是PlatformTransactionManager,与模版类TransactionTemplate(推荐使用)。下面分别详细介绍Spring是如何通过该类实现事务管理。

1)PlatformTransactionManager

事务管理器配置

 
  1. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  2. <property name="jdbcUrl" value="${db.jdbcUrl}" />
  3. <property name="user" value="${user}" />
  4. <property name="password" value="${password}" />
  5. <property name="driverClass" value="${db.driverClass}" />
  6. <!--连接池中保留的最小连接数。 -->
  7. <property name="minPoolSize">
  8. <value>5</value>
  9. </property>
  10. <!--连接池中保留的最大连接数。Default: 15 -->
  11. <property name="maxPoolSize">
  12. <value>30</value>
  13. </property>
  14. <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
  15. <property name="initialPoolSize">
  16. <value>10</value>
  17. </property>
  18. <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
  19. <property name="maxIdleTime">
  20. <value>60</value>
  21. </property>
  22. <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
  23. <property name="acquireIncrement">
  24. <value>5</value>
  25. </property>
  26. <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 -->
  27. <property name="maxStatements">
  28. <value>0</value>
  29. </property>
  30. <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
  31. <property name="idleConnectionTestPeriod">
  32. <value>60</value>
  33. </property>
  34. <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
  35. <property name="acquireRetryAttempts">
  36. <value>30</value>
  37. </property>
  38. <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。Default: false -->
  39. <property name="breakAfterAcquireFailure">
  40. <value>true</value>
  41. </property>
  42. <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable等方法来提升连接测试的性能。Default: false -->
  43. <property name="testConnectionOnCheckout">
  44. <value>false</value>
  45. </property>
  46. </bean>
  47. <!--DataSourceTransactionManager位于org.springframework.jdbc.datasource包下,数据源事务管理类,提供对单个javax.sql.DataSource数据源的事务管理,主要用于JDBC,Mybatis框架事务管理。 -->
  48. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  49. <property name="dataSource" ref="dataSource" />
  50. </bean>

业务中使用代码(以测试类展示)

 
  1. import java.util.Map;
  2. import javax.annotation.Resource;
  3. import javax.sql.DataSource;
  4. import org.apache.log4j.Logger;
  5. import org.junit.Test;
  6. import org.junit.runner.RunWith;
  7. import org.springframework.jdbc.core.JdbcTemplate;
  8. import org.springframework.test.context.ContextConfiguration;
  9. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  10. import org.springframework.transaction.PlatformTransactionManager;
  11. import org.springframework.transaction.TransactionDefinition;
  12. import org.springframework.transaction.TransactionStatus;
  13. import org.springframework.transaction.support.DefaultTransactionDefinition;
  14. @RunWith(SpringJUnit4ClassRunner.class)
  15. @ContextConfiguration(locations = { "classpath:spring-public.xml" })
  16. public class test {
  17. @Resource
  18. private PlatformTransactionManager txManager;
  19. @Resource
  20. private DataSource dataSource;
  21. private static JdbcTemplate jdbcTemplate;
  22. Logger logger=Logger.getLogger(test.class);
  23. private static final String INSERT_SQL = "insert into testtranstation(sd) values(?)";
  24. private static final String COUNT_SQL = "select count(*) from testtranstation";
  25. @Test
  26. public void testdelivery(){
  27. //定义事务隔离级别,传播行为,
  28. DefaultTransactionDefinition def = new DefaultTransactionDefinition();
  29. def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
  30. def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
  31. //事务状态类,通过PlatformTransactionManager的getTransaction方法根据事务定义获取;获取事务状态后,Spring根据传播行为来决定如何开启事务
  32. TransactionStatus status = txManager.getTransaction(def);
  33. jdbcTemplate = new JdbcTemplate(dataSource);
  34. int i = jdbcTemplate.queryForInt(COUNT_SQL);
  35. System.out.println("表中记录总数:"+i);
  36. try {
  37. jdbcTemplate.update(INSERT_SQL, "1");
  38. txManager.commit(status); //提交status中绑定的事务
  39. } catch (RuntimeException e) {
  40. txManager.rollback(status); //回滚
  41. }
  42. i = jdbcTemplate.queryForInt(COUNT_SQL);
  43. System.out.println("表中记录总数:"+i);
  44. }
  45. }

2)使用TransactionTemplate,该类继承了接口DefaultTransactionDefinition,用于简化事务管理,事务管理由模板类定义,主要是通过TransactionCallback回调接口或TransactionCallbackWithoutResult回调接口指定,通过调用模板类的参数类型为TransactionCallback或TransactionCallbackWithoutResult的execute方法来自动享受事务管理。

TransactionTemplate模板类使用的回调接口:

TransactionCallback:通过实现该接口的“T doInTransaction(TransactionStatus status) ”方法来定义需要事务管理的操作代码;
TransactionCallbackWithoutResult:继承TransactionCallback接口,提供“void doInTransactionWithoutResult(TransactionStatus status)”便利接口用于方便那些不需要返回值的事务操作代码。
还是以测试类方式展示如何实现

 
  1. @Test
  2. public void testTransactionTemplate(){
  3. jdbcTemplate = new JdbcTemplate(dataSource);
  4. int i = jdbcTemplate.queryForInt(COUNT_SQL);
  5. System.out.println("表中记录总数:"+i);
  6. //构造函数初始化TransactionTemplate
  7. TransactionTemplate template = new TransactionTemplate(txManager);
  8. template.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
  9. //重写execute方法实现事务管理
  10. template.execute(new TransactionCallbackWithoutResult() {
  11. @Override
  12. protected void doInTransactionWithoutResult(TransactionStatus status) {
  13. jdbcTemplate.update(INSERT_SQL, "饿死");  //字段sd为int型,所以插入肯定失败报异常,自动回滚,代表TransactionTemplate自动管理事务
  14. }}
  15. );
  16. i = jdbcTemplate.queryForInt(COUNT_SQL);
  17. System.out.println("表中记录总数:"+i);
  18. }

声明式事务

可知编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不同,声明式事务属于无侵入式,不会影响业务逻辑的实现。

声明式事务实现方式主要有2种,一种为通过使用Spring的<tx:advice>定义事务通知与AOP相关配置实现,另为一种通过@Transactional实现事务管理实现,下面详细说明2种方法如何配置,已经相关注意点

1)方式一,配置文件如下

 
  1. <!--
  2. <tx:advice>定义事务通知,用于指定事务属性,其中“transaction-manager”属性指定事务管理器,并通过<tx:attributes>指定具体需要拦截的方法
  3. <tx:method>拦截方法,其中参数有:
  4. name:方法名称,将匹配的方法注入事务管理,可用通配符
  5. propagation:事务传播行为,
  6. isolation:事务隔离级别定义;默认为“DEFAULT”
  7. timeout:事务超时时间设置,单位为秒,默认-1,表示事务超时将依赖于底层事务系统;
  8. read-only:事务只读设置,默认为false,表示不是只读;
  9. rollback-for:需要触发回滚的异常定义,可定义多个,以“,”分割,默认任何RuntimeException都将导致事务回滚,而任何Checked Exception将不导致事务回滚;
  10. no-rollback-for:不被触发进行回滚的 Exception(s);可定义多个,以“,”分割;
  11. -->
  12. <tx:advice id="advice" transaction-manager="transactionManager">
  13. <tx:attributes>
  14. <!-- 拦截save开头的方法,事务传播行为为:REQUIRED:必须要有事务, 如果没有就在上下文创建一个 -->
  15. <tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED" timeout="" read-only="false" no-rollback-for="" rollback-for=""/>
  16. <!-- 支持,如果有就有,没有就没有 -->
  17. <tx:method name="*" propagation="SUPPORTS"/>
  18. </tx:attributes>
  19. </tx:advice>
  20. <!-- 定义切入点,expression为切人点表达式,如下是指定impl包下的所有方法,具体以自身实际要求自定义 -->
  21. <aop:config>
  22. <aop:pointcut expression="execution(* com.kaizhi.*.service.impl.*.*(..))" id="pointcut"/>
  23. <!--<aop:advisor>定义切入点,与通知,把tx与aop的配置关联,才是完整的声明事务配置 -->
  24. <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
  25. </aop:config>

2)方式二通过@Transactional实现事务管理

 
  1. <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  2. <property name="dataSource" ref="dataSource"/>
  3. </bean>
  4. <tx:annotation-driven transaction-manager="txManager"/> //开启事务注解

Spring提供的@Transaction注解事务管理,内部同样是利用环绕通知TransactionInterceptor实现事务的开启及关闭。
使用@Transactional注意点:
如果在接口、实现类或方法上都指定了@Transactional 注解,则优先级顺序为方法>实现类>接口;
建议只在实现类或实现类的方法上使用@Transactional,而不要在接口上使用,这是因为如果使用JDK代理机制(基于接口的代理)是没问题;而使用使用CGLIB代理(继承)机制时就会遇到问题,因为其使用基于类的代理而不是接口,这是因为接口上的@Transactional注解是“不能继承的”;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值