Spring transaction infrastructure

Foreword

I guess probably 50 percent of Java programmers (Do not ask how I know, anyway, I was, too failed!) Is now confined to a @Transactional annotation or configure transaction-related stuff in XML, then in addition to transaction level , other knowledge of the transaction may be blank. For a more complete study, so I point summary of what knowledge Spring affairs, there is nothing wrong or supplementary, we remember message tell me ha.

Why Affairs

On the origin of the transaction, I am not a child, for example, many people first reaction is to go to the bank to save money (but I used to spend chant) of the operation. Four characteristics of a transaction ACID: Atomicity (Atomicity), consistency (Consistency), isolation (Isolation), persistent (Durability Rev)

Transaction isolation level

(1) ** read uncommited: ** is the lowest transaction isolation level, which allows another transaction can see the data that uncommitted transactions. (2) ** read commited: ** assurance of things after a submission can be read another transaction. Another thing that the transaction can not read data uncommitted. (3) ** repeatable read: ** This transaction isolation levels prevent dirty reads, non-repeatable reads. But the phantom read may occur. In addition to ensuring that a transaction can not be read by another uncommitted transaction also avoids the addition to produce the following (non-repeatable read). (4) ** serializable: ** This is the most expensive, but the cost of the most reliable transaction isolation level. The transaction is processed as a sequential execution. In addition to prevent dirty reads, non-repeatable read, but also avoids the phantom read

Description:. A dirty read: means that when a data access transaction CNS, and the data is modified, and this data is not submitted to the database, then, another transaction can access the data, then use this data. Because this data is not submitted then another transaction to read this data we call dirty data. Based on what you did the dirty data is willing to be incorrect. . B unrepeatable reads: means within a transaction, a plurality of times to read the same data. In this transaction has not been carried over, another transaction also access the same data, so between the two reads data in the first transaction, second transaction because the modification of the first transaction twice read data may not be the same, so a thing occurs in two consecutive read data is not the same, this is called a non-repeatable read. . C Phantom read: A transaction has a read range of records, but a different number of records read twice, we call phantom read (twice a select statement execution with different results will appear, will be read a second time add a data line, he did not say that it is executed twice in the same transaction)

Interface Architecture

@Transactional annotation estimated that we all understand, so let's look at its source code tracking, found PlatformTransactionManager this interface type, specific interface method is as follows:

public interface PlatformTransactionManager()...{  
    // 由TransactionDefinition得到TransactionStatus对象
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; 
    // 提交
    void commit(TransactionStatus status) throws TransactionException;  
    // 回滚
    void rollback(TransactionStatus status) throws TransactionException;  
    } 
复制代码

It is the definition of the three steps we usually operate affairs. Embodied implemented by its subclasses, the following relationship is shown in FIG:

Several implementations Affairs

(1) programmatic transaction management of POJO-based applications is the only choice. Related transaction management method we need to call beginTransaction code (), commit (), rollback (), etc., this is the programmatic transaction management. (Java will be learned of it, I do not this a long-winded.) (2) based on TransactionProxyFactoryBean declarative transaction management (3) based on @Transactional declarative transaction management (4) Transaction-based Aspectj AOP configuration

1, programmatic transaction

Specific achieve the following:

import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

//1、注入事务管理器对象
@Autowired
private PlatformTransactionManager txManager;

//2、开启事务
TransactionStatus status = txManager.getTransaction(new DefaultTransactionDefinition());
//3、提交
txManager.commit(status);
4、回滚
txManager.rollback(status);
复制代码

Usage scenarios: in springboot project development, involves calling a third-party interface to request the third party interface successfully but returns the transaction fails, you need to delete a data into a table, or update the status table in another table while logging and so on, the actual performance of the third-party request back to the front end.

2, TransactionProxyFactoryBean achieve Affairs

