java transaction learning and extension

Java transaction learning and extension

1. Java transaction

There are three types of Java transactions: JDBC transactions, JTA (Java Transaction API) transactions, and container transactions.

JDBC transaction

JDBC transactions are controlled using Connection objects. The JDBC Connection interface ( java.sql.Connection ) provides two transaction modes: automatic submission and manual submission.

java.sql.Connection 提供了以下控制事务的方法:
public void setAutoCommit(boolean) //设置java事务是否自动提交,true为自动提交,false则需要手动commit或rollback
public boolean getAutoCommit()//获取当前java事务的提交状态
public void commit()//提交事务
public void rollback()//回滚事务

Note: The transaction cycle is limited to the life cycle of Connection. A disadvantage of JDBC transactions is that the scope of the transaction is limited to one database connection. A JDBC transaction cannot span multiple databases.

Specific use:

//JDBC事务
public static void main(String[] args) throws SQLException, ClassNotFoundException {
    
    
        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3306/user";
        String user = "root";
        String password = "123456";
        Connection con = (Connection) DriverManager.getConnection(url, user, password);
        try {
    
    
            //取消自动提交
            //如果设成false,那就是JDBC不自动提交,需要手动的使用commit或者rollback来进行提交或者回滚数据.
            con.setAutoCommit(false);
            Statement stmt = (Statement) con.createStatement();
            //进行数据插入
            String sql = "insert into users(email,password) values('" + "[email protected]" + "','" + "jack" + "');";
            boolean flag = stmt.execute(sql);
            System.out.println(flag);
            //人为制造一个错误,结果就是数据库并没有插入这条数据,也就是数据发生了回滚
            //异常被捕获之后,就不在执行下面的语句,而是执行catch中的语句
            //如果没有异常,数据就会被提交到数据库
            System.out.println(1/0);
            //手动提交
            con.commit();
        } catch (Exception e) {
    
    
            //如果发生错误,就回滚
            con.rollback();
        } finally {
    
    
            con.close();
        }
    }
public int delete(int sID) {
    
    
  dbc = new DataBaseConnection();
  Connection con = dbc.getConnection();
  try {
    
    
   con.setAutoCommit(false);// 更改JDBC事务的默认提交方式
   dbc.executeUpdate("delete from xiao where ID=" + sID);
   dbc.executeUpdate("delete from xiao_content where ID=" + sID);
   dbc.executeUpdate("delete from xiao_affix where bylawid=" + sID);
   con.commit();//提交JDBC事务
   con.setAutoCommit(true);// 恢复JDBC事务的默认提交方式
   dbc.close();
   return 1;
  }
  catch (Exception exc) {
    
    
   con.rollBack();//回滚JDBC事务
   exc.printStackTrace();
   dbc.close();
   return -1;
  }
}

JDBC transaction isolation level:

JDBC defines five transaction isolation levels:

TRANSACTION_NONE indicates that transactions are not supported.

TRANSACTION_READ_UNCOMMITTED indicates that a transaction can see the changes of another transaction before committing. Such dirty reads, non-repeatable reads, and phantom reads are all allowed.

Dirty read: can read the updated data when the data is not committed

TRANSACTION_READ_COMMITTED indicates that reading uncommitted data is not allowed. This level still allows non-repeatable reads and phantom reads.

Non-repeatable read: When querying in a transaction, it is allowed to read the data before submission. After the data is submitted, the current query can read the data. The table is not locked when updating data

TRANSACTION_REPEATABLE_READ indicates that the transaction is guaranteed to be able to read the same data again without failure, but false reading still occurs.

Phantom read: Allows to read new data submitted by other transactions

TRANSACTION_SERIALIZABLE is the highest transaction level, which prevents dirty reads, non-repeatable reads, and phantom reads. When a query is performed in a transaction, any data modification to the query table is not allowed.

In JDBC, set the transaction isolation level through the following API

conn.setTransactionLevel(TRANSACTION_SERIALIZABLE) ;``int` `level = conn.getTransactionIsolation();

Save point (SavePoint):

JDBC defines the SavePoint interface, which provides a finer-grained transaction control mechanism. When a savepoint is set, you can rollback to the state at the savepoint instead of rolling back the entire transaction.

