1, @ Transactional applications on non-public modification method
If Transactional
Notes application in non public
on modified methods, Transactional will fail.
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 JdkDynamicAopProxy
invoke method indirectly calling AbstractFallbackTransactionAttributeSource
the computeTransactionAttribute
method, 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
, private
using the modified method @Transactional
comment, 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
ollbackFor
You can specify the type of transaction that can trigger abnormal rollback. Spring unchecked by default throws unchecked
an exception (inherited from RuntimeException
exception) or Error
only 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.
// 希望自定义的异常可以进行回滚
@Transactional(propagation= Propagation.REQUIRED,rollbackFor= MyException.class
If thrown in the target process is abnormal rollbackFor
abnormal 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 AOP
agents caused, because only when the transaction method is called code outside the current class, will be made Spring
to 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 ServiceB
thrown an exception after ServiceB
identifying the current transaction needs rollback
. But ServiceA
because of you manually capture this exception handling, ServiceA
that the current transaction should be normal commit
. At this point there have been inconsistent, that is, because of this, throw in front of UnexpectedRollbackException
an exception.
spring
The transaction is invoked before the beginning of the business method, business method was executed after the execution is completed commit
or rollback
, if the transaction depends on whether execution is thrown runtime异常
. If you throw runtime exception
did 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 innodb
engine. 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.