Problems encountered in the project

Source: Internet
Author: User

Problems encountered in the project

I. Spring transaction problems

1. Description: a in service1 calls B, B calls c in service2, and c calls d in service3

Expectation: When d throws an exception (the SQL exception is thrown in my real project), d and c will be rolled back, while a and B will not be rolled back.

Test: Considering the self-tuning of Spring transactions and the spring transaction configuration under the cglib dynamic proxy. Added <aop: aspectj-autoproxy expose-proxy = "true" proxy-target-class = "true"/>.

Demo:

Custom exception:

Public class MyException extends SQLException {private static final long serialVersionUID = 1L; public MyException () {super ();} public MyException (String reason, String sqlState, int vendorCode, Throwable cause) {super (reason, sqlState, vendorCode, cause);} public MyException (String reason, String SQLState, int vendorCode) {super (reason, SQLState, vendorCode );} public MyException (String reason, String sqlState, Throwable cause) {super (reason, sqlState, cause);} public MyException (String reason, String SQLState) {super (reason, SQLState);} public MyException (String reason, Throwable cause) {super (reason, cause);} public MyException (String reason) {super (reason );} public MyException (Throwable cause) {super (cause );}}MyException. java

Dao:

@ Repositorypublic class TxDao {@ Autowired private JdbcTemplate jdbcTemplate; public void updateA () {String SQL = "update tx_test set a_field = 1 where id = 1"; jdbcTemplate. update (SQL);} public void updateB () {String SQL = "update tx_test set B _field = 1 where id = 1"; jdbcTemplate. update (SQL);} public void updateC () {String SQL = "update tx_test set c_field = 1 where id = 1"; jdbcTemplate. update (SQL);} public void updateD () {String SQL = "update tx_test set d_field = 1 where id = 1"; jdbcTemplate. update (SQL );}}TxDao. java

ABService:

@ Servicepublic class ABService {@ Autowired private TxDao txDao; @ Autowired private CService cService; @ Transactional public void aMethod () throws MyException {System. out. println ("aMethod"); txDao. updateA (); (ABService) AopContext. currentProxy ()). bMetod () ;}@ Transactional public void bMetod () throws MyException {System. out. println ("bMethod"); txDao. updateB (); cService. cMethod ();}}ABService. java

CService:

@ Servicepublic class CService {@ Autowired private TxDao txDao; @ Autowired private DService dService; @ Transactional (rollbackFor = MyException. class) public void cMethod () throws MyException {System. out. println ("cMethod... "); txDao. updateC (); dService. dMethod ();}}CService. java

DService:

@ Servicepublic class DService {@ Autowired private TxDao txDao; @ Transactional (rollbackFor = MyException. class) public void dMethod () throws MyException {System. out. println ("dMethod... "); txDao. updateD (); throw new MyException ();}}DService. java

Test code:

@ Testpublic void test () {ABService service = context. getBean (ABService. class); try {service. aMethod ();} catch (MyException e) {e. printStackTrace ();}}View Code

(1) test rollbackFor and noRollbackFor

Process:

A custom SQL exception MyException is inherited from SQLException. It is thrown from d and always pushed up.

Set the noRollbackFor attribute of @ Transactional of a and B to MyException. class, while the rollbackFor attribute of c and d is set to MyException. class.

Console output:

AMethod
BMethod
CMethod...
DMethod...

Database output:

Test results: all four methods, a, B, c, and d, are rolled back.

Cause search: It is found that the RollBackFor and noRollBackFor attributes of all transaction methods are read during container initialization.

For details, see org. springframework. transaction. interceptor. RollbackRuleAttribute # RollbackRuleAttribute (java. lang. Class <?>)

After a transaction method throws an exception, the entire transaction is rolled back, and it feels that it has nothing to do with the configuration of noRollBackFor.

For details, see org. springframework. transaction. interceptor. TransactionAspectSupport # invokeWithinTransaction.

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)            throws Throwable {// If the transaction attribute is null, the method is non-transactional.final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);final PlatformTransactionManager tm = determineTransactionManager(txAttr);final String joinpointIdentification = methodIdentification(method, targetClass);if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {    // Standard transaction demarcation with getTransaction and commit/rollback calls.    TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);    Object retVal = null;    try {        // This is an around advice: Invoke the next interceptor in the chain.        // This will normally result in a target object being invoked.        retVal = invocation.proceedWithInvocation();    }    catch (Throwable ex) {        // target invocation exception        completeTransactionAfterThrowing(txInfo, ex);        throw ex;    }    finally {        cleanupTransactionInfo(txInfo);    }    commitTransactionAfterReturning(txInfo);    return retVal;}

The target method will be removed from the marked red. if an exception is thrown by the target method, the catch block will be entered, and the code of the catch block will continue to be thrown up after the catch Block is executed. The catch Block can capture MyException.

Through breakpoint tracking, we can find that the completeTransactionAfterThrowing () method is rolled back. After rollback, we finally call the commitTransactionAfterReturning () method.

In this case, noRollBackFor does not even play any role. If any of you can see this and know the principle, please kindly advise. Thank you.

(2) Test the Propagation Behavior of Spring transactions.

Process: Change the Propagation Behavior of c to REQUIRES_NEW. At the same time, the exception thrown by d is handled in method c.

Console output:

AMethod
BMethod
CMethod...

Database output:

It is found that the d method is not executed at all. I don't quite understand it here.

The above two tests are provided. In fact, n methods are tested and there is no passing test. Wait until the understanding of spring transactions is deepened before parsing. Here we will talk about the final solution.

Solution:

1. manually control transactions

2. Service splitting. For example, a and B are independent transactions, and c and d are independent transactions.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.