1 Series Catalogue
- The Distributed Transaction series (opening) raises questions and research processes
- Distributed Transaction Series (1.1) Spring transaction manager Platformtransactionmanager Source analysis
2 JDBC Transaction2.1 Examples
public void save(User user) throws SQLException{ Connection conn=jdbcDao.getConnection(); conn.setAutoCommit(false); try { PreparedStatement ps=conn.prepareStatement("insert into user(name,age) value(?,?)"); ps.setString(1,user.getName()); ps.setInt(2,user.getAge()); ps.execute(); conn.commit(); } catch (Exception e) { e.printStackTrace(); conn.rollback(); }finally{ conn.close(); }}
2.2 Analysis
How to use Transactions
Set Autocommit to False, which is Conn.setautocommit (false), and then manually to Conn.commit (), or conn.rollback ().
An important consciousness
Conn.commit (); Conn.rollback () These are transaction codes, other code that executes SQL belongs to the business code
Only when the transaction code and the business code use the same connection, the rollback and the commit of the transaction can execute properly, so if we are to implement the separation of the transaction code and the business code, we must ensure that they are using the same connection.
Who is performing the transaction
As we can see, the transaction can be performed by manipulating the connection connection, which does not mean that connection has a transactional function, but rather uses the transaction function of the database itself, connection only to pass some commands such as commit, rollback to the database
2.3 Problems that exist
- 1 business code is nested in the Try Catch transaction template code
2 when there are multiple business logic like save (user user), there is no guarantee that their atomicity
login(user);save(user);
Both of these business logic are similar code, get the connection connection, and then execute the SQL statement. There is no guarantee that they are atomic because they are not using the same connection, not within the same transaction.
3 Hibernate's Business3.1 Examples
public void save(User user){ Session session=hibernateDao.openSession(); Transaction tx=null; try { tx=session.beginTransaction(); session.save(user); tx.commit(); } catch (Exception e) { if(tx!=null){ tx.rollback(); } }finally{ session.close(); }}
3.2 Analysis
Separation of transaction functions and business functions
In a JDBC transaction, connection burdens two aspects of functionality, transactional functionality, and the ability to execute SQL. The transaction here is Hibernate's own definition of the transaction, Hibernate is the function of the two separate, the transaction function to the transaction, make the responsibility more clear division of labor.
The principle of the transaction
In fact, the session, transaction internal will have a same connection, so that the business code and transaction code to use the same connection, The rollback of the transaction transaction is done by the internal connection, as follows:
- Start of transaction, set Autocommit to False
- Commit of the transaction, submitted by connection's Commit method
Operations such as rollback of transactions, no longer enumerated
4 The overall interface design of spring transaction function
Because of the different ways in which the transaction functions are implemented, spring has a unified abstraction that forms the Platformtransactionmanager transaction manager interface, and the commit, rollback, etc. of the transaction are all given to it. Spring's transaction system is also carried out on the Platformtransactionmanager transaction manager interface, so first understand the next Platformtransactionmanager transaction manager.
4.1 Overall interface design for transactional functions
Let's take a look at the three main interfaces
Platformtransactionmanager: Transaction manager
Transactiondefinition: Some basic information about a transaction, such as time-outs, isolation levels, propagation properties, and so on
Transactionstatus: Some state information for a transaction, such as whether it is a new transaction, whether it has been marked as rollback
Take a look at how Platformtransactionmanager operates the transaction:
public interface PlatformTransactionManager { //根据事务定义TransactionDefinition,获取事务 TransactionStatus getTransaction(TransactionDefinition definition); //提交事务 void commit(TransactionStatus status); //回滚事务 void rollback(TransactionStatus status);}
4.2 Interface corresponding to the implementation4.2.1 Transaction Definition Interface Transactiondefinition
- Above the red line are some constant definitions (the isolation level of the transaction and the propagation properties of the transaction, specifically no longer say, a whole bunch of online)
- The definition of a transaction consists of the isolation level of the transaction, the propagation property of the transaction, the time-out setting, whether it is read-only
To understand the place:
The isolation level of a transaction is the transaction capability of the database itself, but the propagation properties of a transaction are the features that spring itself provides for us, and the notion that a database transaction does not have a transactional propagate property.
Implementation of the interface Defaulttransactiondefinition: the default transaction definition
public class DefaultTransactionDefinition implements TransactionDefinition, Serializable { private int propagationBehavior = PROPAGATION_REQUIRED; private int isolationLevel = ISOLATION_DEFAULT; private int timeout = TIMEOUT_DEFAULT; private boolean readOnly = false; //略}
- The propagation property of a transaction is propagation_required, that is, when there is no transaction at present, create one, if any, using the current transaction
- The isolation level of the transaction is based on the default isolation level of the underlying database
- The timeout takes the default time-out for the underlying database
- is read-only as false
4.2.2 Transaction Interface Definition Transactionstatus
The Save Points feature in the connection connection is first drawn:
//创建一个保存点conn.setSavepoint(name);//回滚到某个保存点conn.rollback(savepoint);//释放某个保存点conn.releaseSavepoint(savepoint);
Transactionstatus it inherits the Savepointmanager interface, Savepointmanager is the encapsulation of the above savepoint function in the transaction, as follows:
public interface SavepointManager { Object createSavepoint() throws TransactionException; void rollbackToSavepoint(Object savepoint) throws TransactionException; void releaseSavepoint(Object savepoint) throws TransactionException;}
Spring uses the SavePoint feature to implement nested functions of transactions. Details are explained later.
The transactionstatus itself is more stored with some state information about the transaction:
- Whether it's a new thing
- Do you have a savepoint?
- Whether it has been marked as rollback
The common Transactionstatus interface is implemented as Defaulttransactionstatus:
The JDBC transaction is currently implemented through connection, and Hibernate is implemented by its own definition of transaction, so the transactions are different for each family, so spring can only use object Transaction in the form of a transaction, the rollback and the submission of the transaction are ultimately delegated to the object transaction above.
The role of Object transaction is to commit a ROLLBACK transaction, and this transaction choice might look like this:
- Datasourcetransactionobject
- Hibernatetransactionobject
- Jpatransactionobject (later in detail)
The details were as follows:
For Datasourcetransactionobject:
We used the DataSource to get the connection, and to implement the transaction function, it was necessary to use connection, so there must be a connection in it to perform the operation of the transaction.
There is a connectionholder in Datasourcetransactionobject, which encapsulates a connection.
For Hibernatetransactionobject:
We use Hibenrate, which is what we need to do with Hibernate's own defined transaction to implement transactional functionality.
Hibernatetransactionobject contains a sessionholder, like the above Connectionholder, it encapsulates a session, with a session, We can use the session to generate a hibernate transaction for transactional operations.
4.2.3 Transaction manager Interface Definition Platformtransactionmanager
The class diagram relationships are as follows:
The point is,
- Abstractplatformtransactionmanager
- Datasourcetransactionmanager
- Hibernatetransactionmanager
- Jpatransactionmanager (later in detail)
This needs to look at the interface of the transaction manager, and how they are implemented:
-
1 First interface: transactionstatus gettransaction (transactiondefinition definition) Get transaction status based on transaction definition
The general content is the first to obtain the above description of the object transaction, to determine whether the current transaction is already present, if there is a transaction propagation property processing, after the detailed explanation, if there is no new defaulttransactionstatus, the newly created a transaction, Use object transaction to open the transaction at the same time. The
is divided into several procedures:
- 1.1 Gets the object transaction:
different transaction managers get different object Transaction-datasourcetransactionmanager is to get the above Datasourcetransactionobject Gets the connectionholder of the binding from the current thread, possibly NULL, and if NULL, takes a connection from the DataSource in the next open transaction, encapsulates the Connectionholder, Then bind to the current thread and then we new a datasourcetransactionobject, the concrete process is as follows:! [Datasourcetransactionmanager gets a transaction] [7]-Hibernatetransactionmanager gets hibernatetransactionobject from the current thread to get the sessionholder of the binding, possibly NULL, if NULL, A session is taken from Sessionfactory in the next open transaction, then encapsulated into Sessionholder, then bound to the current thread, and then we can get a new hibernatetransactionobject. , the specific process is as follows:! [Hibernatetransactionmanager gets a transaction] [8]
-1.2 build Defaulttransactionstatus, use object transaction to open transaction-Datasourcetransactionmanager DATASOURCETRANSACTIONOBJEC The opening process is as follows: first to determine whether the previous fetch of the current thread-bound connectionholder is null, if NULL, to obtain a connection from DataSource, encapsulated as Connectionholder, Then bind to the current thread because a transaction is turned on, you must turn off autocommit connection in Datasourcetransactionobject, and the code is as follows (omitted): protected void Dobegin (Ob ject transaction, transactiondefinition definition) {datasourcetransactionobject Txobject = (datasourcetransacti Onobject) transaction; Connection con = null; If Connectionholder is null, obtain the new if (txobject.getconnectionholder () = = NULL | | Txobject.getconnectionholder (). Issynchronizedwithtransaction ()) {Connection Newcon = This.dataSource.getConn Ection (); Txobject.setconnectionholder (New Connectionholder (Newcon), true); } con = Txobject.getconnectionholder (). getconnection (); Integer Previousisolationlevel = Datasourceutils.prepareconnectIonfortransaction (con, definition); Txobject.setpreviousisolationlevel (Previousisolationlevel); Cancels autocommit if (Con.getautocommit ()) {Txobject.setmustrestoreautocommit (true); if (logger.isdebugenabled ()) {Logger.debug ("Switching JDBC Connection [" + con + "] to Manual commit"); } con.setautocommit (FALSE); } txobject.getconnectionholder (). Settransactionactive (True); If it is a new connectionholder, bind to the current thread if (Txobject.isnewconnectionholder ()) {transactionsynchronization Manager.bindresource (Getdatasource (), Txobject.getconnectionholder ()); }}-The hibernatetransactionobject of Hibernatetransactionmanager is opened as follows: The same logic, if Sessionholder is null, from Sessi Onfactory gets a session, then encapsulates it into Sessionholder, then binds the sessionholder to the current thread session NewSession = (Entityinterceptor! = null ? Getsessionfactory (). Withoptions (). Interceptor (ENTItyinterceptor). Opensession (): Getsessionfactory (). Opensession ()); Txobject.setsession (newsession); At the same time, using the session above to open a transaction, the transaction object is also saved to the above Sessionholder. Transaction hibtx=session.begintransaction (); Txobject.getsessionholder (). Settransaction (HIBTX); If it is a newly created sessionholder, bind to the current thread/bind the session holder to the thread. if (Txobject.isnewsessionholder ()) {Transactionsynchronizationmanager.bindresource (Getsessionfactory (), TxObject . Getsessionholder ()); }
2 Second interface: void rollback (transactionstatus status) roll back a transaction
Rollback, or use an object transaction inside Defaulttransactionstatus to perform a rollback operation
- Datasourcetransactionmanager is a rollback operation using the connection in the Datasourcetransactionobject
protected void doRollback(DefaultTransactionStatus status) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction(); Connection con = txObject.getConnectionHolder().getConnection(); try { con.rollback(); } catch (SQLException ex) { throw new TransactionSystemException("Could not roll back JDBC transaction", ex); } }
- Hibernatetransactionmanager is a transaction transaction created using the session in the Sessionholder in hibernatetransactionobject to roll back the operation
protected void doRollback(DefaultTransactionStatus status) { HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction(); try { txObject.getSessionHolder().getTransaction().rollback(); } }
3 Third interface: void commit (Transactionstatus status) COMMIT Transaction
Similarly, Datasourcetransactionmanager relies on internal connection to complete the commit operation
Hibernatetransactionmanager relies on internal transaction to complete the commit operation
Analysis of propagation properties of 4.3 transactions
You can refer to the case of this article to illustrate the propagation behavior and isolation level of spring transactions, the following key source analysis under the spring's transaction propagation properties:
The code for the propagation properties of a transaction is as follows:
After the object transaction is obtained, it is determined whether it is an existing transaction. Because the acquisition of this object transaction is obtained directly from the thread binding, it is possible that when a transaction already exists on the front-line, it is determined as follows:
Datasourcetransactionmanager
protected boolean isExistingTransaction(Object transaction) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; return (txObject.getConnectionHolder() != null && txObject.getConnectionHolder().isTransactionActive());}
Is whether a transaction already exists in the Connectionholder bound by the current thread
Hibernatetransactionmanager
public boolean hasSpringManagedTransaction() { return (this.sessionHolder != null && this.sessionHolder.getTransaction() != null);}
is also a transaction based on whether the Sessionholder is bound to the current thread
If a transaction is already present: the propagation property of the transaction needs to be processed, as in the Handleexistingtransaction method described above:
1 Propagation_never: A transaction is not allowed, if a thrown exception is present
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) { throw new IllegalTransactionStateException( "Existing transaction found for transaction marked with propagation ‘never‘");}
2 propagation_not_supported: Transaction is not supported, if a transaction is present, the transaction must be suspended, saved, and the pending transaction needs to resume after execution is complete
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) { if (debugEnabled) { logger.debug("Suspending current transaction"); } Object suspendedResources = suspend(transaction); boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); return prepareTransactionStatus( definition, null, false, newSynchronization, debugEnabled, suspendedResources);}
After suspending, an object Transaction=null transaction is generated, that is, the transaction code is not executed, and the suspended resource information is passed to the newly created transaction, and when the transaction is completed, the suspended resources are restored.
- 2.1 For Datasourcetransactionmanager, the suspend of a transaction is to unbind the Connectionholder associated with the current thread:
protected Object doSuspend(Object transaction) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; txObject.setConnectionHolder(null); ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.unbindResource(this.dataSource); return conHolder; }同理事务的恢复就是把上述ConnectionHolder再重新绑定到当前线程,继续执行该事务
- 2.2 For Hibernatetransactionmanager, the suspend of a transaction is to unbind the Sessionholder associated with the current thread
Protected Object Dosuspend (object transaction) {Hibernatetransactionobject Txobject = (Hibernatetran Sactionobject) transaction; Txobject.setsessionholder (NULL); Sessionholder Sessionholder = (sessionholder) transactionsynchronizationmanager.unbindresource (GetSessionFactory ( )); Txobject.setconnectionholder (NULL); Connectionholder connectionholder = null; if (getdatasource () = null) {Connectionholder = (Connectionholder) Transactionsynchronizationmanager.unbindresou Rce (Getdatasource ()); } return new Suspendedresourcesholder (Sessionholder, Connectionholder); The recovery of the same transaction is to re-bind the above sessionholder to the current thread and proceed with the transaction
-
3 propagation_requires_new: Opens a new transaction and hangs the current transaction if the current transaction is present
if (definition.getpropagationbehavior () = = transactiondefinition.propagation_requires_new) {Suspendedresourcesholder suspendedresources = suspend ( Transaction); try {Boolean newsynchronization = (Gettransactionsynchronization ()! = Synchronization_never); Defaulttransactionstatus status = Newtransactionstatus (definition, transaction, True, Newsynchronization, Debuge Nabled, suspendedresources); Dobegin (transaction, definition); Preparesynchronization (status, definition); return status; }}
you can see that creating a new transaction invokes Dobegin (transaction, definition), and the transaction is opened.
4 propagation_nested: Principle Many people have explained in detail, can refer to a simple understanding of spring in the propagation_nested, source confirmation to continue to study
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { if (useSavepointForNestedTransaction()) { DefaultTransactionStatus status = prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null); status.createAndHoldSavepoint(); return status; }}
This uses the object transaction to create the savepoint, still using the original transaction
5 Propagation_supports and propagation_required: If a transaction is currently present, the thing is still used
At this point the transaction manager interface is simply finished, there are a lot of details of things, you need to study carefully.
5 concluding remarks
Understanding the Platformtransactionmanager transaction Manager, the following is the implementation of spring's programmatic transactions, declarative transactions, so the next article reads as follows:
- Transactiontemplate can implement programmatic transactions
- Spring uses AOP to implement declarative transactions
Distributed Transaction Series (1.1) Spring transaction manager Platformtransactionmanager