搜搜吧

查看: 566|回复: 0

Springboot编程式事务使用方式详解

[复制链接]

超级钻石贵宾会员

1万

主题

2万

帖子

3万

搜搜币

Rank: 1

UID
15343
威望
-561
在线时间
393 小时
注册时间
2015-10-12
发表于 2021-7-13 14:56:10 | 显示全部楼层 |阅读模式

环境:springboot2.3.9.RELEASE

Spring提供两种编程式事务管理方法:

  • 使用TransactionTemplate 或 TransactionalOperator
  • 直接创建TransactionManager的实现

Spring官方推荐使用TransactionTemplate方式

准备
  • // 实体类
  • @Entity
  • @Table(name = "BC_USERS")
  • @Data
  • public class Users{
  •     private String username ;
  •     private String password ;
  •     private Integer status = 0 ;
  • }
  • // DAO
  • public interface UsersRepository extends JpaRepository<Users, String> {
  •   @Modifying
  •   @Query("update Users u set u.status=?1,u.password='123123' where u.id=?2")
  •   int updateUsers(Integer status, String id) ;
  •      
  • }
  • @Mapper
  • public interface UsersMapper {
  •   int insertUser(Users user) ;
  •      
  • }
  • // Mapper.xml
  • <insert id="insertUser" parameterType="com.pack.domain.Users">
  •   insert into bc_users (id, username, password) values (#{id}, #{username}, #{password})
  • </insert>
1 TransactionTemplate1.1 有返回值的
  • @Service
  • public class UserService {
  •      
  •   @Resource
  •   private TransactionTemplate transactionTemplate ;
  •   @Resource
  •   private UsersRepository usersRepository ;
  •      
  •   public Integer saveUsers(Users users) {
  •     this.transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
  •     Integer result = transactionTemplate.execute(new TransactionCallback<Integer>() {
  •       @Override
  •       public Integer doInTransaction(TransactionStatus status) {
  •         return usersMapper.insertUser(users) ;
  •       }
  •     }) ;
  •     return result ;
  •     }
  •      
  • }
1.2 无返回值的

当没有返回值时可以使用

TransactionCallbackWithoutResult

  • public void saveUsers(Users users) {
  •   transactionTemplate.execute(new TransactionCallbackWithoutResult() {
  •     @Override
  •     protected void doInTransactionWithoutResult(TransactionStatus status) {
  •       usersMapper.insertUser(users) ;
  •     }
  •   }) ;
  • }
1.3 事务回滚

事务的回滚通过

TransactionStatus.setRollbackOnly方法

  • public Users saveUser(Users users) {
  •   return transactionTemplate.execute(new TransactionCallback<Users>() {
  •     @Override
  •     public Users doInTransaction(TransactionStatus status) {
  •       try {
  •         return usersMapper.insertUser(users) ;
  •       } catch (Exception e) {
  •         status.setRollbackOnly() ;
  •       }
  •       return null ;
  •     }
  •   }) ;
  • }
1.4 配置事务属性

在实例化TransactionTemplate对象的时候我们可以对事务进行相关的属性配置,通过如下方式。

  • private TransactionTemplate transactionTemplate ;
  •      
  • public UserService(PlatformTransactionManager transactionManager) {
  •   this.transactionTemplate = new TransactionTemplate(transactionManager) ;
  •   this.transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
  •   this.transactionTemplate.setTimeout(30); //seconds
  • }

测试代码

  • public Integer updateUsers(Integer statusValue, String id) {
  •   return transactionTemplate.execute(new TransactionCallback<Integer>() {
  •     @Override
  •     public Integer doInTransaction(TransactionStatus status) {
  •       return usersRepository.updateUsers(statusValue, id) ;
  •     }
  •   }) ;
  • }
  • @Modifying
  • @Query("update Users u set u.status=?1 where u.id=?2")
  • int updateUsers(Integer status, String id) ;

由于这里事务传播属性设置的NOT_SUPPORTED.所以程序会报错误

  • org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query
  •     at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:403)
  •     at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:257)
  •     at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:531)
2 TransactionalOperator

TransactionalOperator适用于反应式编程,这里不做介绍。

3 TransactionManager

使用TransactionManager管理事务也有两种

PlatformTransactionManager,

ReactiveTransactionManager

ReactiveTransactionManager适用于反应式编程,这里不做介绍。

3.1 PlatformTransactionManager

在程序中可以使用

PlatformTransactionManager来控制事务的提交与回滚

示例:

  • private PlatformTransactionManager transactionManager ;
  • private DefaultTransactionDefinition definition ;
  • private TransactionStatus status ;
  • @Resource
  • private UsersRepository usersRepository ;
  • public UserService3(PlatformTransactionManager transactionManager) {
  •   this.transactionManager = transactionManager ;
  •   definition = new DefaultTransactionDefinition() ;
  •   definition.setName("pgName") ;
  •   definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED) ;
  • }
  •      
  • public Integer saveUsers(Users users) {
  •   TransactionStatus status = this.transactionManager.getTransaction(definition) ;
  •   Integer result = null ;
  •   try {
  •     result = usersMapper.insertUser(users) ;
  •   } catch (Exception e) {
  •     transactionManager.rollback(status) ;
  •     throw e ;
  •   }
  •   transactionManager.commit(status) ;
  •   publisher.publishEvent(new UsersEvent(users));
  •   return result ;        
  • }
