大数跨境
0
0

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

Springboot编程式事务使用方式详解 Spring全家桶实战案例
2021-12-01
0
导读:Springboot编程式事务使用方式详解

环境:springboot2.3.9.RELEASE


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

  1. 使用TransactionTemplate 或 TransactionalOperator

  2. 直接创建TransactionManager的实现

Spring官方推荐使用TransactionTemplate方式

准备

// 实体类@Entity@Table(name = "BC_USERS")@Datapublic class Users{  private String username ;  private String password ;  private Integer status = 0 ;}// DAOpublic 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) ; }@Mapperpublic 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 有返回值的

@Servicepublic 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 ;@Resourceprivate 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管理的线程绑定事务

示例:

// 事件监听@Componentpublic 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()) ; }}// 发布事件@Resourceprivate ApplicationEventPublisher publisher ;@Resourceprivate 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: 1BeforeCommit收到事件通知:mmmmmAfterCommit收到事件通知:mmmmmAfterCompletion收到事件通知:mmmmm

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

完毕!!!

给个关注+转发谢谢

公众:Springboot实战案例锦集


【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读285
粉丝0
内容832