Spring事物与传播性

版权声明:转载请注明出处 https://blog.csdn.net/chenmingxu438521/article/details/90759088

一、什么是事物

1.说白了就是保证数据的一致性。

2.事务的特性:

2.1.原子性:要么全部成功,要么全部失败,不可再分。

2.2.一致性:例如,A用户5000元,B用户0元,转账之后B用户5000元,A用户0元,A+B总和不变为5000元。

2.3.隔离性:多个事务之间互不影响。

2.4.持久性

二、事务的分类

1.编程式事务:手动事务就是自己begin,commit。

2.声明式事务:基于xml和注解@transactional

三、环境搭建(我使用的是springboot环境)

1.项目结构

2.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.5.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.ysfj</groupId>
	<artifactId>transactiondemo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>transactiondemo</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
		<dependency>
			<groupId>com.mchange</groupId>
			<artifactId>c3p0</artifactId>
			<version>0.9.5.2</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.37</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

3.spring.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:context="http://www.springframework.org/schema/context"
	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.xsd">
	<bean id="userDao" class="com.ysfj.transactiondemo.dao.UserDao"></bean>
	<bean id="userSerivce" class="com.ysfj.transactiondemo.service.UserService">
		<property name="userDao" ref="userDao"></property>
	</bean>
	<!-- 扫描包范围 -->
	<context:component-scan base-package="com.ysfj.transactiondemo"></context:component-scan>
	<!-- 1. 数据源对象: C3P0连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test1"></property>
		<property name="user" value="root"></property>
		<property name="password" value="123456"></property>
	</bean>
	<!-- 2. JdbcTemplate工具类实例 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 配置事物 -->
	<bean id="dataSourceTransactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
</beans>

4.db.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:context="http://www.springframework.org/schema/context"
	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.xsd">
	<!-- 开启注解 -->
	<context:component-scan base-package="com.ysfj.transactiondemo"></context:component-scan>
	<!-- 1. 数据源对象: C3P0连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test1"></property>
		<property name="user" value="root"></property>
		<property name="password" value="123456"></property>
	</bean>
	<!-- 2. JdbcTemplate工具类实例 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 配置事物 -->
	<bean id="dataSourceTransactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
</beans>   

5.UserService.java

@Service
public class UserService {

	@Resource(name = "userDao02")
	private UserDao userDao;

	public void add() {
		System.out.println(" userService02 add...");
		userDao.add("chenmingxu", 18);
	}

	public UserDao getUserDao() {

		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		System.out.println("setUseDao");
		this.userDao = userDao;
	}
}

6.UserDao.java

@Repository("userDao02")
public class UserDao {

	@Autowired
	private JdbcTemplate jdbcTemplate;

	public void add(String name, Integer age) {
		String sql = "INSERT INTO users(NAME, age) VALUES(?,?);";
		int update = jdbcTemplate.update(sql, name, age);
		System.out.println("数据库添加user成功..insert:" + update);
	}
	public void add() {
		System.out.println("userDao002 add....");
	}
}

7.SpringTest001.java

public class SpringTest001 {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("db.xml");
		UserService userService = (UserService) app.getBean("userService");
		userService.add();
	}
}

8.建表语句

DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `NAME` varchar(20) DEFAULT NULL,
  `age` int(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

9.结果(成功插入数据库一条消息)

四、编程式事务(手动事物)

1.原理:获取到该数据源的api,数据源api中会自动封装手动begin,commit,rollback.

2.项目结构

3.TranscationUtils.java

@Component
public class TransactionUtils {
    //拿到事务管理器
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;
    //开启事务
    public TransactionStatus begin(){
        TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionDefinition());
        return transaction;
    }
    //提交事物
    public void commit(TransactionStatus transaction){
        dataSourceTransactionManager.commit(transaction);
    }
    //回滚事物
    public void rollback(TransactionStatus transaction){
        dataSourceTransactionManager.rollback(transaction);
    }
}

4.在UserService.java中添加事物

//默认注入容器 id userService
@Service
public class UserService {

	@Resource(name = "userDao02")
	private UserDao userDao;

	//注入事物
	@Autowired
	private TransactionUtils transactionUtils;

