Spring 事务操作
一、事务(概念)
1. 什么是事务
- 事务是数据库的最基本单元,逻辑上的一组操作,要么都成功,如果有一个失败,那么所有的操作都失败
- 典型场景:
- lucy转账100元给mary
- lucy少100元,mary多100元
2. 事务的四个特性(ACID)
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
二、事务操作
1. Spring事务管理介绍
-
事务添加到JavaEE三层结构里面Service层(业务逻辑层)
-
在Spring进行事务管理操作
- 编程式事务管理:就是在代码中编写代码,手动开启事务
- 声明式事务管理:面向切面配置事务,开启事务
-
声明式事务管理
- 基于注解方式(使用)
- 基于xml配置文件方式
-
在Spring进行声明式事务管理,底层使用AOP原理
-
Spring事务管理API
-
提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
-
2. 注解声明式事务管理
-
在Spring配置文件配置事务管理器
<!-- 创建事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 注入数据源 --> <property name="dataSource" ref="dataSource"></property> </bean>
-
在Spring配置文件,开启事务注解
-
在spring配置文件引入名称空间tx
<?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 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">
-
开启事务注解
<!-- 开启事务注解 --> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
-
-
在service类上面(或者service类里面的方法上面)添加事务注解
-
@Transaction,这个注解添加到类上面,也可以添加方法上面
-
如果把这个注解添加到类上面,这个类里面多有的方法都添加事务
-
如果把这个注解添加到方法上面,那么只是为这个方法添加事务
@Service @Transaction public class UserService { ... }
-
3. 声明式事务管理参数配置
-
在service类声明添加注解@Transaction,这个注解里面可以配置事务相关参数
-
propagation:事务传播行为
-
**事务传播行为:**多事务方法直接进行调用,这个过程中事务是如何进行管理的
-
事务方法:对数据库表的书籍进行变化的操作
-
Spring框架事务传播行为有7种,重点掌握
REQUIRED
和REQUIRES_NEW
-
REQUIRED:如果add方法本身有事务,调用update方法后,update使用当前add方法里面的事务;如果add方法本身没有事务,那么调用update方法之后,创建新事务
-
REQUIRES_NEW:使用add方法调用update方法,无论add方法是否有事务,update都要创建新事务,如果add方法的事务正在运行,那么update方法的事务要先挂起
-
-
-
isolation:事务隔离级别
- 事务有特性成为隔离性,多事务之间操作不会产生影响。如果不考虑隔离性则会产生很多问题
- 有三个问题:脏读、不可重复读、幻读
- 脏读:在一个事务种读取到另一个未提交事务的数据
- **不可重复读:**在一个事务中,两次查询到的结果不一致(针对update操作)
-
**幻读:**在一个事务种,两次查询到的结果不一致(针对insert操作)
-
如何解决这些问题?
-
通过设置事务隔离级别,解决读问题
-
SQL标准的事务隔离级别包括:读未提交、读提交、可重复读(MySQL中默认)、串行化
- 读未提交:一个事务还没提交时,它做的变更就能被别的事务看到
- 读已提交:一个事务提交之后,它做的变更才能被其他事务看到
- 可重复读:一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的
- 串行化:对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出像读写锁冲突时候,后访问的事务必须等前一个事务执行完成,才能继续执行
-
-
timeout:超时时间
- 事务需要在一定的时间内进行提交,如果不提交则进行回滚
- 默认值是-1,设置时间以秒单位进行计算
-
readOnly:是否只读
- 读:查询操作 写:添加、修改、删除
- readOnly默认值是false,表示可以读,也可以写
- readOnly设置成true,只能进行读操作,即查询
-
rollbaclFor:回滚
- 设置出现哪些异常进行事务回滚
-
noRollbackFor:不回滚
- 设置出现哪些异常不进行事务回滚
4. XML声明式事务管理
-
在Spring配置文件中进行配置
-
配置事务管理器
<!-- 1. 创建事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
-
配置通知
<!-- 2. 配置通知 --> <tx:advice id="txadvice"> <!-- 配置事务参数 --> <tx:attributes> <tx:method name="accountMoney" propagation="REQUIRED"/> </tx:attributes> </tx:advice>
-
配置切入点和切面
<!-- 3. 配置切入点和切面 --> <aop:config> <!-- 配置切入点 --> <aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/> <!-- 配置切面 --> <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/> </aop:config>
-
5. 完全注解声明式事务管理
-
创建配置类
@Configuration // 配置类 @ComponentScan(basePackages = "com.atguigu") // 开启组件扫描 @EnableTransactionManagement // 开启事务 public class TxConfig { @Bean public DruidDataSource getDruidDataSource() { DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName("com.mysql.jdbc.Driver"); druidDataSource.setUrl("jdbc:mysql://localhost:3306/spring"); druidDataSource.setUsername("root"); druidDataSource.setPassword("root"); return druidDataSource; } // 创建JdbcTemplate对象 @Bean(value = "jdbcTemplate") public JdbcTemplate getJdbcTemplate(DataSource dataSource) { JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } // 创建事务管理器 @Bean public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) { DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); dataSourceTransactionManager.setDataSource(dataSource); return dataSourceTransactionManager; } }