The setSavepoint and releaseSavepoint methods of the Connection interface can set and release savepoints.

Savepoint sp = conn.setSavepoint();``Conn.rollback(sp);``Conn.commit();  ``//回滚后必须要提交

Although the JDBC specification defines the above support behaviors for transactions, each JDBC driver and database vendor may have different support for transactions. If you set it arbitrarily in the program, you may not get the desired effect.

Advantages and disadvantages of JDBC:

  • 1. Long and repetitive
  • 2. Display Transaction Control
  • 3. Each step is not available
  • 4. Show handling checked exceptions

JDBC provides the most basic support for database transaction operations using Java. Through JDBC transactions, we can put multiple SQL statements into the same transaction to ensure its ACID characteristics. The main advantage of JDBC transactions is that the API is relatively simple, the most basic transaction operations can be realized, and the performance is relatively good . However, JDBC transactions have a limitation: a JDBC transaction cannot span multiple databases! so,If it involves multi-database operations or distributed scenarios, JDBC transactions are powerless.

2. JTA affairs (beginners can understand)

The full name of JTA is Java Transaction API, that is, Java Transaction API, explained in English:

Java Transaction API (JTA) specifies standard Java interfaces between a transaction manager and the parties involved in a distributed transaction system: the resource manager, the application server, and the transactional applications.

JTA is a high-level, implementation-independent, protocol-independent API that applications and application servers can use to access transactions.

JTA allows applications to perform distributed transactions - access and update data on two or more networked computer resources, which can be distributed across multiple databases. The JTA support of the JDBC driver greatly enhances data access capabilities.

The main interface of JTA:

Located in the javax.transaction package

a. UserTransaction interface: Allows the application to control the start, suspension, submission, rollback, etc. of the transaction. Called by a Java client program or EJB.
b. TransactionManager interface: used for the application server to manage transaction status
c. Transaction interface: used to execute related transaction operations
d. XAResource interface: used to coordinate the work of the transaction manager and resource manager in a distributed transaction environment
e, Xid Interface: Java mapping for transaction identifiers

Note: The first 3 interfaces are located in the Java EE version of the class library javaee.jar, which is not provided in Java SE! UserTransaction is a commonly used interface for programming. JTA only provides an interface, no specific implementation.

JTA needs to meet the conditions:

If you use JTA to delimit transactions, you need a JDBC driver that implements the javax.sql.XADataSource, javax.sql.XAConnection, and javax.sql.XAResource interfaces. A driver that implements these interfaces can participate in JTA transactions.

An XADataSource object is a factory for XAConnection objects. XAConnection is a JDBC connection that participates in a JTA transaction. To use JTA transactions, you must use XADataSource to generate a database connection, which is an XA connection.

The difference between XA connection (javax.sql.XAConnection) and non-XA (java.sql.Connection) connection is:

XA can participate in JTA transactions, and does not support automatic commit like JDBC .

Also, applications must not call java.sql.Connection.commit() or java.sql.Connection.rollback() on XA connections. Instead, applications should use UserTransaction.begin(), UserTransaction.commit(), and serTransaction.rollback().

Note: Only large databases such as Oracle, Sybase, DB2, and SQL Server support XA and distributed transactions. MySQL belongs to Non-XA.

Transaction Manager Model (TM):

The Java Transaction API allows you to manipulate distributed transactions in your application (Distributed Transaction). There is a set of methods in JTA that encapsulates traditional JDBC calls into a two-phase commit (Two-Phase-Commit) protocol.

In a heterogeneous environment, you will usually find a transaction manager (Transaction Manager), responsible for handling distributed transactions. (Actually, the transaction manager does a lot of the workload balancing.) So there are not only direct connections to the database, but also connections to the transaction manager. This is where JTA comes into play: JTA is the interface between a Java application and a Transaction Manager . The following diagram illustrates a typical environment with distributed transactions.

Due to the existence of the transaction manager (Transaction Manager), which is usually included in the application server (Application Server) , there is no longer a two-tier (Two-Tier) architecture. The traditional client/server (Client/Server) architecture has been replaced by a three-tier (Tree-Tier) architecture, which includes **** applications/clients, transaction managers (Transaction Manager)/application servers ( Application Server) and database server , and the database server is generally called XA Resource .