Profile: applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	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-3.0.xsd
                        http://www.springframework.org/schema/context 
                        http://www.springframework.org/schema/context/spring-context-3.0.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                        http://www.springframework.org/schema/aop
                        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <!-- 引用外部文件 db.properties读取数据库配置-->
    <context:property-placeholder location="classpath:db.properties"/>
 
    <!-- schemaLocation后面两个命名空间是扫描该包必须有的 -->
    <!-- 扫描com.sunline包以及所有子包,为所有加了注解的类创建bean -->
    <context:component-scan base-package="com.sunline">
    </context:component-scan>
	<bean id="dataSource"
		class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName"
			value="${driverClassName}">
		</property>
		<property name="url"
			value="${url}">
		</property>
		<property name="username" value="${username}"></property>
		<property name="password" value="${password}"></property>
	</bean>
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">
					org.hibernate.dialect.MySQLDialect
				</prop>
				<prop key="dialect">
				    org.hibernate.dialect.MySQLDialect
				</prop>
                <prop key="hibernate.hbm2ddl.auto">true</prop>
                <prop key="hibernate.show_sql">true</prop> 
			</props>
		</property>
		<property name="mappingResources">
			<list>
				<value>com/sunline/entity/Account.hbm.xml</value>
			</list>
		</property>
   </bean>
   
   	<!-- 配置Hibernate事务管理器 -->
	 <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
	
   	<!-- ==================================2.使用XML配置声明式的事务管理(原始方式)=============================================== -->
	<!-- 配置业务层的代理 -->
	<bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<!-- 配置目标对象 -->
		<property name="target" ref="accountBizTwo" />
		<!-- 注入事务管理器 -->
		<property name="transactionManager" ref="transactionManager"></property>
		<!-- 注入事务的属性 -->
		<property name="transactionAttributes">
			<props>
				<!-- 
					prop的格式:
						* PROPAGATION	:事务的传播行为
						* ISOTATION		:事务的隔离级别
						* readOnly		:只读
						* -EXCEPTION	:发生哪些异常回滚事务
						* +EXCEPTION 	:发生哪些异常不回滚事务
				 -->
				<prop key="transfer">PROPAGATION_REQUIRED,readOnly</prop>
				<!-- <prop key="transfer">PROPAGATION_REQUIRED,readOnly</prop> -->
				<!-- <prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop> -->
			</props>
		</property>
	</bean>
</beans>
复制代码

This is mainly using xml configuration transactions, in fact, like the effect of @Transactional now. For more detailed configuration can refer to the article: blog.csdn.net/linhaiyun_y...

3, based on the declarative transaction management @Transactional

The most simple, temporarily go into detail.

4, based on the configuration Aspectj AOP affairs

1) create tools for open transactions, commit the transaction, the transaction will roll


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
//注入spring容器中
@Component
//创建为多例对象,放置多线程安全问题
@Scope("prototype")
public class AopAspectUtil {
    @Autowired
    private DataSourceTransactionManager manager; //注入spring的事务管理器
   //事务拦截器
    private TransactionStatus transaction;

    public TransactionStatus begin() {
        transaction = manager.getTransaction(new DefaultTransactionAttribute());//设置为默认事务隔离级别
       //返回事务拦截器
        return transaction;
    }

    public void commit() {
       // 提交事务
        manager.commit(transaction);
    }

    public void rollback() {
       //回滚事务
        manager.rollback(transaction);
    }
}
复制代码

2), defined Note


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Target({ElementType.TYPE,ElementType.METHOD})//设置注解使用范围
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
public @interface MyTransactional {
}
复制代码

3), custom notification

Note the use, in a transaction for management, methods do not go try {} catch () {}, using a try ,, after catch aop can not get to the exception information, will not result in a rollback after an exception, if you do need to try, ,, catch can then finally adding the TransactionAspectSupport.currentTransactionStatus () setRollbackOnly ();. thus rollback transaction code segment

import com.zbin.aop.mytransation.TransactionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
 
@Component
@Aspect
public class AopTransaction {
    @Autowired
    private TransactionUtils transactionUtils;
 
    @Around("execution(* cn.xbmchina.service.UserService.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //调用方法之前执行
        System.out.println("开启事务");
       transactionUtils.begin();
        proceedingJoinPoint.proceed();
        //调用方法之后执行
        System.out.println("提交事务");
        transactionUtils.commit();
 
    }
 
    @AfterThrowing("execution(* cn.xbmchina.aop.service.UserService.add(..))")
    public void afterThrowing() {
        System.out.println("异常通知  ");
        //获取当前事务进行回滚
        //TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        transactionUtils.rollBack();
    }
}
复制代码

4) Test

@MyTransactional
public void add() {
    userDao.add("test001", 20);
    int i = 1 / 0;
    System.out.println("---------------------");
    userDao.add("test002", 20);
}
复制代码

Transaction propagation behavior

The following section is taken from "Don barley": blog.csdn.net/soonfly/art... transaction propagation behavior (propagation behavior) refers to when a transaction method is invoked by another transaction method, this method should be how to make the transaction. For example: methodA transaction method is invoked methodB transaction method, methodB is to continue to run the affairs of the caller methodA it, or start a new run their own affairs, which is determined by the propagation behavior methodB transactions.

After reading still feel a bit ignorant, then one by one for you briefly explain the pictures.

1、PROPAGATION_REQUIRED

If there is a transaction, the current transaction support. If no transaction is to open a new business. The transaction can be thought of as a capsule, used in this context is a capsule Method B (transaction) Method A produced.

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
 methodB();
// do something
}

@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {
    // do something
}
复制代码

When you call methodB method alone, because there is no current context of the transaction, it will open a new business. When you call methodA method, because there is no current context matters, it will open a new business. When executing to methodB, methodB discover the current context matters, and therefore be added to the current transaction.

2、PROPAGATION_SUPPORTS

If there is a transaction, support the current transaction. If there is no transaction, the non-executive affairs. But for the transaction manager to synchronize, PROPAGATION_SUPPORTS and does not use transactions slightly different.

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
 methodB();
