zoukankan      html  css  js  c++  java
  • 理解spring对事务的处理:传播性

    所谓事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。Spring 支持 7 种事务传播行为:

    • PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
    • PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
    • PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
    • PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
    • PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
    • PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
    • PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 PROPAGATION_REQUIRED 类似的操作。

    Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况。假设 ServiveX#methodX() 都工作在事务环境下(即都被 Spring 事务增强了),假设程序中存在如下的调用 链:Service1#method1()->Service2#method2()->Service3#method3(),那么这 3 个服务类的 3 个方法通过 Spring 的事务传播机制都工作在同一个事务中。

    spring 管理事务一般配置在service层、曾经用struts把事务配置在action层 导致系统并发卡死特别严重 分析了下原因:action层并发量过大、数据库经常锁死在某一块;

    spring 配置在service层研究:

    测试方法:查询---》更新-----》查询   分析数据在什么时候提交至数据库

     一  在同一个service中 互相调本类中的方法

    @Service
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class})  // 当标于类前时, 标示类中所有方法都进行事物处理
    public class LoginService extends BaseServiceImpl implements ILoginService {

        @Autowired
        private ILoginDao loginDao;

        @Override
        @Transactional(propagation = Propagation.NOT_SUPPORTED)
        public ResultBase login(SysUser sysUser) {
            ResultBase res=new ResultBase();
            SysUser user=(SysUser) loginDao.get(SysUser.class,sysUser.getUuid());
            res.setObj(user);
            res.setResult(ResultBase.RESULT_SUCC);
            res.setMessage("成功");
            return res;
        }
        @Transactional(propagation = Propagation.REQUIRED)
        public ResultBase update(SysUser sysUser) {
            ResultBase res=new ResultBase();
            loginDao.update(sysUser);
            res.setResult(ResultBase.RESULT_SUCC);
            res.setMessage("成功");
            return res;
        }
        @Transactional(propagation = Propagation.SUPPORTS)  //此方法用于测试 结果 数据库中在此方法走完才更新至数据库
        public ResultBase searchAndUpdate(SysUser sysUser) {
            ResultBase res=new ResultBase();
            res=login(sysUser);
            sysUser=(SysUser) res.getObj();
            sysUser.setLoginname("123");
            update(sysUser);
            res.setMessage("成功");
            return res;
        }

    二  在不同service中 互相调别的service中的方法:第一层事务传播使用NOT_SUPPORTED

    @Service
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class})  // 当标于类前时, 标示类中所有方法都进行事物处理
    public class OperateService extends BaseServiceImpl implements IOperateService {

        @Autowired
        private ILoginService loginService;
        
        /**
         * 事务测试:一个service 调另一个 service 何时更新数据
         * @param sysUser
         * @return
         */
        @Override
        @Transactional(propagation = Propagation.NOT_SUPPORTED)
        public ResultBase TransactionTset(SysUser sysUser) {
            ResultBase res=new ResultBase();
            res=loginService.login(sysUser);
            sysUser=(SysUser) res.getObj();
            sysUser.setLoginname("123");
            loginService.update(sysUser);
            res=loginService.login(sysUser);
            res.setMessage("成功");
            return res;
        }

    结果:方法执行完    loginService.update(sysUser);后数据已经提交  注意:TransactionTset方法@Transactional(propagation = Propagation.NOT_SUPPORTED)设置不使用事务

    三  在不同service中 互相调别的service中的方法:第一层事务传播使用REQUIRED

    @Service
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class})  // 当标于类前时, 标示类中所有方法都进行事物处理
    public class OperateService extends BaseServiceImpl implements IOperateService {

        @Autowired
        private ILoginService loginService;
        
        /**
         * 事务测试:一个service 调另一个 service 何时更新数据
         * @param sysUser
         * @return
         */
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public ResultBase TransactionTset(SysUser sysUser) {
            ResultBase res=new ResultBase();
            res=loginService.login(sysUser);
            sysUser=(SysUser) res.getObj();
            sysUser.setLoginname("123");
            loginService.update(sysUser);
            res=loginService.login(sysUser);
            res.setMessage("成功");
            return res;
        }

    结果:方法执行到最后数据才提交 说明事务已经传播到到下一个service 而且属于同一事务  注意:TransactionTset方法@Transactional(propagation = Propagation.REQUIRED)设置使用REQUIRED事务

    结论:在同一个事务中 前者改变了数据(新增或者更新) 下面service或者自身的方法再次查询 数据是已经改变了、但是service没有走到最后 数据库的数据还是没变化的

    TUser user1=(TUser) operateDao.get(TUser.class, sysUser.getId());
            user1.setPassword("12222");
            operateDao.update(user1);
            user1=(TUser) operateDao.get(TUser.class, sysUser.getId());
            
            Map<String,Class> classMap=new HashMap<String,Class>();
            StringBuffer sql=new StringBuffer("select u.* from t_user as u where id='"+sysUser.getId()+"'");
            PageModel pm=operateDao.searchResultBySql(sql.toString(),null, 0, 0);
    /*        StringBuffer sql=new StringBuffer("select {u.*} from t_user as u where id='"+sysUser.getId()+"'");
            classMap.put("u", TUser.class);
            PageModel pm=operateDao.searchResultBySql(sql.toString(),null, classMap, 0, 0);
    */        System.out.println("11");
            System.out.println("11");
            System.out.println("11");
            System.out.println("11");
            return res;

    为了测试 同一事务中先更新再查询 结果:

           映射对象查询到update后的数据、虽然事务未提交

            纯sql查询的是事务未提交前的数据

         数据在service介绍提交至数据库

  • 相关阅读:
    设置eclipse编码
    前端基础知识
    微信小程序
    jQuery下拉框
    Vue-cli的安装
    vue的数据交互形式
    node安装和小测试
    shui
    JQ-滚动条下拉无限的加载数据
    HTML-video全屏
  • 原文地址:https://www.cnblogs.com/lykxqhh/p/5703626.html
Copyright © 2011-2022 走看看