Springboot編程式事務(wù)使用方式詳解
環(huán)境:springboot2.3.9.RELEASE
Spring提供兩種編程式事務(wù)管理方法:
- 使用TransactionTemplate 或 TransactionalOperator
- 直接創(chuàng)建TransactionManager的實現(xiàn)
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 事務(wù)回滾
事務(wù)的回滾通過
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 配置事務(wù)屬性
在實例化TransactionTemplate對象的時候我們可以對事務(wù)進行相關(guān)的屬性配置,通過如下方式。
- 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) ;
由于這里事務(wù)傳播屬性設(shè)置的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適用于反應(yīng)式編程,這里不做介紹。
3 TransactionManager
使用TransactionManager管理事務(wù)也有兩種
PlatformTransactionManager,
ReactiveTransactionManager
ReactiveTransactionManager適用于反應(yīng)式編程,這里不做介紹。
3.1 PlatformTransactionManager
在程序中可以使用
PlatformTransactionManager來控制事務(wù)的提交與回滾
示例:
- 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 事務(wù)事件監(jiān)聽
通過@
TransactionalEventListener注解監(jiān)聽事務(wù)的不同階段的事件信息
- 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;如果設(shè)置為true,當前即便沒有事務(wù)也會觸發(fā)事件。
TransactionPhase:默認值是事務(wù)提交以后;有如下幾個取值:
- public enum TransactionPhase {
- BEFORE_COMMIT, // 事務(wù)提交前觸發(fā)
- AFTER_COMMIT, // 事務(wù)提交后觸發(fā)
- AFTER_ROLLBACK, // 事務(wù)回滾觸發(fā)
- AFTER_COMPLETION // 事務(wù)完成后 觸發(fā)
- }
注意:@
TransactionalEventListener注解只對聲明式事務(wù)起作用,對編程式事務(wù)無效。僅適用于由PlatformTransactionManager管理的線程綁定事務(wù)
示例:
- // 事件監(jiān)聽
- @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()) ;
- }
- }
- // 發(fā)布事件
- @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 ;
- }
運行結(jié)果:
- 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
總結(jié):編程式的事務(wù)適合少量的事務(wù)操作;比如在一個服務(wù)的調(diào)用中有大量的計算操作,最后將計算結(jié)果進行事務(wù)的操作這種情況就適合應(yīng)用事務(wù)編程式的進行事務(wù)控制。如果一個操作有很多的事務(wù)的操作那聲明式的事務(wù)方式就更加的合適。