insert image description here

  1. A Java application that contains SQL and JTA calls.
  2. An application server (Application Server) that manages distributed transactions.
  3. A database that participates in distributed transactions.
  4. Java applications submit regular SQL statements and generic XA calls to the Application Server.
  5. Messages sent by the application are processed by the Application Server and sent to the database using SQL and database vendor-specific XA calls.

Typically, an application server (Application Server) provides a variety of services that applications can use. When talking about distributed transactions, the service is called XA Resource . Of course, before the application can use the XA Resource, the XA Resource must first be registered and configured in the application server.

Now, if you plan to use JTA in your application, you must modify your code to also communicate with the Application Server. This includes some additional method calls and specified error/exception handling

Distributed transaction:

Before talking about the XA specification, you must first understand the concept of Distributed Transaction Processing (DTP). Transaction, namely transaction, also known as transaction, refers to a program or program segment, on one or more resources, such as databases or files, to complete a collection of execution processes of certain functions.

Distributed transaction processing means that a transaction may involve multiple database operations. The key to distributed transaction processing is that there must be a way to know all the actions performed by the transaction anywhere, and the decision to commit or roll back the transaction must produce a unified result. (commit all or rollback all).

Distributed transaction processing model:

The X/Open organization (now the Open Group) defined the distributed transaction processing model.

**X/Open DTP model (1994) includes: ** Application program (AP), transaction manager (TM), resource manager (RM), communication resource manager (CRM) four parts . Generally, a common transaction manager (TM) is a transaction middleware, a common resource manager (RM) is a database, and a common communication resource manager (CRM) is a message middleware.

Usually, the transaction processing inside a database, such as the operation on multiple tables, is regarded as a local transaction. The object of database transaction processing is a local transaction, while the object of distributed transaction processing is a global transaction.

The so-called global transaction means that in a distributed transaction processing environment, multiple databases may need to jointly complete a job, which is a global transaction. For example, several different databases may be updated in one transaction. Operations on the database occur all over the system, but must all be committed or rolled back. At this time, the submission of a database's internal operations depends not only on the success of its own operations, but also on the success of other database operations related to the global transaction. If any operation of any database fails, all participants in this transaction All operations done by the database must be rolled back.

In general, a certain database cannot know what other databases are doing. Therefore, in a DTP environment, transaction middleware is necessary, which notifies and coordinates the submission or rollback of related databases. A database only maps its own (recoverable) operations into global transactions.

XA is the interface specification (that is, the interface function) between the transaction middleware and the database defined by X/Open DTP . It is used by transaction middleware to notify the database of transaction start, end, commit, rollback, etc. XA interface functions are provided by database vendors.

The XA protocol includes two sets of functions, those starting with xa_ and those starting with ax_.

The following functions enable transaction managers to perform operations on resource managers:

1) xa_open, xa_close: establish and close the connection with the resource manager.

2) xa_start, xa_end: start and end a local transaction.

3) xa_prepare, xa_commit, xa_rollback: pre-submit, commit and roll back a local transaction.

4) xa_recover: Roll back a pre-committed transaction.

5) The function starting with ax_ enables the resource manager to dynamically register in the transaction manager and operate on XID (TRANSACTION IDS).

6) ax_reg, ax_unreg; allow a resource manager to dynamically register or unregister in a TMS (TRANSACTION MANAGER SERVER).

JTA can handle any resource that provides an XA-compliant interface. Including: JDBC connections, databases, JMS, business objects, and more.

XA and two-phase commit protocol (Two-Phase-Commit):

Usually, the transaction middleware and the database use the XA interface specification to complete a global transaction using two-phase commit. The basis of the XA specification is the two-phase commit protocol.

Phase 1: The transaction middleware requests all relevant databases to prepare to submit (pre-commit) their respective transaction branches to confirm whether all relevant databases can submit their respective transaction branches.