	public void add() {
		System.out.println(" userService02 add...");
		TransactionStatus begin=null;
		try {
			begin = transactionUtils.begin();
			userDao.add("chenmingxu", 18);
			int i = 1/0;
			//这样写报异常之后就不走commit()了,要回滚事物
			transactionUtils.commit(begin);
		}catch (Exception e){
			e.printStackTrace();
			//事物一旦开启要释放,不然会报错,一个提交,一个回滚
			transactionUtils.rollback(begin);
		}
	}
	public UserDao getUserDao() {
		return userDao;
	}
	public void setUserDao(UserDao userDao) {
		System.out.println("setUseDao");
		this.userDao = userDao;
	}
}

5.数据库情况

五、声明事物管理(xml或者注解,AOP管理事物)

1.基于AOP的事物管理(使用声明式事物方法一定不要try,将异常抛出去),声明事物原理:AOP编程+环绕通知+异常通知

1.1.项目结构(maven,上面用springboot没有测试出来就改用maven了)

1.2.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.tydic</groupId>
  <artifactId>transactiondemo1</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>transactiondemo1 Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>
  <dependencies>
    <!-- 引入Spring-AOP等相关Jar -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>3.0.6.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>3.0.6.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>3.0.6.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>3.0.6.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.6.1</version>
    </dependency>
    <dependency>
      <groupId>aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.5.3</version>
    </dependency>
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>2.1_2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.37</version>
    </dependency>
  </dependencies>
</project>

1.3.spring.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"
	   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.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
	<bean id="userDao" class="com.tydic.dao.UserDao"></bean>
	<bean id="userSerivce" class="com.tydic.service.UserService">
		<property name="userDao" ref="userDao"></property>
	</bean>
	<!-- 扫描包范围 -->
	<context:component-scan base-package="com.tydic"></context:component-scan>
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
	<!-- 切面类 -->
	<bean id="aop" class="com.tydic.Aop2"></bean>

	<!-- Aop配置 -->
	<aop:config>
		<!-- 定义一个切入点表达式: 拦截哪些方法 -->
		<aop:pointcut expression="execution(* com.tydic.service.*.*(..))"
					  id="pt" />
		<!-- 切面 -->
		<aop:aspect ref="aop">
			<!-- 环绕通知 -->
			<aop:around method="around" pointcut-ref="pt" />
			<!-- 前置通知: 在目标方法调用前执行 -->
			<aop:before method="begin" pointcut-ref="pt" />
			<!-- 后置通知: -->
			<aop:after method="after" pointcut-ref="pt" />
			<!-- 返回后通知 -->
			<aop:after-returning method="afterReturning"
								 pointcut-ref="pt" />
			<!-- 异常通知 -->
			<aop:after-throwing method="afterThrowing"
								pointcut-ref="pt" />
		</aop:aspect>
	</aop:config>
	<!-- 1. 数据源对象: C3P0连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test1"></property>
		<property name="user" value="root"></property>
		<property name="password" value="123456"></property>
	</bean>
	<!-- 2. JdbcTemplate工具类实例 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 配置事物 -->
	<bean id="dataSourceTransactionManager"
		  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
</beans>

1.4.TransactionUtils.java

@Component
public class TransactionUtils {
    //拿到事务管理器
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;
    //开启事务
    public TransactionStatus begin(){
        TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionDefinition());
        return transaction;
    }
    //提交事物
    public void commit(TransactionStatus transaction){
        dataSourceTransactionManager.commit(transaction);
    }
    //回滚事物
    public void rollback(TransactionStatus transaction){
        dataSourceTransactionManager.rollback(transaction);
    }
}

1.5.AOP2.java

//定义切面
//注入Spring容器
public class Aop2 {

	@Autowired
	private TransactionUtils transactionUtils;

	private TransactionStatus begin;

	public void begin() {
		// System.out.println("......前置通知......");
	}

	public void after() {
		// System.out.println(".......后置通知......");
	}

	public void afterReturning() {
		// System.out.println(".......运行通知......");
	}

	public void afterThrowing() {
		System.out.println(".......异常通知......");
		transactionUtils.rollback(begin);
	}

	public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
		begin = transactionUtils.begin();
		System.out.println("我是环绕通知-前");
		// 放行   实际方法
		proceedingJoinPoint.proceed();
		System.out.println("我是环绕通知-后");
		transactionUtils.commit(begin);
	}
}

