1 Series Catalogue
- The Distributed Transaction series (opening) raises questions and research processes
- Distributed Transaction Series (1.1) Spring transaction manager Platformtransactionmanager Source analysis
- Distributed Transaction Series (1.2) Spring Transaction system
23 Types of transactional models
The three transaction models are as follows:
- Local Transaction model
- Programmatic Transaction model
- Declarative Transaction Model
Let's take a look at some examples:
Case 1:
Connection conn=jdbcDao.getConnection();PreparedStatement ps=conn.prepareStatement("insert into user(name,age) value(?,?)");ps.setString(1,user.getName());ps.setInt(2,user.getAge());ps.execute();
Case 2:
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();}
Case 3:
InitialContext ctx = new InitialContext();UserTransaction txn = (UserTransaction)ctx.lookup("UserTransaction");try { txn.begin(); //业务代码 txn.commit();} catch (Exception up) { txn.rollback(); throw up;}
Case 4:
@Transactionalpublic void save(User user){ jdbcTemplate.update("insert into user(name,age) value(?,?)",user.getName(),user.getAge());}
My point of view:
- Case 1 belongs to the local transaction model
- Case 2, 3 belongs to the programmatic transaction model
- Case 4 belongs to the declarative transaction model
I think their respective characteristics are: Who is managing the transaction commit and rollback operations?
There are three roles: Database, Developer, Spring (third party)
- For Case 1: The developer does not need to know the existence of the transaction, all the transactions to the database to manage, the database itself decides when to commit or rollback, so the database is the manager of the transaction
- For Case 2, 3: Transaction commit and rollback operations are entirely left to the developer to determine when the transaction is committed or rolled back, so the developer is the manager of the transaction
- For Case 4: The developer does not care about the transaction at all, the commit and rollback operations of the transaction are all given to spring to manage, so spring is the manager of the transaction
The above features are not all reasonable, as mentioned in the following spring transactiontemplate, although it is a programmatic transaction, but it is indeed the submission of transactions and rollback to the spring to manage. You don't have to be overly obsessed with dividing the transaction model.
3 Programmatic transactions
Programmatic transactions: That is, by manual programming to implement transactional operations, most of the situation is similar to the case 2, 3, the developer to manage the transaction commit and rollback, but it may be spring itself to manage transactions, such as spring transactiontemplate.
3.1 Spring's Transactiontemplate
As I learned in the previous article, programming is cumbersome and always requires writing a set of template-like try catch code, so we can encapsulate the try catch code into a template, which leads to the transactiontemplate of spring:
The cases are as follows:
TransactionTemplate template=new TransactionTemplate();template.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);template.setTransactionManager(transactionManager);template.execute(new TransactionCallback<User>() { @Override public User doInTransaction(TransactionStatus status) { //可以使用DataSourceUtils获取Connection来执行sql //jdbcTemplate.update(sql2); //可以使用SessionFactory的getCurrentSession获取Session来执行 //hibernateTemplate.save(user1) return null; }});
- Transactiontemplate inherits the Defaulttransactiondefinition, has the default transaction definition, and can also customize the setting isolation level, propagate properties, etc.
- Transactiontemplate requires a Platformtransactionmanager transaction manager to perform the operation of the transaction
Transactiontemplate executes the business code in Transactioncallback, the transaction template code of the try catch is encapsulated, wrapped around the business code, See Transactiontemplate's Execute method in detail, as follows:
The detailed procedure is as follows:
First step: Get transactions based on transaction definitions
Since Transactiontemplate inherited the Defaulttransactiondefinition, So using the Platformtransactionmanager transaction manager to get transactions based on Transactiontemplate, which is part of the previous article, See Distributed Transaction Series (1.1) Spring transaction manager platformtransactionmanager source code Analysis
Step Two: Execute the business code
Execute the corresponding business code in the Dointransaction in Transactioncallback.
If you are using Datasourcetransactionmanager, you can use JdbcTemplate to execute business logic, or use connection directly, However, you must use Datasourceutils to get connection
If you are using Hibernatetransactionmanager, you can use Hibernatetemplate to execute business logic, Alternatively, you can use the Sessionfactory Getcurrentsession method to get the session of the current thread binding and not use the Sessionfactory opensession method. is not to be used, the following detailed explanation
Step three: If the business code has an exception, rollback the transaction, and no exception commits the transaction
Rollback and commit are done through the Platformtransactionmanager transaction manager.
3.2 The principle that transaction code and business code can achieve separation
We can see that the use of transactiontemplate, in fact, the separation of transaction code and business code, the cost of separation is to ensure that they are using the same type of transaction. The same principle follows the separation of declarative transaction implementations, which is explained in advance.
1 if using Datasourcetransactionmanager:
- 1.1 The transaction code executes the corresponding transaction through the commit and rollback of the connection in the Connectionholder bound by the current thread, as described in the previous article, explaining the transaction manager's transactional analysis, So we have to make sure that the business code is also using the same connection so that it can be rolled back and committed properly.
- 1.2 The business code uses jdbctemplate.update (SQL) to perform the business, this method is used by connection from where? Is it the same connection as the above transaction? The source code is as follows:
JdbcTemplate when executing SQL, a connection is obtained from DataSource using Datasourceutils. The fetch process is as follows:
也是先获取和当前线程绑定的ConnectionHolder(由于事务在执行业务逻辑前已经开启,已经有了和当前线程绑定的ConnectionHolder),所以会获取到和事务中使用的ConnectionHolder,这样就保证了他们使用的是同一个Connection了,自然就可以正常提交和回滚了
If you want to use connection, you need to use Datasourceutils to get connection from Datasorce and not get DataSource directly from connection.
2 If using Hibernatetransactionmanager:
- The 2.1 transaction code executes the corresponding transaction through the commit and rollback of the transaction in the session of the sessionholder that are bound to the current thread, as described in the previous article, explaining the transaction manager's transactional analysis, So we have to make sure that the business code is also using the same session
- 2.2 Business code can not use JdbcTemplate to execute the corresponding business logic, you need to use the session to perform the corresponding operation, replaced by the corresponding hibernatetemplate to execute.
Hibernatetemplate in the process of executing save (user), a session is obtained, in the following way:
session = getSessionFactory().getCurrentSession();
That is, using Sessionfactory's own Getcurrentsession method, gets the current session. What is the specific strategy?
Hibernate defines an interface such as: Currentsessioncontext, which reads as follows:
public interface CurrentSessionContext extends Serializable { public Session currentSession() throws HibernateException; }
The above sessionfactory get the current session is to rely on the implementation of Currentsessioncontext. It is implemented as follows:In the spring environment, the default is Springsessioncontext, which takes the current session in the following way:
It is also the first to get the sessionholder that is bound to the current thread (because the transaction is already open before the business logic is executed and the current thread is already bound to the Sessionholder), so it gets the sessionholder used in the transaction. This ensures that they are using the same session and will naturally be able to commit and rollback.
If you do not want to use hibernatetemplate, want to directly through the session to operate, the same way you need to use the Sessionfactory Getcurrentsession method to get the session, Instead of using the Sessionfactory Opensession method.
The above analysis is based on the principle of hibernate4,hibenrate3 to see themselves, are similar.
4 Spring's declarative transactions
Spring can have three forms to configure transaction interception, the different configuration form is only the external form, the interception principle is the same, so first through a small example to understand the principle of using AOP to implement transaction interception
4.1 Principles of declarative transactions using AOP4.1.1 Simple examples of AOP transactions
From the above spring transactiontemplate we can implement, the transaction code and business code separation, but the separation is not complete, or need the following code:
TransactionTemplate template=new TransactionTemplate();template.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);template.setTransactionManager(transactionManager);
A lot of settings, while the business code must be nested in the transactioncallback, how to do the following ways to completely separate it?
@Transactionalpublic void save(User user){ jdbcTemplate.update("insert into user(name,age) value(?,?)",user.getName(),user.getAge());}
This requires the use of spring's AOP mechanism, the principle of SPRINGAOP is no longer explained in detail, you can refer to the source analysis of the spring AOP source analysis, here is a simple example of the principle of AOP transaction interception:
@Repositorypublic class AopUserDao implements InitializingBean{ @Autowired private UserDao userDao; private UserDao proxyUserDao; @Resource(name="transactionManager") private PlatformTransactionManager transactionManager; @Override public void afterPropertiesSet() throws Exception { ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(userDao); TransactionInterceptor transactionInterceptor=new TransactionInterceptor(); transactionInterceptor.setTransactionManager(transactionManager); Properties properties=new Properties(); properties.setProperty("*","PROPAGATION_REQUIRED"); transactionInterceptor.setTransactionAttributes(properties); proxyFactory.addAdvice(transactionInterceptor); proxyUserDao=(UserDao) proxyFactory.getProxy(); } public void save(User user){ proxyUserDao.save(user); }}
The code analysis is as follows:
- The
- needs a primitive Userdao first, we need to do an AOP proxy for it, generate the proxy object Proxyuserdao, and then save the function is to use Proxyuserdao to execute
-
The specific agent procedure for Userdao is as follows:
- use a proxy factory to set the object to be proxied, that is, target
proxyfactory.settarget
Rdao);
- Adding interceptors to proxy objects
The is divided into 2 cases, a default interception of the original Userdao all methods, one is to specify Pointcut, that is, some methods of intercepting the original Userdao.
Uses Proxyfactory.addadvice (Transactioninterceptor) here, which means that all methods of the original Userdao are intercepted by default.
If you use Proxyfactory.addadvisor (advisor), the advisor here can be simply considered a combination of pointcut and advice, and pointcut is used to specify whether or not to intercept certain methods.
The above addadvice is the use of the default Pointcut, indicating that all methods are intercepted, the source code is as follows:
addadvisor (POS, New Defaultpointcutadvisor ( Advice)
Defaultpointcutadvisor content is as follows:
public defaultpointcutadvisor (advice advice) { This (pointcut.true, advice); The
Pointcut.true indicates that all methods are blocked. The
Then explains the transaction interceptor in more detail.
- After you have set up the objects and interceptors that the agent factory will proxy, you can create proxy objects.
proxyuserdao= (Userdao) proxyfactory.getproxy ()
After we use the created Proxyuserdao, Will first go into the interceptor and execute the relevant interceptor code, so we can implement transaction handling here
The principle analysis of 4.1.2 Transaction Interceptor
A transaction interceptor requires 2 parameters:
Provider of the transaction configuration
Used to specify which methods have what kind of transactional configuration
There are three ways to get the transaction configuration provider by way of property configuration, or through some other configuration methods:
<property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property>
<tx:attributes> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" />
@Transactional(propagation=Propagation.REQUIRED)
Transaction manager Platformtransactionmanager
With the configuration of the transaction, we can get the transaction through the transaction manager.
When executing the Save (user) method of Agent Proxyuserdao, the transaction interceptor is entered first, and the specific interception code is as follows:
- First step: Get the corresponding transaction configuration of the executed method first
- Second step: Then get the specified transaction manager platformtransactionmanager
- Step three: Create a transaction using the transaction manager based on the transaction configuration
- Fourth step: Proceed to the next interceptor and eventually execute the method to the proxy's original object
- Fifth step: The transaction interceptor is used for the rollback of a transaction once the execution procedure has been abnormal
- Sixth step: If there is no exception, commit the transaction using the transaction interceptor
The content of a transaction interceptor is roughly the same.
Three types of transaction configuration for 4.2 spring4.2.1 using Transactionproxyfactorybean
The configuration cases are as follows:
<bean id="proxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!-- 为事务代理工厂Bean注入事务管理器 --> <property name="transactionManager" ref="transactionManager" /> <!-- 要在哪个Bean上面创建事务代理对象 --> <property name="target" ref="productDao" /> <!-- 指定事务属性 --> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property></bean>
Case Analysis:
There are three major configurations:
- Transaction manager TransactionManager
Provider of the transaction configuration transactionattributes (used to specify which methods have what kind of transactional configuration)
With the above 2 elements, we can create a transaction interceptor Transactioninterceptor
object to proxy for target
Transactionproxyfactorybean This factory bean the principle of creating a proxy object is to create a proxy object against target by Proxyfactory, and then join the above transaction interceptor to implement the transaction interception function.
4.2.2 Using Aop:config and Tx:advice
The way to use Transactionproxyfactorybean only for a target agent, if you want to proxy a target, you need to configure a transactionproxyfactorybean, more trouble, So with Apo:config configuration, you can proxy for all targets that match pointcut.
The configuration cases are as follows:
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="pointcut" expression="XXXX" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" /> </aop:config>
There are 2 types of configurations:
Tx:advice:
With transaction manager TransactionManager and transaction configuration provider attributes, you can generate a transaction interceptor Transactioninterceptor
Aop:config:
This will create a proxy object for the bean that conforms to pointcut, and join the transaction interceptor created above
4.2.3 using @transactional
With Aop:config You can configure proxies in XML, and sometimes you want to configure them directly in your code, and you need to use annotation @transactional.
The cases are as follows:
Start @transactional annotation Scan in XML
<tx:annotation-driven transaction-manager="transactionManager" />
In the code, you can configure @transactional to enable transaction interception.
@Transactional(propagation=Propagation.REQUIRED)public void save(User user){ xxxx}
Starting the annotation scan in the XML configuration, the container bean that joins the @transactional tag is created with the proxy object, and the transaction interceptor is added. When performing a transaction interception, the corresponding transaction configuration and transaction manager configuration is removed from the @transactional annotation, allowing the creation of transactions to be performed.
5 concluding remarks
Now that spring's transaction system is about to be finished, the next step is to explain how to implement distributed transactions, before dealing with Jotm, Atomikos these third-party frameworks, first understand the following, some concepts of distributed transactions
- 1 x/open DTP model, XA specification, 2PC
- 2 JTA, JTS concept
- 3 understanding of JTA interface Definitions
Distributed Transaction Series (1.2) Spring's transaction architecture