Spring5_05_事务
Spring5 事务
事务概念
- 什么是事务 - 事务是数据库操作最基本的单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败
- 典型场景:银行转账
 - lucy转账100元给mary
- lucy少100,mary多100
 
- 事务四个特性(ACID) - 原子性
- 一致性
- 隔离性
- 持久性
 
搭建事务操作环境
- 创建数据库表,添加数据 - 1 
 2
 3
 4
 5
 6- CREATE TABLE t_account(
 id VARCHAR(20),
 username VARCHAR(50),
 money VARCHAR(50))
 INSERT INTO t_account VALUES('1','lucy',1000)
 INSERT INTO t_account VALUES('2','mary',1000)
- 创建service,搭建dao,完成对象创建和注入关系 - service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入DataSource - 1 
 2
 3
 4
 5
 6
 7- @Service
 public class UserService {
 //注入dao
 @Autowired
 private UserDao userDao;
 }- 1 
 2
 3
 4
 5
 6- @Repository
 public class UserDaoImpl implements UserDao{
 @Autowired
 private JdbcTemplate jdbcTemplate;
 }
 
- 在dao创建两个方法,多钱和少钱的方法,在service创建方法(转账的方法) - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21- @Repository
 public class UserDaoImpl implements UserDao{
 @Autowired
 private JdbcTemplate jdbcTemplate;
 //少钱
 @Override
 public void reduceMoney() {
 String sql="update t_account set money=money-? where username=?";
 jdbcTemplate.update(sql,100,"lucy");
 }
 //多钱
 @Override
 public void addMoney() {
 String sql="update t_account set money=money+? where username=?";
 jdbcTemplate.update(sql,100,"mary");
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16- @Service
 public class UserService {
 //注入dao
 @Autowired
 private UserDao userDao;
 //转账的方法
 public void accountMoney(){
 //lucy少100
 userDao.reduceMoney();
 //mary多100
 userDao.addMoney();
 }
 }
- 上面代码,如果正常执行没有问题的,但是如果代码执行过程中出现异常,有问题 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- //转账的方法
 public void accountMoney(){
 //lucy少100
 userDao.reduceMoney();
 //模拟异常
 int i =10/0;
 //mary多100
 userDao.addMoney();
 }
 }
 //结果lucy少了100,而mary并没有增加100- 上面问题如何解决呢 - 使用事务进行解决
 
- 事务操作 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21- //转账的方法
 public void accountMoney(){
 try {
 //第一步 开启事务
 
 //第二步进行业务操作
 //lucy少100
 userDao.reduceMoney();
 
 //模拟异常
 int i = 10 / 0;
 
 //mary多100
 userDao.addMoney();
 
 //第三步 没有发生异常,提交事务
 }catch (Exception e){
 
 //第四步 出现异常,事务回滚
 
 }
 
Spring 事务管理介绍
- 事务添加到JavaEE三层结构里面Service层(业务逻辑层) 
- 在Spring进行事务管理操作 - 有两种方式:编程式事务管理和声明式事务管理(使用)
 
- 声明式事务管理 - 基于注解方式(使用)
- 基于xml配置文件方式
 
- 在Spring进行声明式事务管理,底层使用AOP 
- Spring事务管理API - 提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
 
注解声明式事务管理
- 在Spring:配置文件配置事务管理器 - 1 
 2
 3
 4
 5- <!--创建事务管理器-->
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 <!--注入数据源-->
 <property name="dataSource" ref="dataSource"></property>
 </bean>
- 在Spring配置文件,开启事务注解 - 在Spring配置文件引入名称空间tx - 1 
 2
 3
 4
 5
 6
 7
 8
 9- <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">
- 开启事务注解 - 1 
 2- <!--开启事务注解-->
 <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
- 在service类上面(获取service类里面方法上面)添加事务注解 - @Transactional,这个注解添加到类上面,也可以添加到方法上面
- 如果把这个注解添加到类上面,这个类里面的所有的方法都添加事务
- 如果把这个注解添加到方法上面,为这个方法添加事务
 
 - 1 
 2
 3
 4- @Service
 @Transactional
 public class UserService {
 }
经测试,虽然发生异常,但是事务回滚,lucy和mary的金额仍然是1000
注解声明式事务管理参数配置
- 在service类上面添加注解@Transactiona,在这个注解里面可以配置事务相关参数 
propagation:事务传播行为
- 多事务方法直接进行调用,这个过程中事务是如何进行管理的 
事务的传播行为可以由传播属性指定。Spring定义了7种类传播行为
| 传播属性 | 描述 | 
|---|---|
| REQUIRED | 如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事物,并在自己的事务内运行 | 
| REQUIRED_NEW | 当前的方法必须启动新事物,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起 | 
| SUPPORTS | 如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中 | 
| NOT_SUPPROTS | 当前的方法不应该运行在事务中,如果有运行的事务,将它挂起 | 
| MANDATORY | 当前的方法必须运行在事物内部,如果没有正在运行的事务,就抛出异常 | 
| NEVER | 当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常 | 
| NESTED | 如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行。否则,就启动一个新的事务,并在它自己的事务内运行 | 
| 1 |  | 
isolation:事务隔离级别
- 事务有特性称为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题 
- 有三个读的问题:脏读、不可重复读、幻读 - 脏读(dirty read):当一个事务读取另一个事务尚未提交的改变时,产生脏读 
- 不可重复读(nonrepeatable read):同一个查询再同一事务中多次进行,由于其他提交事务所做的修改或删除操作,每次返回不同的结果集,此时发生不可重复读。 
- 幻读(phantom read):同一个查询再同一事务中多次进行,由于其他提交事务的插入操作,每次返回不同的结果集,此时发生幻读。 
 
- 通过设置事务隔离性,解决读问题 - 脏读 - 不可重复度 - 幻读 - READ UNCOMMITTED(读未提交) - 有 - 有 - 有 - READ COMMITTED(读已提交) - 无 - 有 - 有 - REPEATABLE READ(可重复读) - 无 - 无 - 有 - SERIALIZABLE(串行化) - 无 - 无 - 无 - 1 
 2
 3
 4- @Service
 @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
 public class UserService {
 }
timeout:超时时间
- 事务需要在一定时间内提交,如果不提交进行回滚
- 默认值是-1,设置时间以秒为单位进行计算
| 1 |  | 
readOnly:是否只读
- 读:查询操作,写:添加修改删除操作
- readOnly默认值false,表示可以查询,可以添加修改删除操作
- 设置readOnly值是true,设置成true之后,只能查询
| 1 |  | 
rolibackFor:回滚
- 设置出现哪些异常进行事务回滚
noRollbackFor:不回滚
- 设置出现哪些异常不进行事务回滚
XML声明式事务管理(了解)
- 在Spring配置文件中进行配置 - 配置事务管理器
- 配置通知
- 配置切入点和切面
 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22- <!--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:method name="account*"/>-->
 </tx:attributes>
 </tx:advice>
 <!--3 配置切入点和切面-->
 <aop:config>
 <!--配置切入点-->
 <aop:pointcut id="pt" expression="execution(* com.company.spring5.service.UserService.*(..))"/>
 <!--配置切面-->
 <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
 </aop:config>
完全注解开发
- 创建配置类,使用配置类代替xml配置文件 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34- @Configuration//配置类
 @ComponentScan(basePackages = "com.company")//组件扫描
 @EnableTransactionManagement//开启事务
 public class TxConfig {
 //创建数据库连接池
 @Bean
 public DruidDataSource getDruidDataSource(){
 DruidDataSource dataSource = new DruidDataSource();
 dataSource.setDriverClassName("com.mysql.jdbc.Driver");
 dataSource.setUrl("jdbc:mysql:///user_db");
 dataSource.setUsername("root");
 dataSource.setPassword("hsp");
 return dataSource;
 }
 //Jdbc模板对象
 @Bean
 public JdbcTemplate getJdbcTemplate(DataSource dataSource){
 //到ioc容器中根据类型找到dataSource
 JdbcTemplate jdbcTemplate = new JdbcTemplate();
 //注入dataSource
 jdbcTemplate.setDataSource(dataSource);
 return jdbcTemplate;
 }
 //创建事务事务管理器
 @Bean
 public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
 DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
 transactionManager.setDataSource(dataSource);
 return transactionManager;
 }
 }- 测试 - 1 
 2
 3
 4
 5
 6
 7
 8
 9- @Test
 public void testAccount3(){
 ApplicationContext context =
 new AnnotationConfigApplicationContext(TxConfig.class);
 
 UserService userService = context.getBean("userService", UserService.class);
 userService.accountMoney();
 
 }- 参考:https://frxcat.fun/ 