1.6.UserService.java(调用的是add01()方法)

@Service
public class UserService {

	@Resource(name = "userDao02")
	private UserDao userDao;

	//注入事物
	@Autowired
	private TransactionUtils transactionUtils;

	public void add() {
		System.out.println(" userService02 add...");
		TransactionStatus begin=null;
		try {
			begin = transactionUtils.begin();
			userDao.add("chenmingxu", 18);
			//int i = 1/0;
			//这样写报异常之后就不走commit()了,要回滚事物
			transactionUtils.commit(begin);
		}catch (Exception e){
			e.printStackTrace();
			//事物一旦开启要释放,不然会报错,一个提交,一个回滚
			//transactionUtils.rollback(begin);
		}
	}
	public void add01() {
		System.out.println(" userService02 add...");
		userDao.add("chenmingxu", 18);
		int i = 1/0;
	}

	public UserDao getUserDao() {
		return userDao;
	}
	public void setUserDao(UserDao userDao) {
		System.out.println("setUseDao");
		this.userDao = userDao;
	}
}

1.7.SpringTest002.java

public class SpringTest002 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = (UserService) app.getBean("userService");
        userService.add01();
    }
}

1.8.数据库结果(还是一条结果),这样事物就交给了AOP去管理了

2.基于xml的事物管理(使用声明式事物方法一定不要try,将异常抛出去),声明事物原理:AOP编程+环绕通知+异常通知

2.1.项目结构

2.2.transaction-spring.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.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
	<bean id="userDao" class="com.tydic.dao.UserDao"></bean>
	<bean id="userSerivce" class="com.tydic.service.UserService">
		<property name="userDao" ref="userDao"></property>
	</bean>
	<!-- 扫描包范围 -->
	<context:component-scan base-package="com.tydic"></context:component-scan>
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>


	<!-- 1. 数据源对象: C3P0连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test1"></property>
		<property name="user" value="root"></property>
		<property name="password" value="123456"></property>
	</bean>
	<!-- 2. JdbcTemplate工具类实例 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<!-- 配置事物 -->
	<bean id="dataSourceTransactionManager"
		  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!--事物管理器-->
	<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
		<tx:attributes>
			<!--get*,find*不需要事物的-->
			<tx:method name="get*" read-only="true" />
			<tx:method name="find*" read-only="true" />
			<tx:method name="*" read-only="false" />
		</tx:attributes>
	</tx:advice>
	<!-- Aop配置: 拦截哪些方法(切入点表表达式) + 应用上面的事务增强配置 -->
	<aop:config>
		<aop:pointcut expression="execution(* com.tydic.service.*.*(..))"
					  id="pt" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pt" />
	</aop:config>
</beans>

2.3.UserService.java

@Service
public class UserService {

	@Resource(name = "userDao02")
	private UserDao userDao;

	//注入事物
	@Autowired
	private TransactionUtils transactionUtils;

	public void add() {
		System.out.println(" userService02 add...");
		TransactionStatus begin=null;
		try {
			begin = transactionUtils.begin();
			userDao.add("chenmingxu", 18);
			//int i = 1/0;
			//这样写报异常之后就不走commit()了,要回滚事物
			transactionUtils.commit(begin);
		}catch (Exception e){
			e.printStackTrace();
			//事物一旦开启要释放,不然会报错,一个提交,一个回滚
			//transactionUtils.rollback(begin);
		}
	}
	public void add01() {
		System.out.println(" userService02 add...");
		userDao.add("chenmingxu", 18);
		int i = 1/0;
	}
	public void add02() {
		System.out.println(" userService02 add...");
		userDao.add("chenmingxu", 18);
		int i = 1/0;
	}

	public UserDao getUserDao() {
		return userDao;
	}
	public void setUserDao(UserDao userDao) {
		System.out.println("setUseDao");
		this.userDao = userDao;
	}
}

2.4.SpringTest003.java

public class SpringTest003 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("transaction-spring.xml");
        UserService userService = (UserService) app.getBean("userService");
        userService.add02();
    }
}

2.5.数据库结果

总结:这样也是可以回滚事物的,不会添加到数据中的,避免在业务逻辑层try,原理就和声明式事物AOP一样了(切记)

