spring事务之REQUIRED

spring事务之REQUIRED

准备

1.表

CREATE TABLE `t_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `username` varchar(64) NOT NULL COMMENT '用户名',
  `password` varchar(64) DEFAULT NULL COMMENT '密码',
  `mobile` varchar(64) NOT NULL COMMENT '手机号码',
  `name` varchar(64) DEFAULT NULL COMMENT '真实姓名',
  `is_delete` tinyint(1) DEFAULT NULL COMMENT 'is_delete',
  `gmt_modified` datetime DEFAULT NULL COMMENT 'gmt_modified',
  `gmt_create` datetime DEFAULT NULL COMMENT 'gmt_create',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4;

CREATE TABLE `t_game` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL,
  `created` date DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4;

2.实体类

@Data
public class UserDo {
    private Long id;

    private String username;

    private String password;

    private String mobile;

    private String name;

    private Boolean isDelete;

    private Date gmtModified;

    private Date gmtCreate;
}

@Data
public class GameDo {
    private Integer id;

    private Long userId;

    private Date created;

    private String name;
}

单表

这些方法都在UserManager.java中:

1.粟子一

@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {
   UserDo userDo = new UserDo();
   userDo.setName("user");
   userDo.setUsername("user-aa");
   userDo.setMobile("17370998767");
   userDao.insert(userDo);
   if (1 == 1) {
       throw new RuntimeException("异常");
   }
}


# junit

@Test
public void userMethodBTest(){
   userManager.methodB();
}

测试结果:事务回滚,表中未插入数据

2.粟子二

@Transactional(propagation = Propagation.REQUIRED)
public void methodD(){
    try {
        UserDo userDo = new UserDo();
        userDo.setName("user");
        userDo.setUsername("user-aa");
        userDo.setMobile("17370998767");
        userDao.insert(userDo);
        if (1 == 1) {
            throw new RuntimeException("异常");
        }
    } catch (RuntimeException e) {
        e.printStackTrace();
        throw e;
    }
}

@Test
public void userMethodDTest(){
    userManager.methodD();
}

测试结果:事务回滚,表中未插入数据,相当于粟子1

3.粟子三

@Transactional(propagation = Propagation.REQUIRED)
public void methodC(){
    try {
        UserDo userDo = new UserDo();
        userDo.setName("user");
        userDo.setUsername("user-aa");
        userDo.setMobile("17370998767");
        userDao.insert(userDo);
        if (1 == 1) {
            throw new RuntimeException("异常");
        }
    } catch (RuntimeException e) {
        e.printStackTrace();
    }
}

# junit
@Test
public void userMethodCTest(){
   userManager.methodC();
}

测试结果:异常被处理,事务不回滚,表中插入数据

多表

GameManager.java中:

@Transactional(propagation = Propagation.REQUIRED)
public void meanB(){
   GameDo gameDo = new GameDo();
   gameDo.setName("测试");
   gameDo.setUserId(1L);
   gameDao.insert(gameDo);
   if (1==1){
       throw new RuntimeException("异常");
   }
}

下面都是在UserManager.java中,调用meanB方法:

1.粟子一:

@Transactional(propagation = Propagation.REQUIRED)
public void methodE() {
    UserDo userDo = new UserDo();
    userDo.setName("user");
    userDo.setUsername("user-aa");
    userDo.setMobile("17370998767");
    userDao.insert(userDo);
    gameManager.meanB();
}

# junit
@Test
public void userMethodETest(){
    userManager.methodE();
}

测试结果:事务回滚,表中未插入数据

2.粟子二

@Transactional(propagation = Propagation.REQUIRED)
public void methodG() {
    UserDo userDo = new UserDo();
    userDo.setName("user");
    userDo.setUsername("user-aa");
    userDo.setMobile("17370998767");
    userDao.insert(userDo);
    try {
        gameManager.meanB();
    } catch (RuntimeException e) {
        e.printStackTrace();
        throw e;
    }
}

# junit

@Test
public void userMethodGTest(){
    userManager.methodG();
}

测试结果:事务回滚,表中未插入数据

3.粟子三:

@Transactional(propagation = Propagation.REQUIRED)
public void methodF() {
    UserDo userDo = new UserDo();
    userDo.setName("user");
    userDo.setUsername("user-aa");
    userDo.setMobile("17370998767");
    userDao.insert(userDo);
    try {
        gameManager.meanB();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

# junit
@Test
public void userMethodFTest(){
    userManager.methodF();
}

测试结果:事务回滚,表中未插入数据

这很奇怪呀,已经try catch了,讲道理是user表会插入数据,而game表中数据回滚,为什么呢?这就是spring事务传播级别Propagation.REQUIRED了,使用了Propagation.REQUIRED,如果本来有事务,则加入该事务,如果没有事务,则创建新的事务,本质上使用的是同一个连接connection。看异常有:

org.springframework.transaction.UnexpectedRollbackException: 
		Transaction rolled back because it has been marked as rollback-only

	at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:485)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)

这个异常的意思是,由于内层抛出异常,已经将Transaction的状态标记为rollback-only,所以外层事务也只好回滚,但这个特性是基于同一个事务的,如果是嵌套事务就不一定了

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring框架中,事务的传播性是指在一个方法中调用另一个方法时,事务应该如何进行传播。其中,REQUIREDSpring事务传播性最常用的一种类型。下面是对REQUIRED事务传播性的详细解释: 1. 如果当前方法已经在一个事务中,则调用的方法将在同一个事务中运行。如果调用的方法发生异常并抛出了异常,则整个事务将回滚。 2. 如果当前方法没有在一个事务中,则调用的方法将开启一个新的事务并在其中运行。如果调用的方法发生异常并抛出了异常,则整个事务将回滚。 3. 如果当前方法没有在一个事务中,但调用的方法标有@Transactional注解并且使用REQUIRED传播性,则调用的方法将加入当前方法所在的事务中。 4. 如果当前方法已经在一个事务中,但调用的方法标有@Transactional注解并且使用REQUIRED_NEW传播性,则当前方法的事务将被挂起,调用的方法将在一个新的事务中运行。如果调用的方法发生异常并抛出了异常,则只有调用方法所在的事务会回滚,当前方法所在的事务不会回滚。 总之,使用REQUIRED传播性可以确保方法在一个事务中运行,同时保证整个事务的一致性和完整性。但需要注意的是,如果方法的执行时间过长,可能会导致事务锁定时间过长,从而影响系统性能。因此,在使用Spring事务时,应该根据具体情况选择合适的事务传播性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值