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

开发 前端
编程式的事务适合少量的事务操作;比如在一个服务的调用中有大量的计算操作,最后将计算结果进行事务的操作这种情况就适合应用事务编程式的进行事务控制。

[[410883]]

环境:springboot2.3.9.RELEASE

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

  1. 使用TransactionTemplate 或 TransactionalOperator
  2. 直接创建TransactionManager的实现

Spring官方推荐使用TransactionTemplate方式

准备

  1. // 实体类 
  2. @Entity 
  3. @Table(name = "BC_USERS"
  4. @Data 
  5. public class Users{ 
  6.     private String username ; 
  7.     private String password ; 
  8.     private Integer status = 0 ; 
  9. // DAO 
  10. public interface UsersRepository extends JpaRepository<Users, String> { 
  11.  
  12.   @Modifying 
  13.   @Query("update Users u set u.status=?1,u.password='123123' where u.id=?2"
  14.   int updateUsers(Integer status, String id) ; 
  15.      
  16. @Mapper 
  17. public interface UsersMapper { 
  18.  
  19.   int insertUser(Users user) ; 
  20.      
  21. // Mapper.xml 
  22. <insert id="insertUser" parameterType="com.pack.domain.Users"
  23.   insert into bc_users (id, username, passwordvalues (#{id}, #{username}, #{password}) 
  24. </insert

1 TransactionTemplate

1.1 有返回值的

  1. @Service 
  2. public class UserService { 
  3.      
  4.   @Resource 
  5.   private TransactionTemplate transactionTemplate ; 
  6.   @Resource 
  7.   private UsersRepository usersRepository ; 
  8.      
  9.   public Integer saveUsers(Users users) { 
  10.     this.transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); 
  11.     Integer result = transactionTemplate.execute(new TransactionCallback<Integer>() { 
  12.       @Override 
  13.       public Integer doInTransaction(TransactionStatus status) { 
  14.         return usersMapper.insertUser(users) ; 
  15.       } 
  16.     }) ; 
  17.     return result ; 
  18.     } 
  19.      

1.2 无返回值的

当没有返回值时可以使用

TransactionCallbackWithoutResult

  1. public void saveUsers(Users users) { 
  2.   transactionTemplate.execute(new TransactionCallbackWithoutResult() { 
  3.     @Override 
  4.     protected void doInTransactionWithoutResult(TransactionStatus status) { 
  5.       usersMapper.insertUser(users) ; 
  6.     } 
  7.   }) ; 

1.3 事务回滚

事务的回滚通过

TransactionStatus.setRollbackOnly方法

  1. public Users saveUser(Users users) { 
  2.   return transactionTemplate.execute(new TransactionCallback<Users>() { 
  3.     @Override 
  4.     public Users doInTransaction(TransactionStatus status) { 
  5.       try { 
  6.         return usersMapper.insertUser(users) ; 
  7.       } catch (Exception e) { 
  8.         status.setRollbackOnly() ; 
  9.       } 
  10.       return null ; 
  11.     } 
  12.   }) ; 

1.4 配置事务属性

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

  1. private TransactionTemplate transactionTemplate ; 
  2.      
  3. public UserService(PlatformTransactionManager transactionManager) { 
  4.   this.transactionTemplate = new TransactionTemplate(transactionManager) ; 
  5.   this.transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED); 
  6.   this.transactionTemplate.setTimeout(30); //seconds 

测试代码

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

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

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

2 TransactionalOperator

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

3 TransactionManager

使用TransactionManager管理事务也有两种

PlatformTransactionManager,

ReactiveTransactionManager

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

3.1 PlatformTransactionManager

在程序中可以使用

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

示例:

  1. private PlatformTransactionManager transactionManager ; 
  2. private DefaultTransactionDefinition definition ; 
  3. private TransactionStatus status ; 
  4. @Resource 
  5. private UsersRepository usersRepository ; 
  6.  
  7. public UserService3(PlatformTransactionManager transactionManager) { 
  8.   this.transactionManager = transactionManager ; 
  9.   definition = new DefaultTransactionDefinition() ; 
  10.   definition.setName("pgName") ; 
  11.   definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED) ; 
  12.      
  13. public Integer saveUsers(Users users) { 
  14.   TransactionStatus status = this.transactionManager.getTransaction(definition) ; 
  15.   Integer result = null ; 
  16.   try { 
  17.     result = usersMapper.insertUser(users) ; 
  18.   } catch (Exception e) { 
  19.     transactionManager.rollback(status) ; 
  20.     throw e ; 
  21.   } 
  22.   transactionManager.commit(status) ; 
  23.   publisher.publishEvent(new UsersEvent(users)); 
  24.   return result ;        

4 事务事件监听

通过@

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

  1. public @interface TransactionalEventListener { 
  2.   TransactionPhase phase() default TransactionPhase.AFTER_COMMIT; 
  3.   boolean fallbackExecution() default false
  4.   @AliasFor(annotation = EventListener.class, attribute = "classes"
  5.   Class<?>[] value() default {}; 
  6.   @AliasFor(annotation = EventListener.class, attribute = "classes"
  7.   Class<?>[] classes() default {}; 
  8.   String condition() default ""

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

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

  1. public enum TransactionPhase { 
  2.   BEFORE_COMMIT, // 事务提交前触发 
  3.   AFTER_COMMIT, // 事务提交后触发 
  4.   AFTER_ROLLBACK, // 事务回滚触发 
  5.   AFTER_COMPLETION // 事务完成后 触发 

注意:@

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

示例:

  1. // 事件监听 
  2. @Component 
  3. public class TxListenerComponent { 
  4.   @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) 
  5.   public void handleUsersAfterCommit(UsersEvent usersEvent) { 
  6.     Users user = (Users) usersEvent.getSource() ; 
  7.     System.out.println("AfterCommit收到事件通知:" + user.getPassword()) ; 
  8.   } 
  9.   @TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION) 
  10.   public void handleUsersAfterCompletion(UsersEvent usersEvent) { 
  11.     Users user = (Users) usersEvent.getSource() ; 
  12.     System.out.println("AfterCompletion收到事件通知:" + user.getPassword()) ; 
  13.   } 
  14.  
  15.   @TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK) 
  16.   public void handleUsersAfterRollback(UsersEvent usersEvent) { 
  17.     Users user = (Users) usersEvent.getSource() ; 
  18.     System.out.println("AfterRollback收到事件通知:" + user.getPassword()) ; 
  19.   } 
  20.  
  21.   @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) 
  22.   public void handleUsersBeforeCommit(UsersEvent usersEvent) { 
  23.     Users user = (Users) usersEvent.getSource() ; 
  24.     System.out.println("BeforeCommit收到事件通知:" + user.getPassword()) ; 
  25.   } 
  26. // 发布事件 
  27. @Resource 
  28. private ApplicationEventPublisher publisher ; 
  29. @Resource 
  30. private UsersMapper usersMapper ; 
  31.  
  32. public Integer saveUsers(Users users) { 
  33.   Integer result = transactionTemplate.execute(new TransactionCallback<Integer>() { 
  34.     @Override 
  35.     public Integer doInTransaction(TransactionStatus status) { 
  36.       return usersMapper.insertUser(users) ; 
  37.     } 
  38.   }) ; 
  39.   publisher.publishEvent(new UsersEvent(users)); 
  40.   return result ; 

运行结果:

  1. 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 (?, ?, ?) 
  2. 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) 
  3. 2021-06-17 14:02:56.842 DEBUG 10000 --- [nio-8081-exec-1] com.pack.mapper.UsersMapper.insertUser   : <==    Updates: 1 
  4. BeforeCommit收到事件通知:mmmmm 
  5. AfterCommit收到事件通知:mmmmm 
  6. AfterCompletion收到事件通知:mmmmm 

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

 

责任编辑:姜华 来源: 今日头条
相关推荐

2023-04-28 08:21:36

SpringBoot声明式事务编程式事务

2022-02-21 11:21:40

golang编程语言

2023-09-27 16:22:51

SpringMySQL原子性

2023-06-28 08:25:14

事务SQL语句

2009-12-25 18:05:05

Linux压缩程式

2022-09-12 22:27:05

编程式事务声明式事务对象

2023-09-04 08:00:53

提交事务消息

2022-10-25 18:00:00

Redis事务生产事故

2021-04-15 08:01:27

Spring声明式事务

2009-06-17 14:57:11

Spring事务管理

2019-11-27 10:05:00

LombokJava编程

2015-09-09 18:02:07

PythonAPM

2016-01-18 10:49:13

Java EE编程式Websocket

2024-11-06 09:26:48

SpringprofileENV

2023-02-10 07:00:22

2010-03-11 09:34:31

Python线程编程

2010-01-11 17:30:40

VB.NET播放声音

2023-11-10 09:16:45

SpringBootThymeleaf

2010-06-22 13:23:18

Linux at命令详

2009-08-03 11:38:57

linux at命令详linux at命令
点赞
收藏

51CTO技术栈公众号