• Spring5 框架 ---- 事务操作


    1. 事务概念

    1. 什么是事务

    1. 事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个操作失败,那么所有操作都将失败。
    2. 典型应用场景:银行转账

    2. 事务的四个特性(ACID)

    1. 原子性:不可分割
    2. 一致性:操作之前和操作之后总量不变
    3. 隔离性:多事务操作时,每个事务之间相互独立
    4. 持久性:事务提交之后,数据发生变化

    2. 搭建事务操作环境

    在这里插入图片描述

    1. 创建数据库表,添加记录

    在这里插入图片描述

    2. 创建service,搭建dao,完成对象创建和注入关系

    service 注入 dao,在 dao 注入 JdbcTemplate,在 JdbcTemplate 注入 DataSource

    package com.fickler.spring5.service;
    
    import com.fickler.spring5.dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    /**
     * @author dell
     * @version 1.0
     */
    
    @Service
    public class UserService {
    
        //注入dao
        @Autowired
        private UserDao userDao;
    
    }
    
    
    package com.fickler.spring5.dao;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;
    
    /**
     * @author dell
     * @version 1.0
     */
    
    @Repository
    public class UserDaoImpl implements UserDao{
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
    }
    
    

    3. 在dao创建两个方法:多钱和少钱的方法,在service创建方法(转账的方法)

    package com.fickler.spring5.dao;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;
    
    /**
     * @author dell
     * @version 1.0
     */
    
    @Repository
    public class UserDaoImpl implements UserDao{
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public void addMoney() {
    
            String sql = "update t_account set money = money - ? where username = ?";
            jdbcTemplate.update(sql, 100, "lucy");
    
        }
    
        @Override
        public void reduceMoney() {
    
            String sql = "update t_account set money = money + ? where username = ?";
            jdbcTemplate.update(sql, 100, "mary");
    
        }
    }
    
    
    package com.fickler.spring5.service;
    
    import com.fickler.spring5.dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    /**
     * @author dell
     * @version 1.0
     */
    
    @Service
    public class UserService {
    
        //注入dao
        @Autowired
        private UserDao userDao;
    
        public void accountMoney(){
    
            userDao.reduceMoney();
            userDao.addMoney();
    
        }
    
    }
    
    

    在这里插入图片描述

    4. 上面,如果正常执行没有问题,但是如果代码执行过程中出现异常,有问题

    1. 模拟异常
        public void accountMoney(){
    
            userDao.reduceMoney();
    
            int i = 10 / 0;
    
            userDao.addMoney();
    
        }
    
    1. 事务操作过程
        public void accountMoney() {
    
            try {
    
                //第一步 开启事务
    
                //第二步 进行业务操作
                userDao.reduceMoney();
    
                int i = 10 / 0;
    
                userDao.addMoney();
    
                //第三步 没有发生异常,提交事务
    
            } catch (Exception e) {
    
                //第四步 出现异常,事务回滚
    
            }
    
        }
    

    3. Spring事务管理介绍

    1. 事务添加到JavaEE三层结构里面Service层(业务逻辑层)

    2. 在Spring进行事务管理操作

    两种方式:编程式事务管理声明式事务管理(使用)

    3. 声明式事务管理

    1. 基于注解方式
    2. 基于 xml 配置文件方式

    4. 在Spring进行声明式事务管理,底层使用AOP原理

    5. Spring事务管理API

    提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
    在这里插入图片描述

    4. 注解声明式事务管理

    1. 在spring配置文件配置事务管理器

        
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            
            <property name="dataSource" ref="dataSource">property>
        bean>
    

    2. 在spring配置文件,开启事务注解

    1. 在 spring 配置文件引入名称空间 tx
    
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           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">
    beans>
    
    1. 开启事务注解
        
        <tx:annotation-driven transaction-manager="transactionManager">tx:annotation-driven>
    

    3. 在 service 类上面(或者service类里面方法上面)添加事务注解

    @Service
    @Transactional
    public class UserService {
    }
    
    1. @Transactional ,这个注解既可以添加到类上面也可以添加到方法上面
    2. 如果把这个注解添加到类上面,这个类里面所有的方法都添加事务
    3. 如果把这个注解添加到方法上面,为这个方法添加事务

    5. 声明事务管理参数配置

    1. 在service类上面添加注解@Transactional,这个注解里面可以配置事务相关参数

    2. propagation:事务传播行为

    当一个事务方法被另一个事务方法调用时候,这个事务方法如何进行

    1. REQUIRED
      如果有事务正在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行
      在这里插入图片描述

    2. REQUIRED_NEW
      当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起
      在这里插入图片描述

    3. SUPPORTS
      如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不允许在事务中

    在这里插入图片描述

    事务的传播行为可以由传播属性指定。Spring 定义了 7 种类传播行为。
    在这里插入图片描述

    3. ioslation:事务隔离级别

    1. 事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题

    2. 有三个读问题:脏读、不可重复读、虚(幻)读

    3. 脏读:一个未提交事务读取到另一个未提交事务的数据
      在这里插入图片描述

    4. 不可重复读:一个未提交事务读取到另一提交事务修改数据
      在这里插入图片描述

    5. 幻读:一个未提交事务读取到另一提交事务添加数据

    6. 解决:设置事务隔离性,解决读问题
      在这里插入图片描述

    MySql 默认的隔离级别是 REPEATABLE READ(可重复读)

    4. timeout:超时时间

    1. 事务需要在一定时间内进行提交,如果不提交进行回滚
    2. 默认值是 -1,设置时间以秒单位进行计算

    5. readOnly:是否只读

    1. 度:查询操作,写:添加修改删除操作
    2. readOnly 默认值是 false,表示可以查询,可以添加修改删除操作
    3. 设置 readOnly 值是 true,设置成 true 之后,只能查询

    6. rollbackFor:回滚

    设置出现哪些异常进行事务回滚

    7. noRollbackFor:不回滚

    设置出现哪些异常不进行事务回滚

    6. XML声明式事务管理

    在spring配置文件中进行配置

    第一步 配置事务管理器
    第二步 配置通知
    第三步 配置切入点和切面

    
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           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">
    
        
        <context:component-scan base-package="com.fickler">context:component-scan>
    
        
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
            <property name="url"
                      value="jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=false&rewriteBatchedStatements=true"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        bean>
    
        
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            
            <property name="dataSource" ref="dataSource">property>
        bean>
    
        
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            
            <property name="dataSource" ref="dataSource">property>
        bean>
    
        
        <tx:advice id="txadvice">
            
            <tx:attributes>
                
                <tx:method name="accountMoney" propagation="REQUIRED"/>
            tx:attributes>
        tx:advice>
    
        
        <aop:config>
            
            
            <aop:pointcut id="pt" expression="execution(* com.fickler.spring5.service.UserService.*(..))"/>
            
            <aop:advisor advice-ref="txadvice" pointcut-ref="pt">aop:advisor>
        aop:config>
    
    beans>
    

    7. 完全注解声明式事务管理

    创建配置类,使用配置类替代 xml 配置文件

    package com.fickler.spring5.config;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.sql.DataSource;
    
    /**
     * @author dell
     * @version 1.0
     */
    
    @Configuration      //配置类
    @ComponentScan(basePackages = "com.fickler")    //组件扫描
    @EnableTransactionManagement    //开启事务
    public class TxConfig {
    
        //创建数据库连接池
        @Bean
        public DruidDataSource getDruidDataSource(){
    
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setDriverClassName("com.alibaba.druid.pool.DruidDataSource");
            druidDataSource.setUrl("jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=false&rewriteBatchedStatements=true");
            druidDataSource.setUsername("root");
            druidDataSource.setPassword("root");
    
            return druidDataSource;
    
        }
    
        //创建JdbcTemplate对象
        @Bean
        public JdbcTemplate getJdbcTemplate(DataSource dataSource){ //到ioc容器中根据类型找到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;
    
        }
    
    }
    
    
  • 相关阅读:
    什么是MVCC?
    Ribbon
    基于qiankun搭建angular为基座vue为子应用的微前端项目
    手动实现第一个Servlet程序
    boost搜索引擎
    测试老鸟总结,Web/APP与接口测试测试流程总结,避背黑锅...
    【Qt学习】第一个Qt Quick程序
    三维全景融合拼接技术
    【uniapp】小程序中input输入框的placeholder-class不生效以及解决办法
    PyCharm 出现卡顿解决方案
  • 原文地址:https://blog.csdn.net/qq_52354698/article/details/126857570