When a database receives the pre-commit, if it can submit its own transaction branch, it will record the operations it has done in the transaction branch, and give the transaction middleware a reply that agrees to the submission. At this time, the database will You can no longer add any operations to this transaction branch, but at this time the database has not actually committed the transaction, and the operation of the database on shared resources has not been released (in a locked state). If the database cannot submit its own transaction branch for some reason, it will roll back all its operations, release the lock on the shared resource, and return a failure response to the transaction middleware.

The second stage: The transaction middleware reviews the pre-commit results returned by all databases. If all databases can be submitted, the transaction middleware will require all databases to make a formal submission, so that the global transaction is submitted. And if any database pre-commit fails, the transaction middleware will require all other databases to roll back their operations, so that the global transaction is rolled back .

Taking a global transaction as an example, the AP first informs the transaction middleware to start a global transaction, and the transaction middleware notifies the database to start the transaction through the XA interface function, and then the AP can operate on the resources managed by the database, and the database system records all the transactions on the local resources. operate. After the operation is completed, the transaction middleware notifies the database of the completion of the operation through the XA interface function. The transaction middleware is responsible for recording which databases (transaction branches) AP has operated. The AP notifies the transaction middleware to submit the global transaction according to the situation. The transaction middleware will request each database to pre-submit through the XA interface function. After all databases return successfully, each database will be required to make a formal submission. At this time, a global transaction ends.

For applications, the biggest advantage of the XA specification is that the integrity of transactions is controlled by the transaction middleware and database through the XA interface. AP only needs to pay attention to the processing of application logic with the database, and does not need to care too much about the integrity of transactions. Application design and development will simplify a lot.

Specifically, if there is no transaction middleware, the application system needs to directly notify the database to start, end, and commit transactions within the program. When an abnormal situation occurs, a special program must perform reverse operations on the database to complete the rollback . If it is a global transaction with many transaction branches, the situation will become extremely complicated when rolling back. With the XA interface, the commit of the global transaction is controlled by the transaction middleware. The application only needs to notify the transaction middleware to commit or roll back the transaction, and can control the commit or rollback of the entire transaction (which may involve multiple remote databases). Fuck, the application doesn't have to think about flushing logic at all.

In a global transaction involving multiple databases, in order to ensure the integrity of the global transaction, it is necessary for the transaction middleware to control the database to do two-phase commit. However, the typical two-phase commit takes a relatively long time for the database from the beginning to the end of the transaction (commit or rollback). will release. Therefore, using a typical two-phase commit will take up relatively more resources, and the situation will be even more serious when the network conditions are not very good, such as low-speed network and frequent network bumps.

When a global transaction involves only one database, there is an optimization called one-phase commit. When the AP notifies the transaction middleware to submit the transaction, the transaction middleware directly asks the database to submit the transaction, omitting the first stage of the two-phase commit, which can shorten the time for processing a transaction and improve the efficiency of transaction processing. As a special case of two-phase commit, one-phase commit is as standard as two-phase commit.

Two-phase commit

In an XA implementation, the transaction manager commits the distributed branches of a global transaction by using a two-phase commit protocol.

  1. In phase one, the transaction manager directs each resource manager to prepare to commit, which is to verify and guarantee it can commit its respective branch of the global transaction. If a resource manager cannot commit its branch, the transaction manager rolls back the entire transaction in phase two.
  2. In phase two, the transaction manager either directs each resource manager to commit its branch or, if a resource manager reported it was unable to commit in phase one, rolls back the global transaction.

Note the following optimizations:

  • If a global transaction is determined by the transaction manager to have involved only one branch, it skips phase one and commits the transaction in phase two.
  • If a global transaction branch is read-only, where it does not generate any transaction log records, the transaction manager commits the branch in phase one and skips phase two for that branch.

Note:

The transaction manager considers the global transaction committed if and only if all branches successfully commit.

Two-phase commit details:

In a distributed system, a transaction often includes the activities of multiple participants. The atomicity of activities on a single participant can be guaranteed, while the atomicity guarantee between multiple participants needs to be achieved through two-phase commit. Two-phase commit is the key to the implementation of distributed transactions.