4 事务事件监听

通过@

TransactionalEventListener注解监听事务的不同阶段的事件信息

  • public @interface TransactionalEventListener {
  •   TransactionPhase phase() default TransactionPhase.AFTER_COMMIT;
  •   boolean fallbackExecution() default false;
  •   @AliasFor(annotation = EventListener.class, attribute = "classes")
  •   Class<?>[] value() default {};
  •   @AliasFor(annotation = EventListener.class, attribute = "classes")
  •   Class<?>[] classes() default {};
  •   String condition() default "";
  • }

fallbackExecution: 默认值false;如果设置为true,当前即便没有事务也会触发事件。

TransactionPhase:默认值是事务提交以后;有如下几个取值:

  • public enum TransactionPhase {
  •   BEFORE_COMMIT, // 事务提交前触发
  •   AFTER_COMMIT, // 事务提交后触发
  •   AFTER_ROLLBACK, // 事务回滚触发
  •   AFTER_COMPLETION // 事务完成后 触发
  • }

注意:@

TransactionalEventListener注解只对声明式事务起作用,对编程式事务无效。仅适用于由PlatformTransactionManager管理的线程绑定事务

示例:

  • // 事件监听
  • @Component
  • public class TxListenerComponent {
  •   @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
  •   public void handleUsersAfterCommit(UsersEvent usersEvent) {
  •     Users user = (Users) usersEvent.getSource() ;
  •     System.out.println("AfterCommit收到事件通知:" + user.getPassword()) ;
  •   }
  •   @TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
  •   public void handleUsersAfterCompletion(UsersEvent usersEvent) {
  •     Users user = (Users) usersEvent.getSource() ;
  •     System.out.println("AfterCompletion收到事件通知:" + user.getPassword()) ;
  •   }
  •   @TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
  •   public void handleUsersAfterRollback(UsersEvent usersEvent) {
  •     Users user = (Users) usersEvent.getSource() ;
  •     System.out.println("AfterRollback收到事件通知:" + user.getPassword()) ;
  •   }
  •   @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
  •   public void handleUsersBeforeCommit(UsersEvent usersEvent) {
  •     Users user = (Users) usersEvent.getSource() ;
  •     System.out.println("BeforeCommit收到事件通知:" + user.getPassword()) ;
  •   }
  • }
  • // 发布事件
  • @Resource
  • private ApplicationEventPublisher publisher ;
  • @Resource
  • private UsersMapper usersMapper ;
  • public Integer saveUsers(Users users) {
  •   Integer result = transactionTemplate.execute(new TransactionCallback<Integer>() {
  •     @Override
  •     public Integer doInTransaction(TransactionStatus status) {
  •       return usersMapper.insertUser(users) ;
  •     }
  •   }) ;
  •   publisher.publishEvent(new UsersEvent(users));
  •   return result ;
  • }

运行结果:

  • 2021-06-17 14:02:56.830 DEBUG 10000 --- [nio-8081-exec-1] com.pack.mapper.UsersMapper.insertUser   : ==>  Preparing: insert into bc_users (id, username, password) values (?, ?, ?)
  • 2021-06-17 14:02:56.840 DEBUG 10000 --- [nio-8081-exec-1] com.pack.mapper.UsersMapper.insertUser   : ==> Parameters: mmmmm(String), mmmmm(String), mmmmm(String)
  • 2021-06-17 14:02:56.842 DEBUG 10000 --- [nio-8081-exec-1] com.pack.mapper.UsersMapper.insertUser   : <==    Updates: 1
  • BeforeCommit收到事件通知:mmmmm
  • AfterCommit收到事件通知:mmmmm
  • AfterCompletion收到事件通知:mmmmm

总结:编程式的事务适合少量的事务操作;比如在一个服务的调用中有大量的计算操作,最后将计算结果进行事务的操作这种情况就适合应用事务编程式的进行事务控制。如果一个操作有很多的事务的操作那声明式的事务方式就更加的合适。


过年了,祝各位新年快乐
Powered by www.sosoba.org Copyright © 2013-2021 搜搜吧社区 小黑屋|手机版|Archiver|地图|联系站长|腾讯云代金券|公共DNS|seo优化服务|搜搜吧
广告服务/项目合作/会员购买:QQ 侵权举报邮箱: fuwu-sosoba@qq.com 举报流程必看 搜搜吧建站时间:创建于2013年07月23日
免责声明:本站所有的内容均来自互联网以及第三方作者自由发布,版权归原作者版权所有,搜搜吧不承担任何的法律责任,若有侵权请来信告知,我们立即删除!
版权声明:搜搜吧影视资源均收集自互联网,没有提供影片资源存储和下载,也未参与录制上传,若本站收录的资源涉及您的版权或知识产权或其他利益,我们会立即删除

GMT+8, 2021-9-21 22:46 , Processed in 0.024787 second(s), 6 queries , Redis On.

快速回复 返回顶部 返回列表