赞
踩
--------------------------------------------------------------------------------------------------------------------------------
以银行转账为例,一次转账操作伴随着一个账户的扣钱和另一个账户的加钱,这个流程是一个原子操作,要么同时发生,一气呵成,要么都不做。
- public interface AccountService {
- public void transfer(int out,int in);
- }
- @Service
- public class AccountServiceImpl implements AccountService {
-
- @Autowired
- private AccountMapper accountMapper;
-
- @Override
- public void transfer(int out, int in) {
-
- accountMapper.outMoney(out);
-
- accountMapper.inMoney(in);
- }
- }
- @Repository
- public interface AccountMapper {
- public void inMoney(@Param("id") int id);
- public void outMoney(@Param("id") int id);
- }
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE mapper
- PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
- "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-
- <mapper namespace="com.example.test.mapper.AccountMapper">
- <update id="inMoney">
- update account set money=money+100 where id=#{id}
- </update>
- <update id="outMoney">
- update account set money=money-100 where id=#{id}
- </update>
- </mapper>
- @RunWith(SpringJUnit4ClassRunner.class)//加载类运行器
- @ContextConfiguration(classes = SpringConfig.class)//加载上下文配置
- public class TestTransition {
-
- @Autowired
- private AccountService accountService;
- @Test
- public void test01(){
- accountService.transfer(1,2);
- }
- }
用1/0模拟程序运行时出现异常的情况
由于没有开启事务,出现了莫名其妙少了100块钱的情况,说明这个事务不是连续的。
- public interface AccountService {
- @Transactional
- public void transfer(int out,int in);
- }
- package com.example.test.config;
-
- import com.alibaba.druid.pool.DruidDataSource;
- import com.example.test.dao.StudentDao;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.context.annotation.Bean;
- import org.springframework.jdbc.datasource.DataSourceTransactionManager;
- import org.springframework.transaction.PlatformTransactionManager;
-
- import javax.sql.DataSource;
-
- public class JdbcConfig {
- //返回DataSource的实例化对象
- @Bean("dataSource")
- public DataSource dataSource(){
- DruidDataSource ds = new DruidDataSource();
- ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
- ds.setUrl("jdbc:mysql://localhost:3306/testspring?serverTimezone=Asia/Shanghai");
- ds.setUsername("root");
- ds.setPassword("root");
- return ds;
- }
-
- @Bean
- //Spring事务管理器
- public PlatformTransactionManager transactionManager(DataSource dataSource){
- DataSourceTransactionManager dstm = new DataSourceTransactionManager();
- dstm.setDataSource(dataSource);
- return dstm;
- }
- }
- @Configuration
- @ComponentScan("com.example.test")//包扫描
- @PropertySource("db.properties")//加载properties文件
- @Import({JdbcConfig.class,MybatisConfig.class})//加载第三方bean
- @EnableAspectJAutoProxy //开启AOP
- @EnableTransactionManagement//开启Spring事务
- public class SpringConfig {
- }
由于出现了异常,Spring帮我们回滚了outMoney操作
在这里,transfer方法是事务管理员,inMoney和outMoney方法是事务协调员
程序运行时,两个事务协调员加入事务管理员开启的事务T,成为一个事务,他们要么一起完成,要么都不做。
对于rollbackFor,值得注意的是,Spring只对两种类型进行回滚,一种是error,一种是运行时异常(非受检异常),所以对于受检异常,我们需要手动回滚。
下面是一些常见的受检异常
例
也就是无论转账成功与否,我们都希望对log(日志表)进行写,记录下这次转账操作的发生。
如果没有事务传播,那么log事务会和intMoney,outMoney一样,加入到事务管理员transfer创建的事务T中,与他们同进退。
开启事务传播,可以表明事务协调员对事务管理员所携带的事务的态度
在这里intMoney或outMoney发生的回滚,不会影响到log,因为log单独开了个事务T2
怎么看这个表:
SUPPORTS:管理员开启事务T,协调员就加入;管理员没有开事务,协调员也不开。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。