六、基于注解的事物管理(使用声明式事物方法一定不要try,将异常抛出去),声明事物原理:AOP编程+环绕通知+异常通知

1.项目结构图

2.transaction.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.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
	<bean id="userDao" class="com.tydic.dao.UserDao"></bean>
	<bean id="userSerivce" class="com.tydic.service.UserService">
		<property name="userDao" ref="userDao"></property>
	</bean>
	<!-- 扫描包范围 -->
	<context:component-scan base-package="com.tydic"></context:component-scan>
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>


	<!-- 1. 数据源对象: C3P0连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test1"></property>
		<property name="user" value="root"></property>
		<property name="password" value="123456"></property>
	</bean>
	<!-- 2. JdbcTemplate工具类实例 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<!-- 配置事物 -->
	<bean id="dataSourceTransactionManager"
		  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!--开启注解-->
	<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
</beans>

3.UserService.java

package com.tydic.service;

import com.tydic.TransactionUtils;
import com.tydic.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

//默认注入容器 id userService
@Service
public class UserService {

	@Resource(name = "userDao02")
	private UserDao userDao;

	//注入事物
	@Autowired
	private TransactionUtils transactionUtils;

	public void add() {
		System.out.println(" userService02 add...");
		TransactionStatus begin=null;
		try {
			begin = transactionUtils.begin();
			userDao.add("chenmingxu", 18);
			//int i = 1/0;
			//这样写报异常之后就不走commit()了,要回滚事物
			transactionUtils.commit(begin);
		}catch (Exception e){
			e.printStackTrace();
			//事物一旦开启要释放,不然会报错,一个提交,一个回滚
			//transactionUtils.rollback(begin);
		}
	}
	public void add01() {
		System.out.println(" userService02 add...");
		userDao.add("chenmingxu", 18);
		int i = 1/0;
	}
	public void add02() {
		System.out.println(" userService02 add...");
		userDao.add("chenmingxu", 18);
		int i = 1/0;
	}
	@Transactional//出错帮你回滚
	public void add03() {
		System.out.println(" userService02 add...");
		userDao.add("chenmingxu", 18);
		int i = 1/0;
	}

	public UserDao getUserDao() {
		return userDao;
	}
	public void setUserDao(UserDao userDao) {
		System.out.println("setUseDao");
		this.userDao = userDao;
	}
}

4.测试类

public class SpringTest004 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("transaction.xml");
        UserService userService = (UserService) app.getBean("userService");
        userService.add03();
    }
}

5.测试结果

七、事物的传播行为

1.什么是事物的传播行为:通俗的说就是事物传递给内部调用的方法。

2.事物传播行为种类

  • PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择(都有事物,用当前两个表都会回滚)。
  • PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
  • PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。 
  • PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起(log表中不会回滚)。 
  • PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 
  • PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

3.项目结构图

4.LogDao.java

@Repository
public class LogDao {
	@Autowired
	private JdbcTemplate jdbcTemplate;

	public void addLog() {
		jdbcTemplate.update("insert into log values (NULL ,'"+System.currentTimeMillis()+"');");
		System.out.println("addlog添加完毕!");
	}
}

5.LogService.java

@Service
public class LogService {
	@Autowired
	private LogDao logDao;

	@Transactional(propagation = Propagation.REQUIRED)
	public void addLog() {
		logDao.addLog();
	}
}

6.UserService.java

@Transactional(propagation=Propagation.REQUIRED)
	public void add03() {
		logService.addLog();
		System.out.println(" userService02 add...");
		userDao.add("chenmingxu", 18);
		int i = 1/0;
	}

7.SpringTest004.java

public class SpringTest004 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("transaction.xml");
        UserService userService = (UserService) app.getBean("userService");
        userService.add03();
    }
}

7.建表语句

DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `NAME` varchar(20) DEFAULT NULL,
  `age` int(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `log`;
CREATE TABLE `log` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `log` mediumtext,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

 8.根据实际的情况可以选择事物的传播性

八、总结

整理了三天,终于整理完了,有不懂的欢迎评论留言!!!

猜你喜欢

转载自blog.csdn.net/chenmingxu438521/article/details/90759088
今日推荐