This article mainly studies the relevant content of Spring's transaction mechanism, as follows.
There are usually two transaction strategies: global transactions and local transactions. Global transactions can span multiple transactional resources (i.e., data sources, typically databases and message queues), and usually require the management of J2EE application servers, which requires the server's JTA support at the bottom. Local transactions are related to the persistence technology adopted by the underlying layer. If the underlying layer directly uses JDBC, the Connection object needs to be used to operate the transaction. If Hibernate persistence technology is used, you need to use the session object to operate the transaction.
Generally, the programming process using JTA transactions, JDBC transactions and Hibernate transactions is roughly as follows.
As can be seen from the above figure, using traditional transaction programming, the program code must be coupled with the API of specific transaction policies. If the application needs to switch a strategy, it means that the code needs to be greatly modified. But if you use Spring transactions, there will be no problem.
Sring does not provide any transaction support, it is only responsible for wrapping the underlying transactions, and at the Spring level, it provides a unified programming API to the outside world. The core of Spring transaction is the PlatformTransactionManager interface.
PlatformTransactionManager represents a transaction interface that is independent of the specific type and can represent any transaction, including JDBC transactions, Hibernate transactions, and even JTA transactions.
Springa transaction mechanism is a typical policy model. PlatformTransactionManager represents the transaction management interface, but it does not know how to manage transactions. It only requires transaction management to provide three methods: start transaction getTransaction(), commit() transactions and rollback() However, the specific implementation is left to its implementation class to complete. Programmers only need to configure the transaction type in the configuration file according to the specific transaction type used. The underlying Spring will automatically use the specific transaction implementation class to perform transaction operations. For programmers, they do not need to care about the underlying process at all, they only need to program for the PlatformTransactionManager interface. The PlatformTransactionManager interface provides the following methods: getTransaction(..), commit(); rollback(); These are all transaction operations that are unrelated to the platform.
The complete writing of getTransaction() is TransactionStatus getTransaction(TransactionDefinition definiton)
This method is used to return a transaction object, and the parameter TransactionDefinition can specify various attributes for the transaction object. Usually, it can specify the isolation attributes of the transaction, propagation attributes, timeout, and read only these attributes.
Spring's specific transaction management requires the PlatformTransactionManager to be configured in the configuration file. The following is the Spring configuration corresponding to different types of transactions.
The configuration of the local transaction manager of the JDBC data source is as follows:
<!-- Define the data source bean, use the C3P0 data source to implement it, and inject the necessary information of the data source --> <bean id="dataSource" destroy-method="close" p:driverClass="com.mysql.jdbc.Driver" p:jdbcUrl="jdbc:mysql://localhost/test" p:user="root" p:password="" p:maxPoolSize="40" p:minPoolSize="2" p:initialPoolSize="2" p:maxIdleTime="30" /> <!-- Configure the local data manager for JDBC data source, use the DataSourceTransactionManager class --> <bean id="transactionManager" p:dataSource-ref="dataSource" />
The configuration of the JTA global transaction manager for container management is as follows:
<bean id="dataSource" p:jndiName="jdbc/jpetstore" /><!-- Using the JtaTransactionManager class, this class implements the PlatformTransactionManager interface-><!-- Using JTA global transactions, Spring containers can obtain transactional resources from the Java EE server by themselves without dependency injection--><bean id="transactionManager" />
For JTA global transactions, you only need to specify the transaction manager's implementation class JtaTransactionManager. The Spring container will obtain the data source from the J2EE server by itself, without explicit injection into the transaction manager.
The Spring local transaction configuration based on Hibernate persistence technology is as follows.
<!-- Define the data source bean, use the C3P0 data source to implement it, and inject the necessary information of the data source--> <bean id="dataSource" destroy-method="close" p:driverClass="com.mysql.jdbc.Driver" p:jdbcUrl="jdbc:mysql://localhost/test" p:user="root" p:password="" p:maxPoolSize="40" p:minPoolSize="2" p:initialPoolSize="2" p:maxIdleTime="30" /> <!-- Define the SessionFactory of Hibernate, SessionFactory needs to rely on data source, inject dataSource --> <bean id="sessionFactory" p:dataSource-ref="dataSource"> <!-- annotatedClasses is used to list all persistent classes --> <property name="annotatedClasses"> <list> <!-- The following is used to list all PO classes --> <value>com.entity.User</value> </list> </property> <!-- Define the sessionFactory property of Hibernate--> <property name="hibernateProperties"> <props> <!-- Specify the connection dialect of Hibernate--> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> <!-- Whether to create data tables based on Hibernate mapping tables--> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- Configuring Hibernate's local data manager, using the HibernateTransactionManager class--> <!-- This class is a specific implementation of the PlatformTransactionManager interface for Hibernate--> <!-- Configuring HibernateTransactionManager requires sessionFactory --> <bean id="transactionManager" p:sessionFactory-ref="sessionFactory" />
If Spring transactions adopt Hibernate policy, three points are generally required to configure: data source, sessionFactory, and transaction manager.
If the underlying layer uses Hibernate persistence layer technology and the transaction uses JTA global transaction, the configuration is as follows:
<!-- Configure JTA data source --> <bean id="dataSource" p:jndiName="jdbc/jpetstore" /> <!-- Define Hibernate SessionFactory. SessionFactory needs to rely on the data source and inject dataSource --> <bean id="sessionFactory" p:dataSource-ref="dataSource"> <!-- annotatedClasses are used to list all persistent classes --> <property name="annotatedClasses"> <list> <!-- The following is used to list all PO classes --> <value>com.entity.User</value> </list> </property> <!-- Define the sessionFactory property of Hibernate --> <property name="hibernateProperties"> <props> <!-- Specify the connection dialect of Hibernate --> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> <!-- Whether to create data tables based on Hibernate mapping tables --> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- Use the JtaTransactionManager class, which is an implementation class of the PlatformTransactionManager interface --> <!-- Specific implementations for global transaction management --> <bean id="transactionManager" />
Compared with the previous Hibernate-based Spring transaction, this is to replace the data source with a JNDI data source and replace the transaction manager with a JtaTransactionManager.
For JTA global transactions, because the support of the underlying application server is required, there may be differences in details between JTA global transactions provided by different application servers. Therefore, when actually configuring the global transaction manager, you may need to use subclasses of JtaTransactionManager, such as OC4JJtaTransactionManager provided by Oracle's JavaEE application server, WebLogicJtaTransactionManager provided by Oracle for WebLogic, WebSphereUowTransactionManager provided by IBM for WebSphere, etc.
From the Spring configuration of various transaction types above, it can be seen that when an application adopts Spring transaction management, the application does not need to be coupled with the specific transaction API. The application only needs to be programmed to the PlatormTransactionManager interface. The ApplicationContext will select the appropriate transaction policy implementation class (i.e. the implementation class of the PlatormTransactionManager) based on the configuration file.
So in detail how to perform transaction control programming in Spring, there are usually two ways.
Programming transaction management: It is to directly use the three abstract methods provided by PlatormTransactionManager to control transaction flow in the code. You can also get a Bean of type PlatormTransactionManager in the Spring container. This Bean is always an instance of the specific implementation class of the PlatormTransactionManager. The specific implementation class is selected by the ApplicationContext according to the policy pattern. Programmers do not need to care about it, they only need to program interface-oriented.
Declarative transaction management: This method does not require the transaction control process to be written into the code, but uses AOP to complete the transaction incorporation completely through configuration files. That is, XML configuration files can configure transaction agents for business components, and transaction agents provide transaction control for business components. Now this method is the best, with the lowest source code intrusion.
When using declarative transactions, you only need to write a configuration file and configure the types of components that require transaction control. The business components will be weaved into transaction control under the AOP mechanism, and programmers do not need to write any transaction management code and can focus on the development of business components. Therefore, declarative transaction management is generally recommended.
Spring's XML Schema method provides a concise transaction configuration strategy. It configures a transaction enhancement processing through the namespace <tx:advice> , where various attributes of the transaction can be specified (such as isolation attributes, propagation attributes, timeout, read-only attributes, etc.), and then the transaction enhancement can be bound to the AOP's entry point (i.e., the execution method of the bean) through the <aop:config> tag, thereby weaving the bean's methods into transaction operations. Here is a simple example, configuring a NewsDaoImpl bean for data operations, using the c3p0 data source, Spring's JDBC transaction manager, and setting properties for transactions in <tx:advice.
The complete Spring configuration is as follows:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <!-- Define the data source bean, use the C3P0 data source to implement it, and inject the necessary information of the data source --> <bean id="dataSource" destroy-method="close" p:driverClass="com.mysql.jdbc.Driver" p:jdbcUrl="jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=UTF-8" p:user="root" p:password="" p:maxPoolSize="40" p:minPoolSize="2" p:initialPoolSize="2" p:maxIdleTime="30" /> <!-- Configure the local data manager of JDBC data source, use the DataSourceTransactionManager class --> <bean id="transactionManager" p:dataSource-ref="dataSource" /> <!-- Configure a business logic bean --> <bean id="newsDao" p:ds-ref="dataSource" /> <!-- Configure transaction enhancement processing, specify transaction manager --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- Used to configure detailed transaction definitions --> <tx:attributes> <!-- All methods starting with get are read-only --> <tx:method name="get*" read-only="true" /> <!-- All other methods are subject to transactions by default, specifying a timeout of 5 seconds --> <tx:method name="*" isolation="DEFAULT" propagation="REQUIRED" timeout="5" /> </tx:attributes> </tx:advice> <aop:config> <!-- Configure an entry point to match the execution of all methods in all impl-end classes under the impl package --> <aop:pointcut expression="execution(* com.dao.impl.*Impl.*(..))" id="myPointcut" /> <!-- Binding the entry point myPointcut and enhance txAdvice--> <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" /> <!-- Configure another entry point to match the execution of all methods in the class starting with abc under the impl package --> </aop:config></beans>
In the NewsDaoImpl code, it is to insert duplicate data into the table.
package com.dao.impl;import javax.sql.DataSource;import org.springframework.jdbc.core.JdbcTemplate;import com.dao.NewsDao;public class NewsDaoImpl implements NewsDao {private DataSource ds;public void setDs(DataSource ds) {this.ds = ds;}@Override public void insert(String title, String content) {//Usage of c3p0 data pool JdbcTemplate jt = new JdbcTemplate(ds);jt.update("insert into news_inf" + " values(100,?,?)", title, content);jt.update("insert into news_inf" + " values(100,?,?)", title, content);//If there is no transaction control, the first record can be inserted //If transaction control is added, the first record will not be inserted }}Here is the test method.
public static void test3() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans4JDBC.xml"); //Get the transaction agent Bean NewsDao dao = (NewsDao)ctx.getBean("newsDao", NewsDao.class); dao.insert("Core idea of java programming", "Lightweight Java EE development"); System.out.println("Execution completed"); }Executing the test method will find that an exception is thrown (because of duplicate data) and because of transaction control, there will be no data insertion in the database.
As you can see in the above example, usually in the XML Schema configuration, an AOP configuration is actually done for an ordinary bean, and an advice enhancement is incorporated. The advice enhancement is configured with a transaction manager, which relies on the data source.
For <aop:advisor>, the binding of advice and entry point is done by the Bean postprocessor at the bottom of Spring (such as BeanNameAutoProxyCreator, DefaultAdvisorAutoProxyCreator), which is essentially a dynamic proxy.
In addition, in the <tx:advice> configuration enhancement, you can also specify that when a specific exception is encountered, force rollback and force not rollback, that is, rollback-for="xxxException", no-rollback-for="xxxException"
In addition to using XML Schema methods, you can also directly add @Transaction annotation to the method to make this method have transactional properties. In @Transaction, various properties can be configured for transactions (such as isolation properties, propagation properties, timeouts, read-only properties, etc.). In addition, it is necessary to add a <tx:annotation-triven configuration to the XML configuration, indicating that Spring will configure the transaction agent according to the annotation, so that the property configuration of the transaction and the AOP-cutting configuration can be completed in only one step (directly through the annotation configuration on the method name).
<tx:annotation-driven transaction-manager="transactionManager" />
NewsDaoImpl.
@Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.DEFAULT, timeout=5)@Overridepublic void insert(String title, String content) {The above is the entire content of this article about Spring's transaction mechanism example code, and I hope it will be helpful to everyone. Interested friends can continue to refer to other related topics on this site. If there are any shortcomings, please leave a message to point it out. Thank you friends for your support for this site!