spring事务传播机制_Spring事务传播机制

2a8a2bf53dccccf6543803a1236aefda.png

@Transational

Spring事务传播设置有如下类型:

  1. REQUIRED :如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。==> 会跟随service层方法回滚事务
  2. SUPPORTS :如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。==> 会跟随service层方法回滚事务
  3. MANDATORY :如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。==> 会跟随service层方法回滚事务
  4. REQUIRES_NEW :创建一个新的事务,如果当前存在事务,则把当前事务挂起。 ==> 即使service层的方法也加了事务,也无法回滚dao层的事务(内层已经提交了,外层回滚个屁啊)。
  5. NOT_SUPPORTED :以非事务方式运行,如果当前存在事务,则把当前事务挂起。 ==> 即使service层的方法也加了事务,也无法回滚dao层的事务(内层已经提交了,外层回滚个屁啊)。
  6. NEVER :以非事务方式运行,如果当前存在事务,则抛出异常。 ==> service层无事务的方法可以运行,也就是说,他只能被一个父事务调用。否则,他就要抛出异常。
  7. NESTED :如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 REQUIRED

上述只是单事务方法的情况,如果存在事务嵌套呢??比如serviceA.methodA()内部调用了serviceB.methodB()方法,methodA()和methodB()都是有事务的。这种情况下可以根据如下表格对照:

7b00e76d30d081e98691978c0507edb7.png
c02dc741242a372db649a979a2589ce5.png
822c215c63ae27a9b5f9175bef8a1500.png

简单示例:

package com.ubuntuvim.mybatis.service;import java.util.Random;import java.util.UUID;import javax.annotation.Resource;import com.ubuntuvim.mybatis.dao.UserMapper;import com.ubuntuvim.mybatis.entity.User;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;/** * @Author: ubuntuvim * @Date: 2020/9/8 下午10:18 */@Servicepublic class UserServiceImpl implements UserService {    @Resource    UserMapper userMapper;    @Override    public void saveOneNoTransition() {        userMapper.save(new User(UUID.randomUUID().toString(), "王五service无事务"+new Random().nextInt(10), "M"));    }    @Transactional(rollbackFor = Exception.class)    @Override    public void saveOneHasTransition() {        userMapper.save(new User(UUID.randomUUID().toString(), "ubuntuvim,service有事务"+new Random().nextInt(10), "M"));    }    @Override    public void saveUsersNoTransition() {        String id = UUID.randomUUID().toString();        userMapper.save(new User(UUID.randomUUID().toString(), "张三service无事务", "M"));        userMapper.save(new User(id, "张三2service无事务", "F"));        userMapper.save(new User(UUID.randomUUID().toString(), "张三3service无事务", "F"));        userMapper.save(new User(UUID.randomUUID().toString(), "张三4service无事务", "M"));        // 这个save的id和第二个相同会导致数据库id主键冲突报错,因为当前方法没有加事务不会回滚前面的save持久化        userMapper.save(new User(id, "张三5service无事务", "M"));        userMapper.save(new User(UUID.randomUUID().toString(), "张三6service无事务", "F"));        userMapper.save(new User(UUID.randomUUID().toString(), "张三7service无事务", "M"));    }    /**     * 由于此方法上添加了事务,即使在调用的userMapper.save()方法上也添加事务也会回滚。     * 但是如果dao的save方法的事务传播属性声明为propagation = Propagation.REQUIRES_NEW则无法回滚,在dao层已经提交了事务。service层回滚不了了。     *     */    @Transactional(rollbackFor = Exception.class)    @Override    public void saveUsersHasTransition() {        String id = UUID.randomUUID().toString();        userMapper.save(new User(UUID.randomUUID().toString(), "李四service有事务", "F"));        userMapper.save(new User(id, "李四2service有事务", "F"));        userMapper.save(new User(UUID.randomUUID().toString(), "李四3service有事务", "F"));        userMapper.save(new User(UUID.randomUUID().toString(), "李四4service有事务", "M"));        /*         @Transactional(rollbackFor = Exception.class)         这个save的id和第二个相同会导致数据库id主键冲突报错,但是当前方法加了事务会从异常这个回滚前面的save         最终结果是这个方法内的save都不会持久化         */        userMapper.save(new User(id, "张三5service有事务", "M"));        userMapper.save(new User(UUID.randomUUID().toString(), "李四6service有事务", "M"));        userMapper.save(new User(UUID.randomUUID().toString(), "李四7service有事务", "F"));    }}

service调用dao的方法。

package com.ubuntuvim.mybatis.dao;import com.ubuntuvim.mybatis.entity.User;import org.apache.ibatis.annotations.Insert;import org.apache.ibatis.annotations.Select;import org.springframework.transaction.annotation.Propagation;import org.springframework.transaction.annotation.Transactional;/** * @Author: ubuntuvim * @Date: 2020/8/2 20:54 */public interface UserMapper {    @Select("select * from user t where t.name = #{name}")    User getUser(User user);    /**     * 保存user,id是唯一的,否则insert会报错     * REQUIRED :如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。==> 会跟随service层方法回滚事务     * SUPPORTS :如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。==> 会跟随service层方法回滚事务     * MANDATORY :如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。==> 会跟随service层方法回滚事务     * REQUIRES_NEW :创建一个新的事务,如果当前存在事务,则把当前事务挂起。 ==> 即使service层的方法也加了事务,也无法回滚dao层的事务(内层已经提交了,外层回滚个屁啊)。     * NOT_SUPPORTED :以非事务方式运行,如果当前存在事务,则把当前事务挂起。 ==>  即使service层的方法也加了事务,也无法回滚dao层的事务(内层已经提交了,外层回滚个屁啊)。     * NEVER :以非事务方式运行,如果当前存在事务,则抛出异常。 ==> service层无事务的方法可以运行,也就是说,他只能被一个父事务调用。否则,他就要抛出异常。     * NESTED :如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 REQUIRED     * @param user     */    @Transactional(rollbackFor = Exception.class, propagation = Propagation.NESTED)    @Insert("insert into user(id, name, sex) value (#{id}, #{name}, #{sex})")    void save(User user);}

测试类:

package com.ubuntuvim.mybatis.service;import javax.annotation.Resource;import com.ubuntuvim.mybatis.MybatisTest;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/** * UserServiceImpl Tester. * * @author  * @since 
9月 8, 2020 * @version 1.0 */@RunWith(SpringJUnit4ClassRunner.class)@SpringBootTest(classes = MybatisTest.class)public class UserServiceImplTest {     @Resource    UserService userServiceImpl;    @Test    public void testSaveUsersNoTransition() throws Exception {        userServiceImpl.saveUsersNoTransition();    }    @Test    public void testSaveUsersHasTransition() throws Exception {        userServiceImpl.saveUsersHasTransition();    }    @Test    public void testSaveOneNoTransation() {        userServiceImpl.saveOneNoTransition();    }    @Test    public void testSaveOneHasTransation() {        userServiceImpl.saveOneHasTransition();    }}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值