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

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

[[410883]]

环境:springboot2.3.9.RELEASE

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

  1. 使用TransactionTemplate 或 TransactionalOperator
  2. 直接创建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, passwordvalues (#{id}, #{username}, #{password}) 
</insert
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.

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.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

1.2 无返回值的

当没有返回值时可以使用

TransactionCallbackWithoutResult

public void saveUsers(Users users) { 
  transactionTemplate.execute(new TransactionCallbackWithoutResult() { 
    @Override 
    protected void doInTransactionWithoutResult(TransactionStatus status) { 
      usersMapper.insertUser(users) ; 
    } 
  }) ; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

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.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

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 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

测试代码

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) ; 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

由于这里事务传播属性设置的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) 
  • 1.
  • 2.
  • 3.
  • 4.

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 ;        

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.

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 ""

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

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

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

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

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

注意:@

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 ; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.

运行结果:

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 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

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

 

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

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语句

2023-09-04 08:00:53

提交事务消息

2009-12-25 18:05:05

Linux压缩程式

2022-09-12 22:27:05

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

2022-10-25 18:00:00

Redis事务生产事故

2021-04-15 08:01:27

Spring声明式事务

2023-02-10 07:00:22

2009-06-17 14:57:11

Spring事务管理

2019-11-27 10:05:00

LombokJava编程

2010-03-11 09:34:31

Python线程编程

2016-01-18 10:49:13

Java EE编程式Websocket

2010-01-11 17:30:40

VB.NET播放声音

2015-09-09 18:02:07

PythonAPM

2024-11-06 09:26:48

SpringprofileENV

2010-06-22 13:23:18

Linux at命令详

2009-08-03 11:38:57

linux at命令详linux at命令

2018-02-01 04:02:41

数据中心网络编程
点赞
收藏

51CTO技术栈公众号