Spring transaction best practices

Posted by LAX on Wed, 16 Oct 2019 23:38:29 +0200

Conclusion:

1. Don't use @ Transaction (PS: if you use it, it's better to add it to the method of service layer instead of dao layer and Controller layer) for spring transactions. There will be some situations that cause Transaction rollback failure.

2. It is better to use code to realize transaction management

3. Do not perform RPC, HTTP requests and other operations in the transaction, to avoid the problem of time-consuming transaction caused by network jitter, which locks the database for a long time.

If it can't be avoided, then this is a problem of distributed transaction.

Code implementation transactions:

Create DataSource and use Ali's Druid

DruidDataSource dataSource = new DruidDataSource();

dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl(mysqlSettingParam.getUrl());
dataSource.setUsername(mysqlSettingParam.getUsername());
dataSource.setPassword(mysqlSettingParam.getPassword());
dataSource.setInitialSize(mysqlSettingParam.getInitialSize());
dataSource.setMaxActive(mysqlSettingParam.getMaxActive());
dataSource.setMinIdle(mysqlSettingParam.getMinIdle());
dataSource.setMaxWait(mysqlSettingParam.getMaxWait());
dataSource.setTestWhileIdle(mysqlSettingParam.getTestWhileIdle());
dataSource.setValidationQuery(mysqlSettingParam.getValidQuery());

Create transaction manager

import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Date;
import java.util.List;
    //Define transaction manager
    private PlatformTransactionManager txManager = null;

    @Autowired
    @Qualifier("DBMasterConfig.DataSource")
    DataSource dataSource;
    
    @Test
    public void insertChannel() throws Exception {
         AdChannelInfo adChannelInfo = new AdChannelInfo();
         adChannelInfo.setName("yangzhongyu");
         adChannelInfo.setChargePerson("yzy");
         adChannelInfo.setDesc("test");
         adChannelInfo.setCreatedAt(new Date());
         adChannelInfo.setUpatedAt(new Date());


        System.out.println("datasource="+dataSource);
        txManager = new DataSourceTransactionManager(dataSource);

        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
      //Define the isolation level of the transaction 
       def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
  //Define the propagation level of the transaction
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        //The transaction state class is obtained according to the transaction definition through the getTransaction method of PlatformTransactionManager. After obtaining the transaction state, Spring determines how to start the transaction according to the propagation behavior.
        TransactionStatus status = txManager.getTransaction(def);

        try {
            //Operation database
            adChannelService.insert(adChannelInfo);

            //Intentional abnormality
            int i = 1/0;

            txManager.commit(status);  //Commit the transaction bound in status, which must be placed at the end
        } catch (RuntimeException e) {
            txManager.rollback(status);  //RollBACK
            e.printStackTrace();
        }

    }

Implementation principle of transaction (ThreadLocal)

Topics: Programming Spring Database JDBC Java