1. spring
spring defines things by three APIs
Transaction Definition
Platform Transaction Manager manages things, submits or rolls back
Transaction Status represents the state in which something is running
Definition of Things Transaction Definition
public interface TransactionDefinition { //Isolation level int getIsolationLevel(); //Communication behavior int getPropagationBehavior(); //timeout int getTimeout(); //readOnly boolean isReadOnly(); }
DefaultTransaction Definition is the default implementation class, which has a subclass Transaction Template. Transaction Template's execute method can directly program things.
Management of Things Platform Transaction Manager
public interface PlatformTransactionManager { //Query the current state of things TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException; //Submission of things void commit(TransactionStatus var1) throws TransactionException; //rollback transaction void rollback(TransactionStatus var1) throws TransactionException; }
Realization:
Data Source Transaction Manager: For data persistence operations using JDBC and iBatis.
Hibernate Transaction Manager: Suitable for data persistence operations using Hibernate.
JpaTransaction Manager: Applicable to data persistence operations using JPA.
Rabbit Transaction Manager Rabbitmq supports integration with spring things
There are also JtaTransaction Manager, JdoTransaction Manager, Jms Transaction Manager, and so on.
Transaction Status
public interface TransactionStatus extends SavepointManager, Flushable { //Is it a new thing (to participate in an existing thing, or when nested, the first layer calls nothing nesting to open things)? boolean isNewTransaction(); //Is there a preservation point? boolean hasSavepoint(); //Setting things to roll back void setRollbackOnly(); //Whether to roll things back or not boolean isRollbackOnly(); //Refreshing the session of the current thread to the database has an impact on Hibernate/JPA sessions void flush(); //Are things completed, submitted, or rolled back? boolean isCompleted(); }
Realization:
DefaultTransactionStatus,SimpleTransactionStatus
2. There are two ways to manage things with spring, programming and declarative. Let's look at two ways to implement it
2.1 Programming things:
There are two ways of programmable transaction management
1. Submit rollback items using Platform Transaction Manager
2. Use Transaction Template
Sample code:
@Service public class ProgrammaticService { @Autowired private RuleDOMapper ruleDOMapper; @Autowired private PlatformTransactionManager transactionManager; @Autowired private TransactionDefinition txDefinition; @Autowired private TransactionTemplate transactionTemplate; public void useTXManager(){ TransactionStatus txStatus = transactionManager.getTransaction(txDefinition); boolean result = false; try { ruleDOMapper.insert(new RuleDO()); transactionManager.commit(txStatus); } catch (Exception e) { transactionManager.rollback(txStatus); System.out.println("Transfer Error!"); } } public void useTXTemplate(){ transactionTemplate.execute(new TransactionCallback<Integer>() { @Override public Integer doInTransaction(TransactionStatus status) { ruleDOMapper.insert(new RuleDO()); return 1; } }); } } public class RuleDOMapper { SqlSession sqlSession; public int insert(RuleDO record){ return sqlSession.insert(getNameSpace()+"insert",record); } public String getNameSpace(){ return this.getClass().getName()+"."; } //get set method }
To configure:
<!-- Configure data source information --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://192.168.30.96:3306/test?autoReconnect=true&useUnicode=true&characterset=utf8"/> <property name="username" value="quanyan"/> <property name="password" value="quanyan888"/> </bean> <!-- To configure spring Of PlatformTransactionManager,Name is the default value --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- Object template --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"/> </bean> <!-- Definition of things --> <bean id="txDefinition" class="org.springframework.transaction.support.DefaultTransactionDefinition"> <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/> </bean> <!-- To configure ibatis Mapping information --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:mybatis/mapper/*.xml"/> <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/> </bean> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean> <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.masz.springtest.dao.*"/> <property name="sqlSessionTemplateBeanName" value="sqlSession"/> </bean> <!-- Definition mapper --> <bean id="ruleDOMapper" class="com.masz.springtest.dao.RuleDOMapper"> <property name="sqlSession" ref="sqlSession"/> </bean>
Test code:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath*:application-context.xml") public class SpringTest { @Autowired ProgrammaticService programmaticService; @Autowired TransactionInterceptorTest transactionInterceptorTest; @Test public void programmaticTxTest(){ programmaticService.useTXManager(); // programmaticService.useTXTemplate(); } }
test result
2.2 Declarative Things
Spring's declarative transaction management is based on AOP at the bottom. Its essence is to intercept the method before and after, then create or join a transaction before the target method starts, and submit or roll back the transaction according to the implementation after the target method is executed. The above programmable things are template code. Since it's template code, spring has to solve it.
Comparisons between programmable and declarative transactions
1. Declarative transaction with additional configuration will do without adding transaction management code to the code. So it's more convenient to use than programmers, business code will not be "polluted" by things code.
2. The finest granularity of declarative things can only work at the method level, not at the code block level like programmatic transactions. You can also put the code blocks of declarative things into the way things are managed separately.
Realization:
1,TransactionInterceptor
2,TransactionProxyFactoryBean
3. Implementing declarative things based on <tx> namespaces
4, @Transactional annotation
2.2.1 Using Transaction Interceptor
Sample code:
/** * TransactionInterceptor Implementing declarative things, target classes */ public class TransactionInterceptorTarget { private RuleDOMapper mapper; public void save(){ mapper.insert(new RuleDO()); } //Get set method }
Test code:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath*:application-context.xml") public class SpringTest { @Resource(name = "transactionInterceptorTarget") TransactionInterceptorTarget transactionInterceptorTarget; @Resource(name = "transactionInterceptorTargetProxy") TransactionInterceptorTarget transactionInterceptorTargetProxy; @Test public void transactionInterceptorTest(){ //Direct use is nothing. transactionInterceptorTarget.save(); //Using proxy objects can be enhanced by things transactionInterceptorTargetProxy.save(); } }
Configuration (data source transactionManager, see the configuration above in the reference article):
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <!-- Define the attributes of things --> <props> <!-- Configure the object attributes or method wildcards used by the method name of the target class --> <prop key="save*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <!-- Target object, direct use is nothing.--> <bean id="transactionInterceptorTarget" class="com.masz.springtest.transaction.TransactionInterceptorTarget"> <property name="mapper" ref="ruleDOMapper"/> </bean> <!-- adopt ProxyFactoryBean Getting Enhanced Objects of Target Objects --> <bean id="transactionInterceptorTargetProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- Proxy target class --> <property name="target" ref="transactionInterceptorTarget"/> <!-- Use interceptor Enhance --> <property name="interceptorNames"> <list> <idref bean="transactionInterceptor"/> </list> </property> </bean>
Test results:
Use the target class directly without opening spring things
Open spring things using proxy classes
The disadvantage of using Transaction Interceptor is that there are too many configurations, each target class that uses things needs to be configured with a Transaction Interceptor and a ProxyFactoryBean.
spring also provides a Transaction ProxyFactory Bean that combines the configuration of Transaction Interceptor and ProxyFactory Bean to alleviate this problem.
2.2.2, Transaction ProxyFactoryBean Implementation
Sample code:
/** * TransactionProxyFactoryBean test */ public class ProxyFactoryBeanTestTarget { private RuleDOMapper mapper; public void save(){ mapper.insert(new RuleDO()); } //get set method }
configuration file
<!-- Target object --> <bean id="proxyFactoryBeanTestTarget" class="com.masz.springtest.transaction.TransactionInterceptorTarget"> <property name="mapper" ref="ruleDOMapper"/> </bean> <!-- Surrogate object --> <bean id="proxyFactoryBeanProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="target" ref="proxyFactoryBeanTestTarget"/> <!-- Attributes of Things Management --> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <props> <!-- save The way to start is enhanced by things. --> <prop key="save*">PROPAGATION_REQUIRED</prop> </props> </property> </bean>
Test code:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath*:application-context.xml") public class SpringTest { //Use code objects to be enhanced by things @Resource(name = "proxyFactoryBeanProxy") TransactionInterceptorTarget proxyFactoryBeanProxy; @Test public void proxyFactoryBeanTest(){ proxyFactoryBeanProxy.save(); } }
Test results:
Using TransactionProxyFactoryBean, a class also needs two configurations. And proxy classes need to be injected.
2.2.3. Implementing declarative things based on <tx> namespaces
Test code:
/** * tx Configuration namespace configuration testing */ public class TransactionTXNameSpaceTest { private RuleDOMapper mapper; public void add(){ mapper.insert(new RuleDO()); } //Getset method... }
To configure:
<!-- Target object --> <bean id="transactionTXNameSpaceTest" class="com.masz.springtest.transaction.TransactionTXNameSpaceTest"> <property name="mapper" ref="ruleDOMapper"/> </bean> <!-- Declarative container transaction management advice --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- pointcut matching --> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="upd*" propagation="REQUIRED"/> <tx:method name="del*" propagation="REQUIRED"/> <tx:method name="*" read-only="true"/> </tx:attributes> </tx:advice> <aop:config expose-proxy="true"> <!-- pointcut --> <aop:pointcut id="txPointcut" expression="execution(* com.masz.springtest.transaction..*.*(..))"/> <!-- Advisor --> <aop:advisor pointcut-ref="txPointcut" advice-ref="txAdvice"/> </aop:config>
Test code:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath*:application-context.xml") public class SpringTest { @Autowired TransactionTXNameSpaceTest transactionTXNameSpaceTest; @Test public void transactionTXNameSpaceTest(){ //Direct use of target classes transactionTXNameSpaceTest.add(); } }
Test results:
As long as you configure the facets of the configuration, you can rest assured of using things to enhance.
4. Implementing declarative transactions based on @Transactional
Add configuration:
<! - Declarative transaction configuration based on @Transactional
<! -- The default value of the transaction-manager attribute is transactionManager, which can be omitted if the name of the transaction manager Bean is that value. >
<tx:annotation-driven transaction-manager="transactionManager"/>
The test is relatively simple, so I won't write it.
Attention should be paid to using @Transactional:
1. The @Transactional annotation can work on interfaces, interface methods, classes, and class methods, but it is not recommended to use the annotation on interfaces or interface methods because it will only take effect when using an interface-based proxy.
2. The @Transactional annotation should only be applied to the public method, which is determined by the nature of Spring AOP. If you use the @Transactional annotation on protected, private, or default visibility methods, it will be ignored and no exception will be thrown.
3. The @Transactional approach must be annotated with @Transactional on every method or class that needs to use transactions. Although the rules of most transactions may be consistent, they cannot be reused for @Transactional and must be specified one by one.
End:
Although the above list of four declarative transaction management methods, but this division is only for easy understanding, in fact, the implementation of the background is the same, but the way users use it is different.