Obviously, the two-phase commit guarantees the atomicity of distributed transactions, and these sub-transactions are either done or not done. The consistency of the database is realized by the integrity constraints of the database, and the persistence is realized by the commit log, not by the two-phase commit. As for how to ensure isolation in two-phase commit, you can refer to the specific implementation of two-phase commit in Large-scale Incremental Processing Using Distributed Transactions and Notifications.

The two-phase commit process involves a coordinator and participants. The coordinator can be regarded as the initiator of the transaction and also a participant of the transaction. For a distributed transaction, a transaction involves multiple participants. The specific two-phase commit process is as follows:

The first stage:

First, the coordinator writes a log record in the log of its own node, and then all participants send a message prepare T to ask these participants (including themselves) whether they can submit this transaction;

After receiving the prepare T message, the participant will pre-process the transaction according to its own situation. If the participant can submit the transaction, it will write the log to disk and return a ready T message to the coordinator. At the same time It enters the pre-commit state; if the transaction cannot be committed, it will record the log and return a not commit T message to the coordinator, and at the same time undo the database changes made on itself;

Participants are able to delay sending responses, but eventually they need to be sent.

second stage:

The coordinator will collect the opinions of all participants. If it receives the not commit T message from the participant, it indicates that the transaction cannot be committed. The coordinator will record Abort T in the log and send an Abort to all participants. T information, allowing all participants to cancel all pre-operations on themselves;

If the coordinator receives prepare T (ready T) information from all participants, the coordinator will write the Commit T log to disk, and send a Commit T message to all participants to commit the transaction. If the coordinator has not received the information sent by a participant for a long time, it will be considered that the participant has sent a VOTE_ABORT message, thereby canceling the execution of the transaction.

After the participant receives the Abort T message from the coordinator, the participant will terminate the commit and record Abort T in the log; if the participant receives the Commit T message, it will commit the transaction and write Record.

Under normal circumstances, the two-phase commit mechanism can work well. When a participant goes down during the transaction, after he restarts, he can ask other participants or coordinators to know whether the transaction has been committed. No. Of course, the premise of all this is that each participant will write in the log in advance when performing each step of operation.

The only dilemma that two-phase commit cannot solve is: when the coordinator goes down after sending the commit T message, and the only participant who received this command also goes down, the transaction is in an unknown state at this time , no one knows whether the transaction is committed or not, so the intervention of the database administrator is required to prevent the database from entering an inconsistent state. Of course, if there is a premise that all nodes or network abnormalities will eventually recover, then this problem will not exist, the coordinator and participants will eventually restart, and other nodes will eventually receive the message of commit T.

The database log guarantees the atomicity and durability of transaction execution. The log types can be divided into redo log, undo log, and undo/redo log. For the specific introduction of these log forms, please refer to: http://nosql-wiki.org/foswiki/bin/view/Main/TransactonLog

3. Spring container transactions (beginners mainly understand @Transactional annotations)

There are many details in the implementation of Spring transaction management. If you have a general understanding of the entire interface framework, it will be very helpful for us to understand the transaction. Let's understand Spring's specific strategy for implementing transactions by explaining Spring's transaction interface.

Interfaces and connections involved in Spring transaction management:

insert image description here

Spring does not directly manage transactions, but provides a variety of transaction managers. They delegate the responsibility of transaction management to the transactions of related platform frameworks provided by persistence mechanisms such as Hibernate or JTA. The interface of the Spring transaction manager is org.springframework.transaction.PlatformTransactionManager. Through this interface, Spring provides corresponding transaction managers for various platforms such as JDBC and Hibernate, but the specific implementation is the business of each platform.

Public interface PlatformTransactionManager{
    
      
       // 由TransactionDefinition得到TransactionStatus对象
       TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
    // 提交
       Void commit(TransactionStatus status) throws TransactionException;  
       // 回滚
       Void rollback(TransactionStatus status) throws TransactionException;  
}

Definition of basic transaction attributes:

The transaction manager interface PlatformTransactionManager obtains transactions through the getTransaction(TransactionDefinition definition) method. The parameter in this method is the TransactionDefinition class, which defines some basic transaction attributes.
Transaction attributes can be understood as some basic configurations of transactions, describing how transaction strategies are applied to methods.

Transaction attributes include 5 aspects:

