[Spring] Spring provides transaction management

Spring provides declarative transaction management:

In most cases easier to use than programmatic transaction management, transaction management code will be separated from business processes out to declaratively to implement transaction management, Spring declarative transaction management built on the basis of AOP, is a typical crosscutting concerns, be achieved through enhanced surround, the principle is the before and after method to intercept and then create target method before starting or joining a transaction, commit or roll back the transaction after execution is completed in accordance with the implementation of that model is as follows:

public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
	try {
		//开启事务
		return joinPoint.proceed();
		//提交事务
	} catch (Throwable e) {
		//回滚事务
		throw e;
	}finally {
		//释放资源
	}
}

How to achieve declarative transaction management:

In the following three tables as an example:
There are two books "alive" and "dead", five for each stock, per unit price of 9 yuan this
Here Insert Picture Description
wallet balance users are 10 yuan
Here Insert Picture Description
Following the transaction will add a record order
Here Insert Picture Description

1, add a jar Aspects spring provided herein with "spring-aspects-4.3.10.RELEASE.jar";
2, was added as follows Spring configuration file:
<?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:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

	<!-- 配置自动实例化"cn.jingpengchong"包下带特定注解的类放进IOC容器 -->
	<context:component-scan base-package="cn.jingpengchong"></context:component-scan>
	
	<!-- 配置Hikari数据库连接池 -->
	<bean id="hikariDSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close" p:username="root" p:password="1234">
		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/mytest"></property>
	</bean>
	
	<!-- 配置自动实例化JdbcTemplate类放进IOC容器 -->
	<bean class="org.springframework.jdbc.core.JdbcTemplate" p:dataSource-ref="hikariDSource"></bean>

	<!-- 配置数据源事务管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="hikariDSource"></property>
	</bean>
	
	<!-- 开启事务注解 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
3, add transaction annotation on the method need to use the Service layer affairs: @Transactional
  • ① a class @Transactional annotation comprising a modified method, the Spring Framework is automatically created proxy object class, default JDK created proxy object, by adding <aop: aspectj-autoproxy proxy-target-class = "true" /> Use CGLib create a proxy object, then you need to add aspectjweaver-xxxjar package.
  • ② can not use @Transactional annotation on the method protected, default or private, otherwise invalid.
    Here Insert Picture Description
4, compiled a test class to try:

Buy five "alive", if the transaction is not used, then, after performing "live" inventory is gone, but verify wallet balance when the balance is not found, an exception is thrown, the user's wallet and will not have any record orders Variety. but! We use transactions, and this time, the transaction capture to the operating table before the exception of the book will give the rollback, so the database will not change after this test code execution.

package cn.jingpengchong.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.jingpengchong.coupon.service.ICouponService;

public class Test {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("application.xml");

		ICouponService couponService = application.getBean(ICouponService.class);
		System.out.println(couponService.getClass().getName());
		String userId = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa";
		String bookId = "07f2c23d-5c44-4f42-9afc-27310e96e385";
		int count=5;
		boolean b = couponService.insert(userId, bookId, count);
		System.out.println(b);
		application.close();
	}
}

After executing the console to print a mistake, but did not change the data in the database:
Here Insert Picture Description

@Transactional注解属性:

1、rollbackFor和rollbackForClassName:

@Transactional默认不会捕获检查时异常,如果想要捕获检查时异常,需要用给该注解的rollbackFor或rollbackForClassName赋值,指定捕获哪种异常,例如,将自定义异常改为检查时异常后,将insert方法的下层方法的自定义检查时异常抛出(不能try-catch!!!),当抛给insert方法后,如果想要事务将该异常捕获然后回滚操作,注解需要写成下面的形式:(MoneyException是自定义的检查时异常)

@Transactional(rollbackFor = MoneyException.class)

或:

@Transactional(rollbackForClassName = "cn.jingpengchong.exception.MoneyException")
2、noRollbackFor和noRollbackForClassName:

@Transactional默认会捕获所有的运行时异常,然后进行回滚操作。但是当出现某些异常时并不需要回滚。此时就需要用到noRollbackFor 或 noRollbackForClassName 指定对哪些异常不回滚事务,例如出现类型转换异常时不执行回滚操作就需要这样写:

@Transactional(noRollbackFor = ClassCastException.class)

或:

@Transactional(noRollbackForClassName = "java.lang.ClassCastException")
3、readOnly:

将该属性值设置为true后,在该事务内只能进行读取操作,而不能进行数据库数据的修改,因此可以用该属性来保障数据库的数据安全,使用格式如下:

@Transactional(readOnly = true)
4、timeout:

该属性用来设置事务的最大存活时间(单位:秒),如果超过这个时间事务还没结束,那么将会抛出事务超时异常并执行回滚操作,例如设置事务的最大存活时间为5秒:

@Transactional(timeout = 5)
5、propagation:

该属性用来指定事务传播行为,一个事务方法被另一个事务方法调用时,必须指定事务应该如何传播,例如:方法可能继承在现有事务中运行,也可能开启一个新事物,并在自己的事务中运行。Spring定义了如下7种事务传播行为:
REQUIRED:默认值,如果有事务在运行,当前的方法就在这个事务内运行;
REQUIRES_NEW:当前方法启动新事务,并在它自己的事务内运行,如果有事务在运行,则把当前事务挂起,直到新的事务提交或者回滚才恢复执行;
SUPPORTS:如果有事务在运行,当前的方法就在这个事务内运行,否则以非事务的方式运行;
NOT_SUPPORTED:当前的方法不应该运行在事务中,如果有运行的事务,则将它挂起;
NEVER:当前方法不应该运行在事务中,否则将抛出异常;
MANDATORY(mandatory [ˈmændətɔːri] adj.强制的):当前方法必须运行在事务内部,否则将抛出异常;
NESTED(nest [nest] v.嵌套):如果有事务在运行,当前的方法在这个事务的嵌套事务内运行,否则就启动一个新的事务,并在它自己的事务内运行,此时等价于REQUIRED。注意:对于NESTED内层事务而言,内层事务独立于外层事务,可以独立递交或者回滚,如果内层事务抛出的是运行异常,外层事务进行回滚,内层事务也会进行回滚。
例如要在事务内新开一个事务,应该这样写:

@Transactional(propagation = Propagation.REQUIRES_NEW)
Published 128 original articles · won praise 17 · views 2730

Guess you like

Origin blog.csdn.net/qq_43705275/article/details/104210486