// do something
}

// 事务属性为SUPPORTS
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB() {
    // do something
}

复制代码

When a simple call methodB, performed methodB method is non affairs. When you call methdA, methodB then added methodA transaction, to execute a transaction.

3、PROPAGATION_MANDATORY

If there is already a transaction, support the current transaction. If there is no active transaction, an exception is thrown.

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
 methodB();
// do something
}

// 事务属性为MANDATORY
@Transactional(propagation = Propagation.MANDATORY)
public void methodB() {
    // do something
}

复制代码

When you call methodB alone, because currently there is no active transaction, it will throw an exception throw new IllegalTransactionStateException ( "Transaction propagation 'mandatory' but no existing transaction found"); When you call methodA, methodB then added to methodA affairs transaction executed.

4、PROPAGATION_MANDATORY

Use PROPAGATION_REQUIRES_NEW, need to use JtaTransactionManager as the transaction manager. It will open a new business. If a transaction already exists, the first suspend the existing transaction.

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
doSomeThingA();
methodB();
doSomeThingB();
// do something else
}


// 事务属性为REQUIRES_NEW
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
    // do something
}

复制代码

When methodA call ();, the following code is equivalent to

main(){
    TransactionManager tm = null;
    try{
        //获得一个JTA事务管理器
        tm = getTransactionManager();
        tm.begin();//开启一个新的事务
        Transaction ts1 = tm.getTransaction();
        doSomeThing();
        tm.suspend();//挂起当前事务
        try{
            tm.begin();//重新开启第二个事务
            Transaction ts2 = tm.getTransaction();
            methodB();
            ts2.commit();//提交第二个事务
        } Catch(RunTimeException ex) {
            ts2.rollback();//回滚第二个事务
        } finally {
            //释放资源
        }
        //methodB执行完后,恢复第一个事务
        tm.resume(ts1);
        doSomeThingB();
        ts1.commit();//提交第一个事务
    } catch(RunTimeException ex) {
        ts1.rollback();//回滚第一个事务
    } finally {
        //释放资源
    }
}
复制代码

Here, I called the outer transaction ts1, ts2 called inner affairs. As can be seen from the above code, TS2 and ts1 are two separate transactions, independent of each other. Ts2 success does not depend on whether ts1. If methodA method doSomeThingB method after the call methodB method failed, and the results made methodB methods are still being submitted. Other code in addition to the result methodB been caused rollback

5、PROPAGATION_NOT_SUPPORTED

PROPAGATION_NOT_SUPPORTED always perform non-transactional, and suspend any transaction exists. Use PROPAGATION_NOT_SUPPORTED, also need to use JtaTransactionManager as a transaction manager.

6、PROPAGATION_NEVER

Always perform non-transactional, if there is an active transaction, an exception is thrown.

7、PROPAGATION_NESTED

Example:

@Transactional(propagation = Propagation.REQUIRED)
methodA(){
  doSomeThingA();
  methodB();
  doSomeThingB();
}

@Transactional(propagation = Propagation.NEWSTED)
methodB(){
  ……
}
复制代码

If you call methodB method alone, press execute REQUIRED property. If you call methodA method is equivalent to the following effect:


main(){
    Connection con = null;
    Savepoint savepoint = null;
    try{
        con = getConnection();
        con.setAutoCommit(false);
        doSomeThingA();
        savepoint = con2.setSavepoint();
        try{
            methodB();
        } catch(RuntimeException ex) {
            con.rollback(savepoint);
        } finally {
            //释放资源
        }
        doSomeThingB();
        con.commit();
    } catch(RuntimeException ex) {
        con.rollback();
    } finally {
        //释放资源
    }
}

复制代码

Before methodB method calls, method calls setSavepoint, save the current state to the savepoint. If methodB method call fails, revert to a previously saved state. However, note that at this time of the transaction did not commit, if the follow-up code (doSomeThingB () method) call fails, the rollback all operations including methodB methods. A very important concept nested transaction is dependent on the outer layer of the inner affairs matters. When the outer transaction fails, it will roll back action to do the inner office. The inner affairs operation fails and does not cause the transaction to roll back the outer layer.

In particular: The biggest difference is that PROPAGATION_REQUIRES_NEW and PROPAGATION_NESTED, PROPAGATION_REQUIRES_NEW is a completely new transaction, and is a sub-transaction PROPAGATION_NESTED external affairs, external affairs if the commit, will also be nested transaction commit, this rule also applies to roll back.

These are transactions in the case of a data source, then you have not thought about the case if multiple data sources, how to get the transaction to ensure it? Please also note that the next update multiple data sources Affairs [Spring]

Reference article

blog.csdn.net/soonfly/art…

At last

More Articles may be concerned about the public number coding ** [love] , Reply 2019 ** Oh relevant information.

Guess you like

Origin juejin.im/post/5e081ca9e51d45584d23a266