Propagation behavior, isolation rules, rollback rules, transaction timeout, read-only

TransactionDefinition:

public interface TransactionDefinition {
    
    
    int getPropagationBehavior(); // 返回事务的传播行为
    int getIsolationLevel(); // 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
    int getTimeout();  // 返回事务必须在多少秒内完成
    boolean isReadOnly(); // 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的
}

7 communication behaviors:

  • **PROPAGATION_REQUIRED:** If there is no current transaction, create a new transaction, if there is already a transaction, join this transaction. This is the most common choice.
  • **PROPAGATION_SUPPORTS:** supports the current transaction, if there is no current transaction, it will be executed in a non-transactional manner.
  • **PROPAGATION_MANDATORY: **Support current transaction, if there is no current transaction, an exception will be thrown.
  • **PROPAGATION_REQUIRES_NEW:** Create a new transaction, if there is a current transaction, suspend the current transaction.
  • **PROPAGATION_NOT_SUPPORTED:** Perform operations in a non-transactional manner. If there is a current transaction, suspend the current transaction.
  • **PROPAGATION_NEVER:** Executed in a non-transactional manner, if there is a current transaction, an exception is thrown.

Although there are 7 types, the first type REQUIRED and the fourth type REQUIRES_NEW are commonly used

Five isolation levels:

  • **ISOLATION_DEFAULT:** This is the default isolation level of PlatfromTransactionManager, using the default transaction isolation level of the database. The other four correspond to the isolation level of JDBC;
  • **ISOLATION_READ_UNCOMMITTED:** This is the lowest isolation level of the transaction, which allows another transaction to see the uncommitted data of this transaction. This isolation level produces dirty reads, non-repeatable reads, and phantom reads.
  • **ISOLATION_READ_COMMITTED: **Ensure that the data modified by a transaction can only be read by another transaction after it is committed. Another transaction cannot read uncommitted data of this transaction. This transaction isolation level can avoid dirty reads, but non-repeatable reads and phantom reads may occur.
  • **ISOLATION_REPEATABLE_READ:** This transaction isolation level can prevent dirty reads and non-repeatable reads. However, phantom reads may occur. In addition to ensuring that one transaction cannot read uncommitted data of another transaction, it also ensures that the following situations are avoided (non-repeatable read).
  • **ISOLATION_SERIALIZABLE:** This is the most expensive but most reliable transaction isolation level. Transactions are processed as sequential execution.

In addition to preventing dirty reads and non-repeatable reads, phantom reads are also avoided.

The attributes of the transaction can be configured through annotations or configuration files:

Annotation method: @Transactional

step:

  1. Add annotations to the startup main class: @EnableTransactionManagement to enable annotation transaction management , which is equivalent to the <tx:annotation-driven /> annotation driver previously configured in xml.
  2. Add the @Transactional(rollbackFor = Exception.class) annotation on the class or method that requires transactions, in which you can configure the required granularity:
  3. Logically, if manual rollback is required, add the following code TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

usage

  • @**Transactional can act on interfaces, interface methods, classes, and class methods. **When used on a class, all public methods of the class will have transaction attributes of this type. At the same time, we can also use this annotation at the method level to override the class-level definition.

  • Although the @Transactional annotation can act on interfaces, interface methods, classes, and class methods, Spring recommends not to use this annotation on interfaces or interface methods, because it will only take effect when using interface-based proxies.

  • In addition, the ==@Transactional annotation should only be applied to public methods, which is determined by the nature of Spring AOP. == If you use the @Transactional annotation on a method with protected, private or default visibility, this will be ignored and no exception will be thrown.

  • By default, only method calls from the outside will be captured by the AOP proxy, that is, calling other methods inside the class will not cause transactional behavior, even if the called method is modified with the @Transactional annotation.

@Transactional(readOnly = true)
public class DefaultFooService implements FooService {
    
    

  public Foo getFoo(String fooName) {
    
    
    // do something
  }

  // these settings have precedence for this method
  //方法上注解属性会覆盖类注解上的相同属性
  @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
  public void updateFoo(Foo foo) {
    
    
    // do something
  }
}

Guess you like

Origin blog.csdn.net/Ghoul___/article/details/126522604