PROPAGATION_REQUIRED 若是当前没有事务,就新建一个事务,若是已经存在一个事务中,加入到这个事务中html
PROPAGATION_REQUIRES_NEW 每个受影响的事务做用域都使用彻底 独立的事务.物理上的事务就不一样了而且能够独立的提交或者回滚, 外部事物不会影响到内部事务的回滚 状态java
PROPAGATION_NESTED 事务嵌套 子事务是父事务的一部分,父事务失败则所有回滚,若是子事务失败,则回滚到进入子事务以前的状态spring
官网好像只列出了这几个,可是不少博客都说有9种,不过咱们大部分都用的Required级别,其它的就不深究了,若是须要进一步了解可参考 https://my.oschina.net/dongli...数据库
理解声明式事务实现机制
注解事务的最基本是利用了spring的aop实现,调用者调用的实则是目标类的代理类,代理类有事务的拦截器Interceptor, TransactionInterceptor 来实现对应的事务处理express
xml配置方式apache
<!-- 事务化配置 --> <tx:advice id="txAdvice" transaction-manager="txManager"> <!-- 事务语义... --> <tx:attributes> <!-- 全部用'get'开头的方法都是只读的 --> <tx:method name="get*" read-only="true"/> <!-- 其余的方法使用默认的事务配置(看下面) --> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- 定义切面配置 --> <aop:config> <!-- FooService 下的全部方法--> <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/> </aop:config> <!-- DataSource数据源配置 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/> <property name="username" value="scott"/> <property name="password" value="tiger"/> </bean> <!-- 声明事务管理器实现 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
tx-method配置项说明编程
配置项 | 是否必须 | 默认值 | 描述 |
---|---|---|---|
name | 是 | ||
propagation | 否 | REQUIRED | 事务传播行为,参考上文描述 |
isolation | 否 | DEFAULT | 隔离级别 default使用数据库默认的事务隔离级别 |
timeout | 否 | -1 | 事务超时时间 单位 秒 |
read-only | 否 | false | 事务级别是否只读 |
rollback-for | 否 | ----- | 指定回滚异常类型 |
no-rollback-for | 否 | ----- | 指定什么异常类型不回滚 |
isolation 可选值
DEFAULT 使用当前数据库默认的事务界别
READ_UNCOMMITTED
READ_COMMITTED
REPEATABLE_READ 可重复读
SERIALIZABLEapi
注解方式(经常使用)mybatis
配置的方式是采用通配符的方式进行事务切入,不够灵活,在实际开发中注解的方式用的较多,配置可参考下面oracle
<!-- 数据源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/> <property name="username" value="scott"/> <property name="password" value="tiger"/> </bean> <!-- 使用注解配置的事务行为生效 --> <tx:annotation-driven transaction-manager="txManager"/> <!--事务管理器--> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--开启事务注解配置 --> <tx:annotation-driven transaction-manager="txManager"/>
须要事务的方法加上注解便可
//注解加到类上,则该类里全部public方法启用事务 //注解加在方法上,则只有方法启用事务 @Transactional public class DefaultFooService implements FooService { Foo getFoo(String fooName); Foo getFoo(String fooName, String barName); void insertFoo(Foo foo); void updateFoo(Foo foo); }
方法可见性和@Transactional
当使用代理时, 你应该只给public可见性的方法添加@Transactional注解. 若是你给protected, private或者包访问的方法添加了@Transactional注解, 不会产生错误, 可是事务不生效. 若是你须要给非公开的方法添加注解能够参考其它文档,此处不作概述
多数据源,多事务
<!-- 同上,不一样的dataSource配置不一样的txManager --> <tx:annotation-driven transaction-manager="txManager"/> <tx:annotation-driven transaction-manager="txManager1"/> <tx:annotation-driven transaction-manager="txManager2"/>
//名字和事务管理器同名便可 @Transactional("txManager1") public class DefaultFooService implements FooService { Foo getFoo(String fooName); Foo getFoo(String fooName, String barName); void insertFoo(Foo foo); void updateFoo(Foo foo); }
也能够给txManager加上别名
<!--事务管理器--> <bean id="txManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <qualifier value="order"/> <property name="dataSource" ref="dataSource"/> </bean> <bean id="txManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <qualifier value="account"/> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="txManager1"/> <tx:annotation-driven transaction-manager="txManager2"/>
//名字和事务管理器的qualifier相同便可 @Transactional("order") public class DefaultFooService implements FooService { Foo getFoo(String fooName); Foo getFoo(String fooName, String barName); void insertFoo(Foo foo); void updateFoo(Foo foo); }
*使用注解的方式,注意下面这种情形,防止事务不生效
1.不要对本身要进行事务控制的代码进行try catch,spring的事务触发是执行体出现异常,若是本身的程序catch住了异常,spring事务管理器觉得执行成功,回滚不生效
//错误示例 @Transactional public void update2(String name){ try { jdbcTemplate.execute("UPDATE t_menua SET mname='"+name+"' WHERE mid=106 "); } catch (DataAccessException e) { e.printStackTrace(); } }
//错误案例 @Transactional public void update2(String name){ jdbcTemplate.execute("UPDATE t_menua SET mname='"+name+"' WHERE mid=106 "); } public void update3(String name) { this.update2(name); throw new RuntimeException(); }
调用堆栈以下
//事务生效 @Transactional public void update2(String name){ jdbcTemplate.execute("UPDATE t_menua SET mname='"+name+"' WHERE mid=106 "); } @Transactional public void update3(String name) { this.update2(name); throw new RuntimeException(); }
调用堆栈以下
你们对比能够发现,第一种的执行栈里压根就没有事务拦截器,因此事务没有生效
spring 配置
<!-- dataSource 配置同上--> <!-- 事务管理器 配置同上 管理器名字 txManage--> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" > <property name="transactionManager" ref="txManage" /> </bean>
java代码
public class LocalDataService { /** * 编程式事务模板 */ @Resource private TransactionTemplate transactionTemplate; /** * dao层执行体,能够是hibernate,mybatis等其它db框架 */ @Resource private JdbcTemplate jdbcTemplate; /** * 修改数据 */ public void update(final String name){ transactionTemplate.execute(new TransactionCallback<Integer>() { public Integer doInTransaction(TransactionStatus transactionStatus) { jdbcTemplate.execute("UPDATE t_menua SET mname='"+name+"' WHERE mid=106 "); return 1; } }); throw new RuntimeException(); } }
transactionTemplate 官方有两种
TransactionTemplate
PlatformTransactionManager
Spring通常都推荐使用TransactionTemplate来进行编程式事务管理. 第二种方式有点相似于使用JTA的 UserTransaction接口
参考文档
spring中文文档 http://spring.cndocs.tk/trans...