spring-@Transactional

  1. 事务ACID原则
    • 原子性:原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
    • 一致性:事务前后数据的完整性必须保持一致。
    • 隔离性:事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
    • 持久性: 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
  2. 传播行为
    1. 简介(需要熟悉呦~~~

      行为名称 作用
      REQUIRED 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。(default)
      SUPPORTS 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。
      MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。(必须运行在事务内)
      REQUIRES_NEW 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。(新开事务,如果已经有一个事务,那么就是有两个事务)
      NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务
      NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常(必须事务外)
      NESTED 如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行
    2. 代码

      1. server1
        import org.springframework.stereotype.Service;
        import org.springframework.transaction.annotation.Isolation;
        import org.springframework.transaction.annotation.Propagation;
        import org.springframework.transaction.annotation.Transactional;
        
        import javax.annotation.Resource;
        
        @Service
        public class Server1 {
            @Resource
            private DeptMapper deptMapper;
            @Resource
            private Server2 server2;
        
          /*  @Transactional(
            )*/
            public void update () {
                server2.update();
                Dept dept = new Dept();
                dept.setDeptno(43);
                dept.setLoc("中国-1");
                dept.setDname("事业部-1");
                int i = deptMapper.updateByPrimaryKey(dept);
        
                int b = 1 / 0;
                System.out.println(i);
            }
        }      
        
      2. Server2
        @Service
        public class Server2 {
            @Resource
            private DeptMapper deptMapper;
        
            @Transactional
            public void update () {
                Dept dept = new Dept();
                dept.setDeptno(46);
                dept.setLoc("中国-2");
                dept.setDname("事业部-2");
                int i = deptMapper.updateByPrimaryKey(dept);
            }
        }  
        
      3. 测试类
        @SpringBootTest(classes =  TranscationdemoApplicationTests.class)
        @ComponentScan("com.zh")
        @EnableAutoConfiguration
        @MapperScan("com.zh.transcationdemo.dao")
        class TranscationdemoApplicationTests {
            @Resource
            private SelectThread selectThread;
            @Resource
            private UpdateThread updateThread;
        
            @Resource
            private Server1 server1;
            /**
             *  测试 事务的传播行为 和 事务的隔离性
             */
            @Test
            public void testNone() {
                server1.update();
            }
        
        }
        
    3. 场景

      1. REQUIRED [如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。(default)]
        1. server1 update 方法使用@Transactional,server2 update 方法不使用 @Transactional
          • 则server1和 server2的数据都不会更新,此时默认使用 REQUIRED
          • 数据都会回滚
      2. SUPPORTS [如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。]
        1. server1 update方法使用 @Transactional(propagation = Propagation.REQUIRED),server2 update方法使用@Transactional(propagation = Propagation.SUPPORTS)
          • 此时server1和server2的 update方法会在同一个事务中。
        2. server1 update方法不使用 @Transactional,server2 update方法使用@Transactional(propagation = Propagation.SUPPORTS)
          • 此时 server1和server2的update方法是没有事务
      3. MANDATORY [如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。(必须运行在事务内)]
        1. server1 update 方法使用 @Transactional ,server2 update 方法使用@Transactional(propagation = Propagation.MANDATORY)
          • 此时如果 server2 中update 方法或 server1 中update方法 出现异常,那么,server1 和 server2 的操作都会回滚
      4. REQUIRES_NEW [总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。]
        1. server1 update 方法使用 @Transactional ,server2 update 方法使用@Transactional(propagation = Propagation.REQUIRES_NEW)
          • 如果server1 update 方法在 server2的操作后 中出现错误,那么 server1的操作会回滚,server2不会回滚
          • 此时 是两个事务,server1的update方法开启一个事务,server2的update方法开启一个事务。
      5. NESTED [如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务, 则按REQUIRED 属性执行]
        1. server1 Update 方法使用 @Transactional ,server2 update 方法使用@Transactional(propagation = Propagation.NESTED)
          • 如果 server 2 update 方法 中出现问题,而server1 的 update方法捕捉到,那么,server2 的操作会被回滚,而server1的操作不会回滚。
          • 如果 是server1 的update方法出现错误,那么两个操作都会回滚。
          • 主事务和嵌套事务属于同一个事务
          • 嵌套事务出错回滚不会影响到主事务
          • 主事务回滚会将嵌套事务一起回滚了
    4. 注意

      • 传播行为是针对于 两个事务之间的传播
  1. 隔离性

    1. 简介
      属性名称 作用 是否存在脏读 是否存在不可重复读 是否存在幻读
      DEFAULT 使用后端数据库默认的隔离级别
      READ_UNCOMMITTED 允许读取尚未提交的数据变更(最低的隔离级别)
      READ_COMMITTED 允许读取并发事务已经提交的数据
      REPEATABLE_READ 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改
      SERIALIZABLE 最高的隔离级别,完全服从ACID的隔离级别,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的
    2. 读问题
      1. 脏读
        • 事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。
      2. 不可重复读
        • 事务 A 多次读取同一数据
        • 事务 B 在事务A多次读取的过程中,对数据作了更新并提交
        • 导致事务A多次读取同一数据时,结果不一致。
      3. 幻读
        • 系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,
        • 但是系统管理员B就在这个时候插入了一条具体分数的记录,
        • 当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
  2. 使用注意

    1. @Transactional注解应该只被应用到 public 方法上,这是由Spring AOP的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

    2. 使用位置

      • 实现类的方法
      • 接口类的方法
    3. 默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为(有例子和结论呦~~⬇⬇⬇⬇)

      同一个类调用的测试
      
      @Service
      public class Server1 {
        @Resource
        private DeptMapper deptMapper;
        @Resource
        private Server2 server2;
      
        public  void update () {
            Dept dept = new Dept();
            dept.setDeptno(43);
            dept.setLoc("中国-1");
            dept.setDname("事业部-1");
            int i = deptMapper.updateByPrimaryKey(dept);
            this.update2();
            System.out.println(i);
        }
      
      
        @Transactional
        public  void update2 () {
            Dept dept = new Dept();
            dept.setDeptno(47);
            dept.setLoc("中国-47");
            dept.setDname("事业部-47");
            int i = deptMapper.updateByPrimaryKey(dept);
            int b = 1 / 0;
            System.out.println(i);
        }
      }
      
      
      class TestServer{
        /**
         *  测试 事务的传播行为 和 事务的隔离性
         */
        @Test
        public void testNone() {
            server1.update();
        }
      }
      
      1. 例子
        1. update 方法 上没有@Transactional,而update2 方法上有@Transactional
          • 方法 update2 和update方法的修改都不会回滚
          • 因为是update2方法和update方法在同一个类中,aop捕获不到,update2方法就不会在事务中进行操作,相当于udpate2方法也没有@Transactional标识。
        2. update方法上有@Transactional,而update2方法上没有@Transactional
          • 此时两个方法修改都会回滚
          • 因为调用update方法的是TestServer类中的方法,不在同一个类,可以使用aop代理,此时 update方法就是在事务中进行的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,029评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,238评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,576评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,214评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,324评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,392评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,416评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,196评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,631评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,919评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,090评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,767评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,410评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,090评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,328评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,952评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,979评论 2 351