? 解决:把转出钱和转入钱的业务放到同一个事务空间。把 connection 绑定到当前线程中;从当前线程中获取 Connection 对象 创建事务。封装事务的隔离级别和超时时间,是否为只读事务和事务的隔离级别和传播规则等事务属性.封装了事务的具体运行状态。如是否是新开启事务,是否已经提交事务,设置当前事务为rollback-only.
在一个事务方法中,调用了其他事务的方法,此时事务该如何传递,按照什么规则传播.

REQUIRED:(常用)必须存在一个事务,如果当前存在一个事务,则加入到该事务中,否则,新建一个事务.
SUPPORTS:支持当前事务,如果当前存在事务,则使用该事务,否则,以非事务形式运行.
MANDATORY:必须要存在事务,如果当存在事务,就使用该事务,否则,非法的事务状态异常:(IllegalTranactionStatusException)
常用)不管当前是否存在事务,都会新开启一个事务.必须是一个新的事务.NESTED:寄生事务,如果当前存在事务,则在内部事务内执行.如果当前不存在事务,则创建一个新的事务.
寄生事务可以通过数据库savePoint(保存点)来实现,奇生事务可以回滚的,但是他的回滚不影响外部事务.但是外部事务的回滚会影响寄生事务.
寄生事务并不是所有的事务管理器都支持,比如HibernateTransactionManager默认就不支持,需要手动去开启.Jdbc和MyBatis的事务管理器:DataSourceTransactionManager:默认就是支持的. <!-- ===============好比是AOP,事务增强================================== --> <!-- 1、what:配置jdbc事务管理器 --> <bean id="txManager" > <property name="dataSource" ref="dataSource"/> </bean> <!-- 2:when:配置事务管理器增强(环绕增强) --><!-- 关联what --> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="trans"/> </tx:attributes> </tx:advice> <!-- 3、where:配置切面 --><!-- 关联when --> <aop:config> <aop:pointcut id="txPc" expression="execution(* com.shan.service.*Service.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPc"/> </aop:config>| 属性 | 必要? | 默认 | 描述 |
|---|---|---|---|
| name 匹配方法的模式 | 是 | ||
| propagation 事务的传播规则 | 否 | required | |
| isolation 事务的隔离级别 | 否 | default | DEFAULT:使用数据库自身设置的隔离级别,其他四种都是Spring通过java代码模拟出来的 |
| timeout 事务超时时间 | 否 | -1 | 缺省 -1 表示使用底层数据库自身的超时时间 |
| read-only 是否是只读事务 | 否 | false | 若对于查询方法,设置只读,会提高性能,例如Hibernate |
| rollback-for 遇到什么异常做回滚 | 否 | java.lang.RuntimeException | 当我们在业务方法中,抛出一个Runtime异常,则事务回滚。自定义异常,若是需要配置多个异常,使用,隔开 |
| no-rollback-for 遇到什么异常不做回滚 | 否 |
<bean id="txManager" > <property name="dataSource" ref="dataSource"></property></bean><!-- tx注解解析器 --><tx:annotation-driven transaction-manager="txManager"/>@Service@Transactionalpublic class AccountServiceImpl implements IAccountService{ @Autowired private IAccountDAO dao; @Override public void trans(Long outId, Long inId, int money) { dao.transOut(outId, money); int a = 1/0; //算术异常 dao.transIn(inId, money); } //若是有查询方法,可以再贴注解@Transactional添加注解属性 @Transactional(readOnly = true) public void listXX() { }}
//当前项目的连接池的配置类@Configuration@PropertySource("classpath:db.properties")public class DataSourceConfig { @Value("${jdbc.driverClassName}") private String driverClassName; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Value("${jdbc.initialSize}") private int initialSize; //配置连接池的Bean @Bean public DataSource dataSource() { DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driverClassName); ds.setUrl(url); ds.setUsername(username); ds.setPassword(password); ds.setInitialSize(initialSize); return ds; }}■ AppConfig.java
//当前项目的配置类,好比是pplicationContext.xml@Configuration //标识当前类为一个配置类@Import(DataSourceConfig.class) //包含其他的配置类@ComponentScan //ioc注解解析器【di注解解析器默认是导入的】@EnableTransactionManagement//事务注解解析器public class AppConfig { //创建事务管理的Bean @Bean public DataSourceTransactionManager txManager(DataSource ds) { return new DataSourceTransactionManager(ds); }}■ App.java
@SpringJUnitConfig(classes = AppConfig.class)public class App { @Autowired private IAccountService service; @Test void testTrans() throws Exception { service.trans(1L, 2L, 100); }}本文来自博客园,作者:一乐乐,转载请注明原文链接:https://www.cnblogs.com/shan333/p/15962418.html