@Transactional annotation failure scenarios

1, @ Transactional applications on non-public modification method

  If TransactionalNotes application in non publicon modified methods, Transactional will fail.

Here Insert Picture Description

 

  The reason is because the failure Spring AOP agent, as shown above TransactionInterceptor(transaction interceptor) to intercept target before and after performing the method, DynamicAdvisedInterceptor(CglibAopProxy inner classes) the intercept method or JdkDynamicAopProxyinvoke method indirectly calling AbstractFallbackTransactionAttributeSourcethe computeTransactionAttributemethod, obtaining Transactional Notes transaction configuration information.

protected TransactionAttribute computeTransactionAttribute(Method method,
    Class<?> targetClass) {
        // Don't allow no-public methods as required.
        if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
        return null;
}

  This method checks whether the target method modifiers public, not public property is not acquired @Transactional configuration information.

Note: protected, privateusing the modified method @Transactionalcomment, although the transaction is not valid, but there will be no error, this is our very little tolerance for error.

2, @ Transactional annotation attribute setting error propagation

  This failure is due to configuration errors, incorrect configuration if the following three propagation, roll back the transaction will not occur.

TransactionDefinition.PROPAGATION_SUPPORTS: If the current transaction exists, it is added to the transaction; if no transaction, non-transactional way places continue to run. TransactionDefinition.PROPAGATION_NOT_SUPPORTED: Running in non-transactional way, if the current transaction exists, put the current transaction pending. TransactionDefinition.PROPAGATION_NEVER: Running in non-transactional way, if the current transaction exists, an exception is thrown.

3, @ Transactional annotation property rollbackFor set incorrectly

  ollbackForYou can specify the type of transaction that can trigger abnormal rollback. Spring unchecked by default throws uncheckedan exception (inherited from RuntimeExceptionexception) or Erroronly roll back the transaction; other exception does not trigger a rollback transactions. If other types of exceptions thrown in the transaction, but they can expect Spring roll back the transaction, you need to specify rollbackFor property.

 

Here Insert Picture Description

 

// 希望自定义的异常可以进行回滚
@Transactional(propagation= Propagation.REQUIRED,rollbackFor= MyException.class

  If thrown in the target process is abnormal rollbackForabnormal subclass specified, the transaction will also be rolled back. Spring source code as follows:

private int getDepth(Class<?> exceptionClass, int depth) {
        if (exceptionClass.getName().contains(this.exceptionName)) {
            // Found it!
            return depth;
}
        // If we've gone as far as we can go and haven't found it...
        if (exceptionClass == Throwable.class) {
            return -1;
}
return getDepth(exceptionClass.getSuperclass(), depth + 1);
}

4, call the same class method, resulting in failure @Transactional

  It will not prevent the development of the same inside a class method calls, such as a class Test, which is a method of A, A and then call a method of the present class B (Method B whether public or private modifier is used), but no method A transaction statement notes, while the B methods. After calling the external method A, method B, the transaction is not functioning. This is also a place often make mistakes.

  Why would that happen? In fact, this is due to the use of Spring AOPagents caused, because only when the transaction method is called code outside the current class, will be made Springto manage the proxy object generated.

//@Transactional
    @GetMapping("/test")
    private Integer A() throws Exception {
        CityInfoDict cityInfoDict = new CityInfoDict();
        cityInfoDict.setCityName("2");
        /**
         * B 3 is inserted into the data field
         */
        this.insertB();
        /**
         * A data field 2 is inserted
         */
        int insert = cityInfoDictMapper.insert(cityInfoDict);

        return insert;
    }

    @Transactional()
    public Integer insertB() throws Exception {
        CityInfoDict cityInfoDict = new CityInfoDict();
        cityInfoDict.setCityName("3");
        cityInfoDict.setParentCityId(3);

        return cityInfoDictMapper.insert(cityInfoDict);
    }

5. The exception is your catch "eat" lead to failure @Transactional

  This situation is the most common form of failure @Transactional annotation scene,

    @Transactional
    private Integer A() throws Exception {
        int insert = 0;
        try {
            CityInfoDict cityInfoDict = new CityInfoDict();
            cityInfoDict.setCityName("2");
            cityInfoDict.setParentCityId(2);
            /**
             * A data field 2 is inserted
             */
            insert = cityInfoDictMapper.insert(cityInfoDict);
            /**
             * B 3 is inserted into the data field
             */
            b.insertB();
        } catch (Exception e) {
            e.printStackTrace ();
        }
    }
 

  If the internal B method throw an exception, but this time try catch A method of abnormal B method, and that the transaction can be rolled back to normal yet? Answer: No!

  It will throw an exception:org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

Because when ServiceBthrown an exception after ServiceBidentifying the current transaction needs rollback. But ServiceAbecause of you manually capture this exception handling, ServiceAthat the current transaction should be normal commit. At this point there have been inconsistent, that is, because of this, throw in front of UnexpectedRollbackExceptionan exception.

  springThe transaction is invoked before the beginning of the business method, business method was executed after the execution is completed commitor rollback, if the transaction depends on whether execution is thrown runtime异常. If you throw runtime exceptiondid not catch on to your business methods, then the transaction is rolled back.

In business methods generally do not need to catch an exception, if you must catch must be thrown out throw new RuntimeException(), or throw an exception specified annotation type @Transactional(rollbackFor=Exception.class), otherwise it will cause the transaction to fail, resulting in inconsistent data commit data, so sometimes try catch the rather superfluous.

6, the database engine does not support transactions

  The probability of this happening is not high, the transaction can take effect transactional database engine supports is the key. Commonly used MySQL database supports transactions using the default innodbengine. Once the database engine does not support switching to a transaction myisam, that transaction will fail fundamentally.

to sum up

@Transactional annotation may seem simple to use, but if it smattering of usage, or will step on a lot of the pit.

 

Guess you like

Origin www.cnblogs.com/luxianyu-s/p/12588419.html