Spring事务看这一篇就够了!!(Spring事务特征+Spring事务管理+实现+Spring七种事务传播行为+集成MyBatis)
Posted Lotus_dong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring事务看这一篇就够了!!(Spring事务特征+Spring事务管理+实现+Spring七种事务传播行为+集成MyBatis)相关的知识,希望对你有一定的参考价值。
Spring事务管理
事务可以看做是数据库的若干操作组成的一个单元。
我们在开发企业级应用时,用户的一个操作实际却是对数据读写多步操作的结合。由于数据操作在顺序执行中,任何一步都有可能发生异常,导致后续的操作无法完成,此时由于业务逻辑全部完成,之前操作的数据并不可靠,需要在这种情况下进行回退(回滚),将数据恢复到用户操作之前。
事务的作用就是为了保证用户的每一个操作都是可靠的,事务的每一步操作都必须完成,只要发生异常就回退到事务未开始操作的状态,这些操作要么全部完成,要么全部取消,从而保证数据满足一致性的要求。
Spring事务特征ACID
原子性(Atomicity):强调事务的不可分割性。
一致性(Consistency):事务的执行前后数据完整性保持一致。
隔离性(Isolation):一个事务在执行中不会受到其它事务的影响。
持久性(Durability):事务一旦结束,数据变化会持久到数据库。
Spring事务管理形式
1.编程式事务,这类事务管理形式在项目中很少使用,这种方式需要注入一个事务管理对象TransactionTemplate,然后再我们的代码中需要提交事务或回滚事务时由我们自己写代码实现。
2.声明式事务:这类事务管理建立在AOP的基础上,本质式对方法前后进行切面式的拦截,所以声明式事务是方法级别的。声明式事务管理方式有两种:分别是基于xml配置实现和基于注解的方式实现。
Spring事务管理的实现
由于事务是数据库的操作集合,因此我们对事务的管理都是基于数据库源操作的。
1.配置数据库源
(1)在pom.xml中导入Spring-jdbc的相关jar包,这里我们使用阿里的德鲁伊数据库源
<!--Spring管理的JDBC-->
<!-- spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<!--这里以mysql为例,故导入MySql驱动包-->
<!-- mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!-- 阿里数据源 数据库链接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
(2)在Spring文件中配置数据库源,将数据库源交给spring进行管理
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启Spring注解扫描-->
<context:component-scan base-package="com.cwd.spring6pro.demo1"> </context:component-scan>
<!--配置DruidDataSource交给spring容器管理,spring管理数据库链接(数据源)-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis_db?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai"></property>
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
</beans>
2.配置事务管理器
Spring针对不同的dao框架,提供了不同的实现类,JDBC和MyBtais的事务管理实现类是DataSourceTransactionManager。
配置spring事务管理器,并注入数据源。
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
3.基于xml配置实现
(1)配置事务传播行为
<!--配置事务的传播行为-->
<tx:advice id="txadvice" transaction-manager="dataSourceTransactionManager">
<tx:attributes>
<!--
name:所有save开头的方法
propagation:事务传播行为
-->
<tx:method name="save*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
(2)基于aop为不同的类和方法开启事务管理,aop部分不了解的可以看SpringAOP(面向切面编程)
<!--织入-->
<aop:config>
<!--连接点-->
<aop:pointcut expression="execution(* com.cwd.spring6pro.demo1.dao.UserDao.*(..))" id="allmethod"/>
<!--
advice-ref:引入配置好的事务传播行为
pointcut-ref:需要事务管理的类或方法
-->
<aop:advisor advice-ref="txadvice" pointcut-ref="allmethod"/>
</aop:config>
4.基于注解方式实现
(1)在配置好事务管理器后,开启注解事务管理。
<!--开始注解事务管理-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"></tx:annotation-driven>
(2)在service层中通过注解控制事务
import com.cwd.spring6pro.demo1.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service(value = "userService")
@Transactional(propagation = Propagation.REQUIRED)
//@Transactional注解如果使用在类名上,那么这个类的所有方法都在事务中运行,也可以在方法上
public class UserService {
@Autowired//注入注解
private UserDao userDao;
public void UserSave() {
userDao.saveUser();
}
public void saveAdd() {
userDao.save();
userDao.add();
}
}
Spring事务传播行为
什么是事务传播行为?
即然是传播,那么至少有两个东西才可以产生传播。单体是不存在传播的。事务传播行为(Propagation Behavior)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何继续进行。事务传播行为是Spring框架独有的事务增强特性,它不属于事务的实际提供方行为,即不属于数据库行为。
举个例子,方法A事务调用方法B事务时,方法B是在方法A的事务中运行呢?还是自己新开一个事务运行呢?这就由方法B的事务传播行为决定。
七种传播行为
我们使用传播行为有两种方式,一种是基于xml配置,一种是注解方式:
· 基于xml配置
<!--配置事务的传播行为-->
<tx:advice id="txadvice" transaction-manager="dataSourceTransactionManager">
<tx:attributes>
<!--
name:所有save开头的方法
propagation:事务传播行为
-->
<tx:method name="save*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
· 基于注解方式
@Transactional(propagation = Propagation.REQUIRED)//事务传播行为
public class XXX{}
1.PROPAGATION_REQUIRED
指定的方法必须在事务内执行,若当前存在事务,就加入到当前事务中,若当前没有事务,则自行创建一个新的事务,这种传播行为是最常见的,也是Spring框架默认的传播行为。
2.PROPAGATION_SUPPORTS
如果方法A调用方法B时,方法B配置了此传播行为,方法A有事务时,方法B就加入方法A的事务,如果方法A没有事务,方法B就以非事务的方式执行。
3.PROPAGATION_REQUIRES_NEW
总是新建一个事务,如果当前已经存在了一个事务,就把当前事务挂起,直到新建事务的结束。
4.PROPAGATION_MANDATORY
总是加入到当前事务,如果当前没有事务,就会抛出异常
5.PROPAGATION_NOT_SUPPORTED
总是以非事务的方式执行操作,如果当前存在一个事务,就把当前事务挂起。
6.PROPAGATION_NEVER
总是以非事务的方式执行操作,如果当前存在一个事务,就抛出异常。
7.PROPAGATION_NESTED
如果当前存在事务,则在嵌套的事务内执行。如果当前没有事务,就自行创建一个事务。
Spring集成MyBatis
关于MyBtais的学习,这里推荐几篇文章:
1.一篇文章告诉你什么是Mybatis+Mybatis的搭建及使用
3.详解MyBatis查询结果处理(简单类型,POJO,resultMap输出映射)
4.MyBatis多表关联查询处理结果集、懒加载、association(一对一)、collection(一对多)、案例详解
5.MyBtais动态sql和特殊符号处理(案例集锦:不定条件查询+模糊查询+批量查询+批量删除…)
6.MyBatis缓存看这一篇就够了(一级缓存+二级缓存+缓存失效+缓存配置+工作模式+测试)
详细步骤
Spring集成MyBtais的核心操作就是将SqlSessionFactory交给Spring进行管理,并由Spring管理对dao接口的代理实现。
1.导入MyBatis的相关jar
Spring结合MyBatis插件包
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
<!--spring-mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
2.配置SqlSessionFactory
由于上面文章中事务那一部分已经配置好了数据库源如下所示,因此这里我们就直接使用。
(1)数据库源
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启Spring注解扫描-->
<context:component-scan base-package="com.cwd.spring6pro.demo1"> </context:component-scan>
<!--配置DruidDataSource交给spring容器管理,spring管理数据库链接(数据源)-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis_db?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai"></property>
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
</beans>
(2)配置SqlSessionFactory
<!--spring管理SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--注入数据库源-->
<property name="dataSource" ref="dataSource"></property>
<!--导入mybatis全局配置文件-->
<property name="configLocation" value="MyBatisConfig.xml"></property>
<!--扫描所有的映射文件-->
<property name="mapperLocations" value="mapper/*Mapper.xml"> </property>
</bean>
3.指定生成代理接口
<!--扫描Dao中的所有接口并生成接口的代理对象-->
<bean id="mapperFactory" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.cwd.springmybatis"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
4.使用
我们此时就可以在Service中直接注入Dao的代理对象,此接口由Spring代理实现。
package com.cwd.ssm.service;
import com.cwd.ssm.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class UserService {
@Autowired
UserDao userDao;
}
以上是关于Spring事务看这一篇就够了!!(Spring事务特征+Spring事务管理+实现+Spring七种事务传播行为+集成MyBatis)的主要内容,如果未能解决你的问题,请参考以下文章
超详细的Spring框架总结,学spring,看这一篇就够了!
Spring Boot 2.x(十四):整合Redis,看这一篇就够了