精华内容
下载资源
问答
  • 主要介绍了spring的@Transactional注解用法解读,具有一定借鉴价值,需要的朋友可以参考下
  • 主要介绍了Spring @Transactional注解失效解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • @Transactional注解使用

    2019-10-21 16:25:23
    @Transactional注解 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。 虽然@...

    1.1 @Transactional介绍

           @Transactional注解 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

           虽然@Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional注解应该只被应用到 public 方法上,这是由Spring AOP的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

           默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。

    1.2 @Transactional注解属性

           @Transactional注解里面的各个属性和咱们在上面讲的事务属性里面是一一对应的。用来设置事务的传播行为、隔离规则、回滚规则、事务超时、是否只读。

    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface Transactional {
    
        /**
         * 当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器。
         */
        @AliasFor("transactionManager")
        String value() default "";
    
        /**
         * 同上。
         */
        @AliasFor("value")
        String transactionManager() default "";
    
        /**
         * 事务的传播行为,默认值为 REQUIRED。
         */
        Propagation propagation() default Propagation.REQUIRED;
    
        /**
         * 事务的隔离规则,默认值采用 DEFAULT。
         */
        Isolation isolation() default Isolation.DEFAULT;
    
        /**
         * 事务超时时间。
         */
        int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
    
        /**
         * 是否只读事务
         */
        boolean readOnly() default false;
    
        /**
         * 用于指定能够触发事务回滚的异常类型。
         */
        Class<? extends Throwable>[] rollbackFor() default {};
    
        /**
         * 同上,指定类名。
         */
        String[] rollbackForClassName() default {};
    
        /**
         * 用于指定不会触发事务回滚的异常类型
         */
        Class<? extends Throwable>[] noRollbackFor() default {};
    
        /**
         * 同上,指定类名
         */
        String[] noRollbackForClassName() default {};
    
    }
    

    1.2.1 value、transactionManager属性

           它们两个是一样的意思。当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器。大多数项目只需要一个事务管理器。然而,有些项目为了提高效率、或者有多个完全不同又不相干的数据源,从而使用了多个事务管理器。机智的Spring的Transactional管理已经考虑到了这一点,首先定义多个transactional manager,并为qualifier属性指定不同的值;然后在需要使用@Transactional注解的时候指定TransactionManager的qualifier属性值或者直接使用bean名称。配置和代码使用的例子:

    <tx:annotation-driven/>
     
    <bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource1"></property>
        <qualifier value="datasource1Tx"/>
    </bean>
     
    <bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource2"></property>
        <qualifier value="datasource2Tx"/>
    </bean>
    
    public class TransactionalService {
     
        @Transactional("datasource1Tx")
        public void setSomethingInDatasource1() { ... }
     
        @Transactional("datasource2Tx")
        public void doSomethingInDatasource2() { ... }
    
    }
    

    1.2.2 propagation属性

           propagation用于指定事务的传播行为,默认值为 REQUIRED。propagation有七种类型,就是我们在上文中讲到的事务属性传播行为的七种方式,如下所示:

    propagation属性事务属性-传播行为含义
    REQUIREDTransactionDefinition.PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务,则加入到这个事务中。这是最常见的选择。
    SUPPORTSTransactionDefinition.PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行。
    MANDATORYTransactionDefinition.PROPAGATION_MANDATORY表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常。
    REQUIRES_NEWTransactionDefinition.PROPAGATION_REQUIRES_NEW表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。
    NOT_SUPPORTEDTransactionDefinition.PROPAGATION_NOT_SUPPORTED表示该方法不应该运行在事务中。如果当前存在事务,就把当前事务挂起。
    NEVERTransactionDefinition.PROPAGATION_NEVER表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常。
    NESTEDTransactionDefinition.PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

    1.2.3 isolation属性

           isolation用于指定事务的隔离规则,默认值为DEFAULT。@Transactional的隔离规则和上文事务属性里面的隔离规则也是一一对应的。总共五种隔离规则,如下所示:

    @isolation属性事务属性-隔离规则含义脏读不可重复读幻读
    DEFAULTTransactionDefinition.ISOLATION_DEFAULT使用后端数据库默认的隔离级别  
    READ_UNCOMMITTEDTransactionDefinition.ISOLATION_READ_UNCOMMITTED允许读取尚未提交的数据变更(最低的隔离级别)
    READ_COMMITTEDTransactionDefinition.ISOLATION_READ_COMMITTED允许读取并发事务已经提交的数据
    REPEATABLE_READTransactionDefinition.ISOLATION_REPEATABLE_READ对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改
    SERIALIZABLETransactionDefinition.ISOLATION_SERIALIZABLE最高的隔离级别,完全服从ACID的隔离级别,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的

    1.2.4 timeout

           timeout用于设置事务的超时属性。

    1.2.5 readOnly

           readOnly用于设置事务是否只读属性。

    1.2.6 rollbackFor、rollbackForClassName、noRollbackFor、noRollbackForClassName

           rollbackFor、rollbackForClassName用于设置那些异常需要回滚;noRollbackFor、noRollbackForClassName用于设置那些异常不需要回滚。他们就是在设置事务的回滚规则。

    1.3 @Transactional注解的使用

           @Transactional注解的使用关键点在理解@Transactional注解里面各个参数的含义。这个咱们在上面已经对@Transactional注解参数的各个含义做了一个简单的介绍。接下来,咱们着重讲一讲@Transactional注解使用过程中一些注意的点。

           @Transactional注解内部实现依赖于Spring AOP编程。而AOP在默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为。

    1.3.1 @Transactional 注解尽量直接加在方法上

           为什么:因为@Transactional直接加在类或者接口上,@Transactional注解会对类或者接口里面所有的public方法都有效(相当于所有的public方法都加上了@Transactional注解,而且注解带的参数都是一样的)。第一影响性能,可能有些方法我不需要@Transactional注解,第二方法不同可能@Transactional注解需要配置的参数也不同,比如有一个方法只是做查询操作,那咱们可能需要配置Transactional注解的readOnly参数。所以强烈建议@Transactional注解直接添加的需要的方法上。

    1.3.2 @Transactional 注解必须添加在public方法上,private、protected方法上是无效的

           在使用@Transactional 的时候一定要记住,在private,protected方法上添加@Transactional 注解不会有任何效果。相当于没加一样。即使外部能调到protected的方法也无效。和没有添加@Transactional一样。

    1.3.3 函数之间相互调用

           关于有@Transactional的函数之间调用,会产生什么情况。这里咱们通过几个例子来说明。

    2.3.3.1 同一个类中函数相互调用

           同一个类AClass中,有两个函数aFunction、aInnerFunction。aFunction调用aInnerFunction。而且aFunction函数会被外部调用。

    情况0: aFunction添加了@Transactional注解,aInnerFunction函数没有添加。aInnerFunction抛异常。

    public class AClass {
    
        @Transactional(rollbackFor = Exception.class)
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            aInnerFunction(); // 调用内部没有添加@Transactional注解的函数
        }
    
        private void aInnerFunction() {
            //todo: 操作数据B(做了增,删,改 操作)
            throw new RuntimeException("函数执行有异常!");
        }
    
    }
    

           结果:两个函数操作的数据都会回滚。

    情况1:两个函数都添加了@Transactional注解。aInnerFunction抛异常。

    public class AClass {
    
        @Transactional(rollbackFor = Exception.class)
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            aInnerFunction(); // 调用内部没有添加@Transactional注解的函数
        }
    
        @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
        private void aInnerFunction() {
            //todo: 操作数据B(做了增,删,改 操作)
            throw new RuntimeException("函数执行有异常!");
        }
    
    }
    

           结果:同第一种情况一样,两个函数对数据库操作都会回滚。因为同一个类中函数相互调用的时候,内部函数添加@Transactional注解无效。@Transactional注解只有外部调用才有效。

    情况2: aFunction不添加注解,aInnerFunction添加注解。aInnerFunction抛异常。

    public class AClass {
    
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            aInnerFunction(); // 调用内部没有添加@Transactional注解的函数
        }
    
        @Transactional(rollbackFor = Exception.class)
        protected void aInnerFunction() {
            //todo: 操作数据B(做了增,删,改 操作)
            throw new RuntimeException("函数执行有异常!");
        }
    
    }
    

           结果:两个函数对数据库的操作都不会回滚。因为内部函数@Transactional注解添加和没添加一样。

    情况3:aFunction添加了@Transactional注解,aInnerFunction函数没有添加。aInnerFunction抛异常,不过在aFunction里面把异常抓出来了。

    public class AClass {
    
        @Transactional(rollbackFor = Exception.class)
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            try {
                aInnerFunction(); // 调用内部没有添加@Transactional注解的函数
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private void aInnerFunction() {
            //todo: 操作数据B(做了增,删,改 操作)
            throw new RuntimeException("函数执行有异常!");
        }
    
    }
    

           结果:两个函数里面的数据库操作都成功。事务回滚的动作发生在当有@Transactional注解函数有对应异常抛出时才会回滚。(当然了要看你添加的@Transactional注解有没有效)。

    1.3.3.1. 不同类中函数相互调用

           两个类AClass、BClass。AClass类有aFunction、BClass类有bFunction。AClass类aFunction调用BClass类bFunction。最终会在外部调用AClass类的aFunction。

    情况0:aFunction添加注解,bFunction不添加注解。bFunction抛异常。

    @Service()
    public class AClass {
    
        private BClass bClass;
    
        @Autowired
        public void setbClass(BClass bClass) {
            this.bClass = bClass;
        }
    
        @Transactional(rollbackFor = Exception.class)
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            bClass.bFunction();
        }
    
    }
    
    @Service()
    public class BClass {
    
        public void bFunction() {
            //todo: 数据库操作A(增,删,该)
            throw new RuntimeException("函数执行有异常!");
        }
    }
    

           结果:两个函数对数据库的操作都回滚了。

    情况1:aFunction、bFunction两个函数都添加注解,bFunction抛异常。

    @Service()
    public class AClass {
    
        private BClass bClass;
    
        @Autowired
        public void setbClass(BClass bClass) {
            this.bClass = bClass;
        }
    
        @Transactional(rollbackFor = Exception.class)
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            bClass.bFunction();
        }
    
    }
    
    @Service()
    public class BClass {
    
        @Transactional(rollbackFor = Exception.class)
        public void bFunction() {
            //todo: 数据库操作A(增,删,该)
            throw new RuntimeException("函数执行有异常!");
        }
    }
    

           结果:两个函数对数据库的操作都回滚了。两个函数里面用的还是同一个事务。这种情况下,你可以认为事务rollback了两次。两个函数都有异常。

    情况2:aFunction、bFunction两个函数都添加注解,bFunction抛异常。aFunction抓出异常。

    @Service()
    public class AClass {
    
        private BClass bClass;
    
        @Autowired
        public void setbClass(BClass bClass) {
            this.bClass = bClass;
        }
    
        @Transactional(rollbackFor = Exception.class)
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            try {
                bClass.bFunction();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }
    
    @Service()
    public class BClass {
    
        @Transactional(rollbackFor = Exception.class)
        public void bFunction() {
            //todo: 数据库操作A(增,删,该)
            throw new RuntimeException("函数执行有异常!");
        }
    }
    

           结果:两个函数数据库操作都没成功。而且还抛异常了。org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only。看打印出来的解释也很好理解把。咱们也可以这么理解,两个函数用的是同一个事务。bFunction函数抛了异常,调了事务的rollback函数。事务被标记了只能rollback了。程序继续执行,aFunction函数里面把异常给抓出来了,这个时候aFunction函数没有抛出异常,既然你没有异常那事务就需要提交,会调事务的commit函数。而之前已经标记了事务只能rollback-only(以为是同一个事务)。直接就抛异常了,不让调了。

    情况3:aFunction、bFunction两个函数都添加注解,bFunction抛异常。aFunction抓出异常。这里要注意bFunction函数@Transactional注解我们是有变化的,加了一个参数propagation = Propagation.REQUIRES_NEW,控制事务的传播行为。表明是一个新的事务。其实咱们情况3就是来解决情况2的问题的。

    @Service()
    public class AClass {
    
        private BClass bClass;
    
        @Autowired
        public void setbClass(BClass bClass) {
            this.bClass = bClass;
        }
    
        @Transactional(rollbackFor = Exception.class)
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            try {
                bClass.bFunction();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }
    
    @Service()
    public class BClass {
    
        @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
        public void bFunction() {
            //todo: 数据库操作A(增,删,该)
            throw new RuntimeException("函数执行有异常!");
        }
    }
    

           结果:bFunction函数里面的操作回滚了,aFunction里面的操作成功了。有了前面情况2的理解。这种情况也很好解释。两个函数不是同一个事务了。


         总结:

    1. 要知道@Transactional注解里面每个属性的含义。@Transactional注解属性就是来控制事务属性的。通过这些属性来生成事务。

    2. 要明确我们添加的@Transactional注解会不会起作用。@Transactional注解在外部调用的函数上才有效果,内部调用的函数添加无效,要切记。这是由AOP的特性决定的。

    3. 要明确事务的作用范围,有@Transactional的函数调用有@Transactional的函数的时候,进入第二个函数的时候是新的事务,还是沿用之前的事务。稍不注意就会抛UnexpectedRollbackException异常。

    展开全文
  • @Transactional注解详细使用

    万次阅读 2020-06-17 11:33:03
    三、开发案例 workflow服务: payment服务添加注解:回滚所有的异常。 workflow调用payment服务的saveTransactionDatasBatch方法:

    一、@Transactional 注解使用

                 1. @Transactional  注解只能用在public 方法上,如果用在protected或者private的方法上,不会报错,但是该注解不会生效。

                 2. @Transactional注解只能回滚非检查型异常,具体为RuntimeException及其子类。

                3. 使用rollbackFor 属性来定义回滚的异常类型,使用 propagation 属性定义事务的传播行为。如:

                  回滚Exception类的异常,事务的传播行为支持当前事务,如果没有事务,那么会创建一个事务。

                4. @Transactional注解不能回滚被try{}catch() 捕获的异常。

                5. @Transactional注解只能对在被Spring 容器扫描到的类下的方法生效。

     @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)

     二、 Spring事务的传播行为

       

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

      

    三、开发案例

    workflow服务, 设置的事务传播行为为 :REQUIED

     

    payment服务添加注解: 回滚所有的异常。

     

    用feign实现workflow 服务调用Payment服务:

    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import java.util.List;
    
    /**
     * PaymentInterface
     *
     * @Date:2019/8/19
     * @remark
     */
    @FeignClient(
            name = "payment",
            contextId = "PaymentInterface"
    )
    public interface PaymentInterface {
    
        @PostMapping({"/api/implement/payment/cash/transactionData/batch/v2"})
        void saveTransactionDatasBatch(@RequestBody List<ApprovalDocumentWithValuesCODTO> cashTransactionDatas);
    
    
    }
    

     

    测试:

      workflow 调用payment服务的saveTransactionDatasBatch方法, 然Payment服务报错,workflow服务收到错误后回滚:

    展开全文
  • 主要介绍了Java注解@Transactional事务类内调用不生效问题及解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。 2.2 @Transactional注解属性 @...

    https://www.jianshu.com/p/befc2d73e487

    一、事务简单介绍

           事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功。

    1.1 事务基本要素

    • 原子性(Atomicity): 事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
    • 一致性(Consistency): 事务开始前和结束后,数据库的完整性约束没有被破坏。比如A向B转账,不可能A扣了钱,B却没收到。
    • 隔离性(Isolation): 同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
    • 持久性(Durability): 事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

    1.2 Spring事务属性

    Spring事务属性对应TransactionDefinition类里面的各个方法。TransactionDefinition类方法如下所示:

     

    public interface TransactionDefinition {
    
        /**
         * 返回事务传播行为
         */
        int getPropagationBehavior();
    
        /**
         * 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
         */
        int getIsolationLevel();
    
        /**
         * 事务超时时间,事务必须在多少秒之内完成
         */
        int getTimeout();
    
        /**
         * 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的
         */
        boolean isReadOnly();
    
        /**
         * 事务名字
         */
        @Nullable
        String getName();
    }
    

           事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。事务属性包含了5个方面:传播行为、隔离规则、回滚规则、事务超时、是否只读。

    事务的产生需要依赖这些事务属性。包括我们下面要讲到的@Transactional注解的属性其实就是在设置这些值。

    1.2.1 传播行为

           当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。Spring定义了七种传播行为:

    传播行为含义
    TransactionDefinition.PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务,则加入到这个事务中。这是最常见的选择。
    TransactionDefinition.PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行。
    TransactionDefinition.PROPAGATION_MANDATORY表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常
    TransactionDefinition.PROPAGATION_REQUIRED_NEW表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。
    TransactionDefinition.PROPAGATION_NOT_SUPPORTED表示该方法不应该运行在事务中。如果当前存在事务,就把当前事务挂起。
    TransactionDefinition.PROPAGATION_NEVER表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常
    TransactionDefinition.PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

    1.2.2 隔离规则

           隔离级别定义了一个事务可能受其他并发事务影响的程度。

           在实际开发过程中,我们绝大部分的事务都是有并发情况。下多个事务并发运行,经常会操作相同的数据来完成各自的任务。在这种情况下可能会导致以下的问题:

    • 脏读(Dirty reads)—— 事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。
    • 不可重复读(Nonrepeatable read)—— 事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。
    • 幻读(Phantom read)—— 系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

    不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

           咱们已经知道了在并发状态下可能产生: 脏读、不可重复读、幻读的情况。因此我们需要将事务与事务之间隔离。根据隔离的方式来避免事务并发状态下脏读、不可重复读、幻读的产生。Spring中定义了五种隔离规则:

    隔离级别含义脏读不可重复读幻读
    TransactionDefinition.ISOLATION_DEFAULT使用后端数据库默认的隔离级别  
    TransactionDefinition.ISOLATION_READ_UNCOMMITTED允许读取尚未提交的数据变更(最低的隔离级别)
    TransactionDefinition.ISOLATION_READ_COMMITTED允许读取并发事务已经提交的数据
    TransactionDefinition.ISOLATION_REPEATABLE_READ对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改
    TransactionDefinition.ISOLATION_SERIALIZABLE最高的隔离级别,完全服从ACID的隔离级别,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的

           ISOLATION_SERIALIZABLE 隔离规则类型在开发中很少用到。举个很简单的例子。咱们使用了ISOLATION_SERIALIZABLE规则。A,B两个事务操作同一个数据表并发过来了。A先执行。A事务这个时候会把表给锁住,B事务执行的时候直接报错。

           补充:

    • 事务隔离级别为ISOLATION_READ_UNCOMMITTED时,写数据只会锁住相应的行。
    • 事务隔离级别为可ISOLATION_REPEATABLE_READ时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。
    • 事务隔离级别为ISOLATION_SERIALIZABLE时,读写数据都会锁住整张表。
    • 隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也就越大。

    1.2.3 回滚规则

           事务回滚规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,只有未检查异常(RuntimeException和Error类型的异常)会导致事务回滚。而在遇到检查型异常时不会回滚。 但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。

    1.2.4 事务超时

           为了使应用程序很好地运行,事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定,也会占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。

    1.2.5 是否只读

           如果在一个事务中所有关于数据库的操作都是只读的,也就是说,这些操作只读取数据库中的数据,而并不更新数据, 这个时候我们应该给该事务设置只读属性,这样可以帮助数据库引擎优化事务。提升效率。

    二、@Transactional使用

           Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编码式和声明式的两种方式:

    • 编程式事务:允许用户在代码中精确定义事务的边界。编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

    • 声明式事务: 基于AOP,有助于用户将操作与事务规则进行解耦。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务管理也有两种常用的方式,一种是在配置文件(xml)中做相关的事务规则声明,另一种是基于@Transactional注解的方式。显然基于注解的方式更简单易用,更清爽。@Transactional注解的使用也是我们本文着重要理解的部分。

           显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

    2.1 @Transactional介绍

           @Transactional注解 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

           虽然@Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional注解应该只被应用到 public 方法上,这是由Spring AOP的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

           默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。

    2.2 @Transactional注解属性

           @Transactional注解里面的各个属性和咱们在上面讲的事务属性里面是一一对应的。用来设置事务的传播行为、隔离规则、回滚规则、事务超时、是否只读。

     

    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface Transactional {
    
        /**
         * 当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器。
         */
        @AliasFor("transactionManager")
        String value() default "";
    
        /**
         * 同上。
         */
        @AliasFor("value")
        String transactionManager() default "";
    
        /**
         * 事务的传播行为,默认值为 REQUIRED。
         */
        Propagation propagation() default Propagation.REQUIRED;
    
        /**
         * 事务的隔离规则,默认值采用 DEFAULT。
         */
        Isolation isolation() default Isolation.DEFAULT;
    
        /**
         * 事务超时时间。
         */
        int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
    
        /**
         * 是否只读事务
         */
        boolean readOnly() default false;
    
        /**
         * 用于指定能够触发事务回滚的异常类型。
         */
        Class<? extends Throwable>[] rollbackFor() default {};
    
        /**
         * 同上,指定类名。
         */
        String[] rollbackForClassName() default {};
    
        /**
         * 用于指定不会触发事务回滚的异常类型
         */
        Class<? extends Throwable>[] noRollbackFor() default {};
    
        /**
         * 同上,指定类名
         */
        String[] noRollbackForClassName() default {};
    
    }
    

    2.2.1 value、transactionManager属性

           它们两个是一样的意思。当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器。大多数项目只需要一个事务管理器。然而,有些项目为了提高效率、或者有多个完全不同又不相干的数据源,从而使用了多个事务管理器。机智的Spring的Transactional管理已经考虑到了这一点,首先定义多个transactional manager,并为qualifier属性指定不同的值;然后在需要使用@Transactional注解的时候指定TransactionManager的qualifier属性值或者直接使用bean名称。配置和代码使用的例子:

     

    <tx:annotation-driven/>
     
    <bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource1"></property>
        <qualifier value="datasource1Tx"/>
    </bean>
     
    <bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource2"></property>
        <qualifier value="datasource2Tx"/>
    </bean>
    

     

    public class TransactionalService {
     
        @Transactional("datasource1Tx")
        public void setSomethingInDatasource1() { ... }
     
        @Transactional("datasource2Tx")
        public void doSomethingInDatasource2() { ... }
    
    }
    

    2.2.2 propagation属性

           propagation用于指定事务的传播行为,默认值为 REQUIRED。propagation有七种类型,就是我们在上文中讲到的事务属性传播行为的七种方式,如下所示:

    propagation属性事务属性-传播行为含义
    REQUIREDTransactionDefinition.PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务,则加入到这个事务中。这是最常见的选择。
    SUPPORTSTransactionDefinition.PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行。
    MANDATORYTransactionDefinition.PROPAGATION_MANDATORY表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常。
    REQUIRES_NEWTransactionDefinition.PROPAGATION_REQUIRES_NEW表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。
    NOT_SUPPORTEDTransactionDefinition.PROPAGATION_NOT_SUPPORTED表示该方法不应该运行在事务中。如果当前存在事务,就把当前事务挂起。
    NEVERTransactionDefinition.PROPAGATION_NEVER表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常。
    NESTEDTransactionDefinition.PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

    2.2.3 isolation属性

           isolation用于指定事务的隔离规则,默认值为DEFAULT。@Transactional的隔离规则和上文事务属性里面的隔离规则也是一一对应的。总共五种隔离规则,如下所示:

    @isolation属性事务属性-隔离规则含义脏读不可重复读幻读
    DEFAULTTransactionDefinition.ISOLATION_DEFAULT使用后端数据库默认的隔离级别  
    READ_UNCOMMITTEDTransactionDefinition.ISOLATION_READ_UNCOMMITTED允许读取尚未提交的数据变更(最低的隔离级别)
    READ_COMMITTEDTransactionDefinition.ISOLATION_READ_COMMITTED允许读取并发事务已经提交的数据
    REPEATABLE_READTransactionDefinition.ISOLATION_REPEATABLE_READ对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改
    SERIALIZABLETransactionDefinition.ISOLATION_SERIALIZABLE最高的隔离级别,完全服从ACID的隔离级别,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的

    2.2.4 timeout

           timeout用于设置事务的超时属性。

    2.2.5 readOnly

           readOnly用于设置事务是否只读属性。

    2.2.6 rollbackFor、rollbackForClassName、noRollbackFor、noRollbackForClassName

           rollbackFor、rollbackForClassName用于设置那些异常需要回滚;noRollbackFor、noRollbackForClassName用于设置那些异常不需要回滚。他们就是在设置事务的回滚规则。

    2.3 @Transactional注解的使用

           @Transactional注解的使用关键点在理解@Transactional注解里面各个参数的含义。这个咱们在上面已经对@Transactional注解参数的各个含义做了一个简单的介绍。接下来,咱们着重讲一讲@Transactional注解使用过程中一些注意的点。

           @Transactional注解内部实现依赖于Spring AOP编程。而AOP在默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为。

    2.3.1 @Transactional 注解尽量直接加在方法上

           为什么:因为@Transactional直接加在类或者接口上,@Transactional注解会对类或者接口里面所有的public方法都有效(相当于所有的public方法都加上了@Transactional注解,而且注解带的参数都是一样的)。第一影响性能,可能有些方法我不需要@Transactional注解,第二方法不同可能@Transactional注解需要配置的参数也不同,比如有一个方法只是做查询操作,那咱们可能需要配置Transactional注解的readOnly参数。所以强烈建议@Transactional注解直接添加的需要的方法上。

    2.3.2 @Transactional 注解必须添加在public方法上,private、protected方法上是无效的

           在使用@Transactional 的时候一定要记住,在private,protected方法上添加@Transactional 注解不会有任何效果。相当于没加一样。即使外部能调到protected的方法也无效。和没有添加@Transactional一样。

    2.3.3 函数之间相互调用

           关于有@Transactional的函数之间调用,会产生什么情况。这里咱们通过几个例子来说明。

    2.3.3.1 同一个类中函数相互调用

           同一个类AClass中,有两个函数aFunction、aInnerFunction。aFunction调用aInnerFunction。而且aFunction函数会被外部调用。

    情况0: aFunction添加了@Transactional注解,aInnerFunction函数没有添加。aInnerFunction抛异常。

     

    public class AClass {
    
        @Transactional(rollbackFor = Exception.class)
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            aInnerFunction(); // 调用内部没有添加@Transactional注解的函数
        }
    
        private void aInnerFunction() {
            //todo: 操作数据B(做了增,删,改 操作)
            throw new RuntimeException("函数执行有异常!");
        }
    
    }
    

           结果:两个函数操作的数据都会回滚。

    情况1:两个函数都添加了@Transactional注解。aInnerFunction抛异常。

     

    public class AClass {
    
        @Transactional(rollbackFor = Exception.class)
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            aInnerFunction(); // 调用内部没有添加@Transactional注解的函数
        }
    
        @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
        private void aInnerFunction() {
            //todo: 操作数据B(做了增,删,改 操作)
            throw new RuntimeException("函数执行有异常!");
        }
    
    }
    

           结果:同第一种情况一样,两个函数对数据库操作都会回滚。因为同一个类中函数相互调用的时候,内部函数添加@Transactional注解无效。@Transactional注解只有外部调用才有效。

    情况2: aFunction不添加注解,aInnerFunction添加注解。aInnerFunction抛异常。

     

    public class AClass {
    
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            aInnerFunction(); // 调用内部没有添加@Transactional注解的函数
        }
    
        @Transactional(rollbackFor = Exception.class)
        protected void aInnerFunction() {
            //todo: 操作数据B(做了增,删,改 操作)
            throw new RuntimeException("函数执行有异常!");
        }
    
    }
    

           结果:两个函数对数据库的操作都不会回滚。因为内部函数@Transactional注解添加和没添加一样。

    情况3:aFunction添加了@Transactional注解,aInnerFunction函数没有添加。aInnerFunction抛异常,不过在aFunction里面把异常抓出来了。

     

    public class AClass {
    
        @Transactional(rollbackFor = Exception.class)
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            try {
                aInnerFunction(); // 调用内部没有添加@Transactional注解的函数
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private void aInnerFunction() {
            //todo: 操作数据B(做了增,删,改 操作)
            throw new RuntimeException("函数执行有异常!");
        }
    
    }
    

           结果:两个函数里面的数据库操作都成功。事务回滚的动作发生在当有@Transactional注解函数有对应异常抛出时才会回滚。(当然了要看你添加的@Transactional注解有没有效)。

    2.3.3.1. 不同类中函数相互调用

           两个类AClass、BClass。AClass类有aFunction、BClass类有bFunction。AClass类aFunction调用BClass类bFunction。最终会在外部调用AClass类的aFunction。

    情况0:aFunction添加注解,bFunction不添加注解。bFunction抛异常。

     

    @Service()
    public class AClass {
    
        private BClass bClass;
    
        @Autowired
        public void setbClass(BClass bClass) {
            this.bClass = bClass;
        }
    
        @Transactional(rollbackFor = Exception.class)
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            bClass.bFunction();
        }
    
    }
    
    @Service()
    public class BClass {
    
        public void bFunction() {
            //todo: 数据库操作A(增,删,该)
            throw new RuntimeException("函数执行有异常!");
        }
    }
    

           结果:两个函数对数据库的操作都回滚了。

    情况1:aFunction、bFunction两个函数都添加注解,bFunction抛异常。

     

    @Service()
    public class AClass {
    
        private BClass bClass;
    
        @Autowired
        public void setbClass(BClass bClass) {
            this.bClass = bClass;
        }
    
        @Transactional(rollbackFor = Exception.class)
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            bClass.bFunction();
        }
    
    }
    
    @Service()
    public class BClass {
    
        @Transactional(rollbackFor = Exception.class)
        public void bFunction() {
            //todo: 数据库操作A(增,删,该)
            throw new RuntimeException("函数执行有异常!");
        }
    }
    

           结果:两个函数对数据库的操作都回滚了。两个函数里面用的还是同一个事务。这种情况下,你可以认为事务rollback了两次。两个函数都有异常。

    情况2:aFunction、bFunction两个函数都添加注解,bFunction抛异常。aFunction抓出异常。

     

    @Service()
    public class AClass {
    
        private BClass bClass;
    
        @Autowired
        public void setbClass(BClass bClass) {
            this.bClass = bClass;
        }
    
        @Transactional(rollbackFor = Exception.class)
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            try {
                bClass.bFunction();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }
    
    @Service()
    public class BClass {
    
        @Transactional(rollbackFor = Exception.class)
        public void bFunction() {
            //todo: 数据库操作A(增,删,该)
            throw new RuntimeException("函数执行有异常!");
        }
    }
    

           结果:两个函数数据库操作都没成功。而且还抛异常了。org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only。看打印出来的解释也很好理解把。咱们也可以这么理解,两个函数用的是同一个事务。bFunction函数抛了异常,调了事务的rollback函数。事务被标记了只能rollback了。程序继续执行,aFunction函数里面把异常给抓出来了,这个时候aFunction函数没有抛出异常,既然你没有异常那事务就需要提交,会调事务的commit函数。而之前已经标记了事务只能rollback-only(以为是同一个事务)。直接就抛异常了,不让调了。

    情况3:aFunction、bFunction两个函数都添加注解,bFunction抛异常。aFunction抓出异常。这里要注意bFunction函数@Transactional注解我们是有变化的,加了一个参数propagation = Propagation.REQUIRES_NEW,控制事务的传播行为。表明是一个新的事务。其实咱们情况3就是来解决情况2的问题的。

     

    @Service()
    public class AClass {
    
        private BClass bClass;
    
        @Autowired
        public void setbClass(BClass bClass) {
            this.bClass = bClass;
        }
    
        @Transactional(rollbackFor = Exception.class)
        public void aFunction() {
            //todo: 数据库操作A(增,删,该)
            try {
                bClass.bFunction();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }
    
    @Service()
    public class BClass {
    
        @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
        public void bFunction() {
            //todo: 数据库操作A(增,删,该)
            throw new RuntimeException("函数执行有异常!");
        }
    }
    

           结果:bFunction函数里面的操作回滚了,aFunction里面的操作成功了。有了前面情况2的理解。这种情况也很好解释。两个函数不是同一个事务了。


           关于@Transactional注解的使用,就说这么些。最后做几点总结:

    1. 要知道@Transactional注解里面每个属性的含义。@Transactional注解属性就是来控制事务属性的。通过这些属性来生成事务。

    2. 要明确我们添加的@Transactional注解会不会起作用。@Transactional注解在外部调用的函数上才有效果,内部调用的函数添加无效,要切记。这是由AOP的特性决定的。

    3. 要明确事务的作用范围,有@Transactional的函数调用有@Transactional的函数的时候,进入第二个函数的时候是新的事务,还是沿用之前的事务。稍不注意就会抛UnexpectedRollbackException异常。

    展开全文
  • 文章目录 1.美图 2. 源码 3.@Transactional 注解的属性信息 4.... 案例 6.1 基于tx标签的声明式事物 参考:基于tx标签的声明式事物 6.2 基于@Transactional注解的声明式事物 参考:基于@Transactional注解的声明式事物

    1.美图

    在这里插入图片描述

    2. 源码

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    展开全文
  • 假设,如果每一个service只会对应的更新他所对应的这张表,下面这三个方法上面加不加@Transactional效果都是一样的。不会对最终的结果产生影响。 Pubic void updateA(){ //只进行更新A表的操作 }...
  • @Transactional注解怎么使用

    千次阅读 2020-03-13 00:32:21
    @Transactional注解使用: 1、在方法或者类上都可以添加,如果在类上添加,则此类中的所有方法都会执行事务,不推荐,因为可能后续接手开发的小伙伴添加方法的时候根本不需要执行事务; 2、触发事务回滚有两种...
  • 引言@Transactional注解哪些场景下会失效,一时语塞致使面试失败。所以今天简单的和大家分享一下@Transactional相关的知识...使用@Transactional注解时需要注意许多的细节,不然你会发现@Transactional总是莫名其妙...
  • 前言 事务管理是应用系统开发中必不可少的...声明式事务管理使业务代码逻辑不受污染, 因此在实际使用中声明式事务用的比较多。声明式事务有两种方式,一种是在配置文件(xml)中做相关的事务规则声明,另一种是基于...
  • Spring Boot 中使用 @Transactional 注解配置事务管理

    万次阅读 多人点赞 2017-11-29 21:15:06
    事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编程式和声明式的两种方式...声明式事务管理使业务代码逻辑不受污染, 因此在实际使用中声明式事务用的比较多。
  • 我在@service下面加个@Transactional 注解就不能注册到zookeeper 上面去,不加就没事,我有点不清楚原因,网上说是spring 事务底层是采用了aop ,用的是动态代理,然后发布不上去,但我还是搞不清楚是怎么回事
  • @Transactional如果在一个方法上面添加@Transactional注解 查看postgresql数据库当前的事务隔离级别: @Transactional public void updateData(){  aService.updateA();//更新A表  bService.updateB...
  • @Modifying注解和@Transactional注解

    千次阅读 2020-01-11 20:56:30
    JPA中自定义的插入、更新、删除方法为什么要添加@Modifying注解和@Transactional注解?  前几天,有个同事在使用JPA的自定义SQL方法时,程序一直报异常,捣鼓了半天也没能解决,咨询我的时候,我看了一眼他的程序,...
  • 今天做系统开发的时候,遇到了一个BUG:@Transactional注解在同类方法调用中不生效 代码如下: /** * @description: 快递100接口服务类 * @date 2021/11/23 */ @Service public class SysExpressServiceImpl ...
  • 原来是我在使用@Transactional注解的时候,忘记使用“接口.方法”调用形式了。 在service方法里直接像调用普通方法一样去调用加了@Transactional注解方法。 丢人.jpg 写此博文,引以为戒! ...
  • 通过本篇学习,你将加深对@Transactional 注解以及所有的属性的理解,还可以学习到@Transactional 注解常见的失效场景【文章最后】。
  • 当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。...在@Transactional注解中如果不配置rollbackFor属性,那么事物只...
  • @Transactional注解使用

    千次阅读 2019-05-30 16:53:19
    在当前的项目当中可以利用@Transactiona注解来管理事务,然后将不必要的炒作进行回滚但是在操作的过程当中要注意以下这些地方: 这里面有几点需要大家留意: A. 一个功能是否要事务,必须纳入设计、编码考虑。不能...
  • 今天在学习spring的事务中遇到了一个小问题于@Transactional注解方法使用try catch()不回滚,发现解决方法如下。 在@Transactional的使用中,只有方法抛出了异常,事务才会进行回滚,而如果异常被try捕获,在...
  • 1,场景一,最常见的用法,在方法使用@Transactional 注解,事务正常起作用。无异常时正常插入数据库,有异常时数据不插入数据库,代码如下。 @Service public class ComeServiceImpl implements ComeService { ...
  • springboot默认不开启了事务,需要是要注解@EnableTransactionManagement 这注解有以属性proxyTargetClass,默认为false,表示使用jdk动态代理 如果设置为true,则表示使用cjlib做动态代理,可以联想jdk和cjlib使用...
  • 总结:springboot中在方法上(或类上)声明@Transactional注解即可在springboot中使用事务。 一。在Spring Boot中,当我们使用了spring-boot-starter-jdbc或spring-boot-starter-data-jpa依赖的时候,框 架会自动...
  • 使用@Transactional注解时需要注意许多的细节,不然你会发现@Transactional总是莫名其妙的就失效了。 一、事务 事务管理在系统开发中是不可缺少的一部分,Spring提供了很好事务管理机制,主要分为编程式事务和声明...
  • 引言@Transactional注解相信大家并不陌生,平时开发中很常用的一个注解,它能保证方法内多个数据库操作要么同时成功、要么同时失败。使用@Transactional注解时需要注意许多的细节,不然你会发现@Transactional总是...
  • spring使用@Transactional注解用法

    千次阅读 2019-01-18 15:45:59
     声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。此处就说明一下注解的用法: 事务注解方式: @Transact....
  • @Transactional - 属性之Propagation 两个常用的 REQUIRED(默认值):在有transaction状态下执行;如当前没有transaction,则创建新的...1、@Transactional 应用在非 public 修饰的方法上 如果Transaction
  • springboot的redis方法增加了@Transactional事务注解后再用watch方法就会报错,请问怎么在Transactional事务标记的方法内监测要设置的键值有没有被改变呢 @Transactional标记的redis操作方法内如果不使用watch,即使...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 53,750
精华内容 21,500
关键字:

@transactional注解使用方法

友情链接: 1.zip