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

环境: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 TransactionTemplate

1.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 

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

用方源码库
IT科技类资讯
上一篇:在数以亿计的网站中,我们应该抓住每一个可能带来宣传的机会,域名可以带有企业的名字,一般可以使用汉语拼音或者英语单词或者是相关缩写的形式,只要用户记住了你企业的名字,就能很容易的打出你的网站域名,同样的,记住了网站域名也能很快的记住你公司的名字。
下一篇:3、商标域名一经注册,就可以作为域名裁决过程中的主要信息之一。这可以大大增加公司被抢注的相关域名胜诉的机会。