对springBoot事务的一些初步了解

对springBoot事务的一些初步了解


springboot事务初步了解

什么是事务:

事务由单独单元的一个或者多个sql语句组成,在这个单元中,每个sql语句时相互依赖的。而整个单独单元作为一个不可分割的整体,如果单元中某条sql语句一旦执行失败或者产生错误,整个单元将会回滚,也就是所有受到影响的数据将会返回到事务开始以前的状态;如果单元中的所有sql语句均执行成功,则事务被顺利执行

事务的属性:

  • 原子性:一个事务不可在分割,要么都执行要么都不执行。
  • 一致性:一个事务的执行会使数据从一个一致状态切换到另一个一致的状态。
  • 隔离性:一个事务的执行不受其他事物的干扰
  • 持久性: 一个事务一旦提交,则会永久的改变数据库的数据

事务的两种管理方式

注解式事务管理

在SpringBoot中声明式事务最常见,就是把需要事务的方法用@Transactional标注一下就行了,这个一般用在Service层。标注后该方法就具备了事务的能力,出错了会自动回滚。
在大部分场景下,该方法已经够用了。

  1. 在入口类使用注解@EnableTransactionManagement开启事务
  2. 在访问数据库的service方法上添加注解@Transactional即可
@SpringBootApplication
@EnableTransactionManagement
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private UserMapper userMapper;

    @Override
    @Transactional
    public void updataUser(int id,String name) {
        //sql相关接口实现
    }

}

编程式事务管理

在有些场景下,我们需要获取事务的状态,是执行成功了还是失败回滚了,那么使用声明式事务就不够用了,需要编程式事务。
在SpringBoot中,可以使用两种编程式事务。

  • TransactionTemplate
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private TransactionTemplate transactionTemplate;

    @Override
    public void updataUser(int id,String name) {
        User user = new User();
        user.setName(name);
        user.setId(id);
        transactionTemplate.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(TransactionStatus transactionStatus) {
                try {
                    //在doIntransaction里做逻辑处理即可
                    boolean res = userMapper.updateUser(user);
                }catch (Exception e){
                    //如果出异常了,就执行isRollbackOnly方法进行回滚
                    transactionStatus.isRollbackOnly();
                    e.printStackTrace();
                }
                return null;
            }
        });
    }

}
  • TransactionManager
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PlatformTransactionManager transactionManager;

    @Override
    public void updataUser(int id,String name) {
        User user = new User();
        user.setName(name);
        user.setId(id);
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
        try{
            //进行sql逻辑处理
            boolean res = userMapper.updateUser(user);
            transactionManager.commit(status);
        }catch (Exception e){
            transactionManager.rollback(status);
            e.printStackTrace();
        }
    }

}

使用这个就可以把事务结果同步返回给调用端了,出异常了就返回false,成功了就true。


业务中相关的应用

业务场景

在项目中,往往需要执行数据库操作后,发送消息或事件来异步调用其他组件执行相应的操作,例如:
用户注册后发送激活码;
配置修改后发送更新事件等。
但是,数据库的操作如果还未完成,此时异步调用的方法查询数据库发现没有数据,这就会出现问题

解决方案

  1. 使用注解@TransactionalEventListener
  2. 使用TransactionSynchronizationManager方法
  • TransactionalEventListener
@Service
public class TransactionEventTestService {

    @Resource
    private TestMapper mapper;

    @Resource
    private ApplicationEventPublisher publisher;

    @Transactional
    public void addTestModel() {
        TestModel model = new TestModel();
        model.setName("haogrgr");
        mapper.insert(model);

        //对于@TransactionalEventListener, 会在事务提交后才执行Listener处理逻辑.
        
        //发布事件, 事务提交后, 记录日志, 或发送消息等操作
        publisher.publishEvent(model);
    }
    //当事务提交后, 才会真正的执行@TransactionalEventListener配置的Listener, 如果Listener抛异常, 方法返回失败, 但事务不会回滚.

}

@Component
public class TransactionEventListener {

    @TransactionalEventListener
    public void handle(PayloadApplicationEvent<TestModel> event) {
        System.out.println(event.getPayload().getName());
        //这里可以记录日志, 发送消息等操作.
        //这里抛出异常, 会导致addTestModel方法异常, 但不会回滚事务.
    }
}
  • TransactionSynchronizationManager
//线程池异步调用提高性能
private final ExecutorService executorService = Executors.newFixedThreadPool(5);
    public void insert(TechBook techBook){
        bookMapper.insert(techBook);
 
//        send after tx commit but is async
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("send email after transaction commit...");
                        try {
                            Thread.sleep(10*1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("complete send email after transaction commit...");
                    }
                });
            }
        }
        );
 
//        async work but tx not work, execute even when tx is rollback
//        asyncService.executeAfterTxComplete();
 
        ThreadLocalRandom random = ThreadLocalRandom.current();
        if(random.nextInt() % 2 ==0){
            throw new RuntimeException("test email transaction");
        }
        System.out.println("service end");
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lgbisha

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值