Spring Transaction Services Analog

    Affairs, is an abstract description of a set of operations, such as the database of a set of operations either all succeed, or all fail.
    Transaction has four characteristics:
        Atomicity (atomicity), Consistency (consistency), Isolation (isolation), Durability (persistent)
    Spring support for transactions is very powerful, but in essence, whether the transaction into effect depends on whether the underlying database support (MySQL's MyISAM engine does not support transactions),
At the same time, a transaction requires multiple operations on the same connection at. Handwriting analysis following a Demo Spring transaction underlying implementation.
 
  • Engineering structure
        
 
  • connection part
           Spring When a plurality of data sources DataSource, needed to obtain operation of the database through the Connection pipe DataSource.
            
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
public class ConnectionHolder {
     // map data stored in map source connection line
     private Map<DataSource, Connection> map=  new HashMap<DataSource, Connection>();
     // Get Connection according dataSource
     public Connection getConnectionByDataSource(DataSource datasource) throws SQLException{
          Connection connection = map.get(datasource);
          if(connection == null || connection.isClosed()){
              connection = datasource.getConnection();
              map.put(datasource, connection);
          }
          return connection;
     }
}
   
ConnectionHolder in the case of multi-threaded, map is not thread-safe, there may be used at the same time, another thread in the case of close links.
    Another idea is to use thread-safe ConcurrentHashMap. But we really need to do is to ensure that in the next threads, multiple operations in one transaction is to get a Connection, use ConcurrentHashMap does not guarantee
this problem.
    Therefore, considering the type of use ThreadLocal, ThreadLocal type is thread shared variable is a global variable thread. And ThreadLocal In the case of multiple threads, it will create a copy for each thread, the thread operations on ThreadLocal variables only affect the copies in this thread.
    
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
 
public class SingleThreadConnectionHolder {
    // ThreadLocal thread shared variables package Map
     private  static ThreadLocal<ConnectionHolder> threadLocal = new ThreadLocal<ConnectionHolder>();
     private static ConnectionHolder getConnectionHolder() {
          ConnectionHolder connectionHolder = threadLocal.get();
          if(connectionHolder == null) {
              connectionHolder = new ConnectionHolder();
              threadLocal.set(connectionHolder);
          }
          return connectionHolder;
     }
     public static Connection getConnection(DataSource dataSource) throws SQLException{
          return getConnectionHolder().getConnectionByDataSource(dataSource);
     }
}
        After ThreadLocal by encapsulation, a thread can be guaranteed a DataSource acquired Connection is unique.
 
  • manage part
 
        New TransactionManage, for transaction control
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import resource.connection.SingleThreadConnectionHolder;
public class TransactionManager {
     private DataSource dataSource;
     public TransactionManager(DataSource dataSource) {
          // TODO Auto-generated constructor stub
          this.dataSource = dataSource;
     }
     private Connection getConnection() throws SQLException{
          return SingleThreadConnectionHolder.getConnection(dataSource);
     }
     // open affairs
     public void start() throws SQLException{
          Connection connection = getConnection();
          connection.setAutoCommit(false);
     }
     // roll back the transaction
     public void rollback() {
          Connection connection = null;
          try {
              connection = getConnection();
              connection.rollback();
          }catch(SQLException e) {
              e.printStackTrace ();
          }
     }
     // close the transaction
     public void close() throws SQLException{
          Connection connection = getConnection();
          connection.commit();
          connection.setAutoCommit(false);
          connection.close();
     }
}
 
  • DAO layer, for operating the database links, including UserAcountDao, UserOrderDao
        Users purchase operation Dao
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import resource.connection.SingleThreadConnectionHolder;
public class UserAcountDao {
     private DataSource dataSource;
     public UserAcountDao(DataSource dataSource){
          this.dataSource = dataSource;
     }
     
     public void buy() throws SQLException {
          Connection connection = SingleThreadConnectionHolder.getConnection(dataSource);
          // business operations
          //。。。。
          System.out.println ( "current users to buy thread:". + Thread.currentThread () getName () +
                   "Use pipe (hashcode):" + connection.hashCode ());
     }
}
 
    Orders operation user Dao
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import resource.connection.SingleThreadConnectionHolder;
public class UserOrderDao {
     private DataSource dataSource;
     public UserOrderDao(DataSource dataSource){
          this.dataSource = dataSource;
     }
     
     public void order() throws SQLException {
          Connection connection = SingleThreadConnectionHolder.getConnection(dataSource);
          // business operations
          //。。。。
          System.out.println ( "current customer orders thread:". + Thread.currentThread () getName () +
                   "Use Management (hashcode):" + connection.hashCode ());
     }
}
 
  • service level, the user business operations
 
import javax.sql.DataSource;
import resource.dao.UserAcountDao;
import resource.dao.UserOrderDao;
import resource.manage.TransactionManager;
public class UserService {
     private UserAcountDao userAcountDao;
     private UserOrderDao userOrderDao;
     private TransactionManager transactionManager;
 
     public UserService(DataSource dataSource) {
          userAcountDao = new UserAcountDao(dataSource);
          userOrderDao = new UserOrderDao(dataSource);
          transactionManager = new TransactionManager(dataSource);
     }
     public void action() {
          try {
              // make a purchase, the next single operation
              transactionManager.start();
              userAcountDao.buy();
              userOrderDao.order();
              transactionManager.close();
          }catch(Exception e) {
              // exception occurs, the transaction is rolled back
              e.printStackTrace ();
              transactionManager.rollback();
          }
     }
}
         
  • Test test procedure
import resource.service.UserService;
public class TestTransaction {
     public static final String jdbcDriver = "com.mysql.jdbc.Driver";
     public static final String jdbcURL = "jdbc: mysql://localhost:3306/my_web?useSSL=false";
     public static final String jdbcUsername = "******"; // mysql user name
     public static final String jdbcPassword = "******";//密码
     
     public static void main(String[] args) {
          BasicDataSource basicDataSource = new BasicDataSource();
          basicDataSource.setDriverClassName(jdbcDriver);
          basicDataSource.setUsername(jdbcUsername);
          basicDataSource.setPassword(jdbcPassword);
          basicDataSource.setUrl(jdbcURL);
          final UserService userService = new UserService(basicDataSource);
 
          // simulated users concurrent requests
          for(int i = 0; i < 10; i++) {
              new Thread((Runnable)()-> {userService.action();}).start();
          }
          
          try {
              Thread.sleep(10000);
          }catch(InterruptedException e) {
              e.printStackTrace ();
          }
     }
}
 
       By testing procedure to simulate the user concurrent requests, a total of 10 threads, each thread calls DAO layer data operations. Operation results are as follows
 
 
Current users to buy thread: Thread-10, use the pipe (hashcode): 1671328438
Orders current user thread: Thread-10, use the pipe (hashcode): 1671328438
Current users to buy thread: Thread-5, use the pipe (hashcode): 1172249069
Orders current user thread: Thread-5, use the pipe (hashcode): 1172249069
Current users to buy thread: Thread-1, using the pipe (hashcode): 863698743
Orders current user thread: Thread-1, using the pipe (hashcode): 863698743
Current users to buy thread: Thread-7, using the pipe (hashcode): 1206124853
Orders current user thread: Thread-7, using the pipe (hashcode): 1206124853
Current users to buy thread: Thread-2, use the pipe (hashcode): 1861628772
Current users to buy thread: Thread-6, using the pipe (hashcode): 1394656535
Orders current user thread: Thread-2, use the pipe (hashcode): 1861628772
Orders current user thread: Thread-6, using the pipe (hashcode): 1394656535
Current users to buy thread: Thread-8, using the pipe (hashcode): 1883267477
Orders current user thread: Thread-8, using the pipe (hashcode): 1883267477
Current users to buy thread: Thread-9, use the pipe (hashcode): 1475410105
Orders current user thread: Thread-9, use the pipe (hashcode): 1475410105
Current users to buy thread: Thread-3, using the pipe (hashcode): 1472283137
Orders current user thread: Thread-3, using the pipe (hashcode): 1472283137
Current users to buy thread: Thread-4, using the pipe (hashcode): 678585609
Orders current user thread: Thread-4, using the pipe (hashcode): 678585609
 
The results can be seen, the same thread gets Connection pipe is the same, if the presence of a plurality of data sources, the same data source the same thread acquired duct is the same.
 
 
 
         

Guess you like

Origin www.cnblogs.com/ytcs8121/p/11331941.html