• Spring事务管理 | 数据库连接池流程原理分析


    在这里插入图片描述

    💗wei_shuo的个人主页

    💫wei_shuo的学习社区

    🌐Hello World !


    Spring事务管理

    事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transactionend transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成

    概念:

    例如:在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序

    事务ACID原则:

    • 原子性(atomicity):一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做
    • 一致性(consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性密切相关
    • 隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰
    • 持久性(durability):持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响
    • 声明式事务:

      通过AOP(面向切面)方式在方法前使用编程式事务的方法开启事务,通过注解或XML配置实现,在方法后提交或回滚。用配置文件的方法或注解方法(如:@Transactional)控制事务

    • 编程式事务:代码中进行事务管理

      手动开启、提交、回滚事务

    环境搭建

    • User类
    package com.wei.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private int id;
        private String name;
        private String pwd;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • UserMapper接口
    package com.wei.Mapper;
    
    import com.wei.pojo.User;
    
    import java.util.List;
    
    public interface UserMapper {
    
        //查询用户
        public List<User> selectUser();
    
        //添加用户
        public int addUser(User user);
    
        //删除用户
        public int deleteUser(int id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • UserMapper.xml接口映射文件
    
    
    
    
    <mapper namespace="com.wei.Mapper.UserMapper">
    
        
        <select id="selectUser" resultType="com.wei.pojo.User">
            select * from mybatis.user;
        select>
    
        <insert id="addUser" parameterType="user">
            insert into mybatis.user (id, name, pwd) values (#{id}, #{name}, #{pwd});
        insert>
    
        <delete id="deleteUser" parameterType="int">
            deletes from mybatis.user where id=#{id};
        delete>
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • mybatis-config.xml核心配置文件
      
      • 1
    
    
    
    
    <configuration>
    
        
        
    
        <settings>
            
            <setting name="logImpl" value="LOG4J"/>
        settings>
    
    
        <typeAliases>
            <package name="com.wei.pojo"/>
        typeAliases>
    
        
        <environments default="development">
            <environment id="development">
                
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                dataSource>
            environment>
        environments>
    
    configuration>
    
    • 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
    • 35
    • 36
    • Spring-dao.xml(配置、整合Mybatis)
    
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           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/tx
            http://www.springframework.org/schema/tx/spring-tx.xsd
            ">
    
    
        
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
        bean>
    
        
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            
            <property name="dataSource" ref="dataSource"/>
    
            
            <property name="configLocation" value="classpath:mybatis-config.xml"/>
            <property name="mapperLocations" value="classpath:com/wei/Mapper/*.xml"/>
        bean>
    
    
        
    
        
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            
            <constructor-arg ref="dataSource" />
        bean>
    
    beans>
    
    • 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
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • applicationContext.xml(配置Spring框架所需的信息)
    package com.wei.Mapper;
    
    import com.wei.pojo.User;
    import org.mybatis.spring.support.SqlSessionDaoSupport;
    
    import java.util.List;
    
    public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
    
        public List<User> selectUser(){
    
            User user = new User(5, "haha", "123456");
    
            UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
    
            mapper.addUser(user);
            mapper.deleteUser(5);
    
            return mapper.selectUser();
    
        }
    
        @Override
        public int addUser(User user) {
            UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
            return mapper.addUser(user);
        }
    
        @Override
        public int deleteUser(int id) {
            UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
            return mapper.deleteUser(1);
        }
    }
    
    • 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

    标准配置

    要开启 Spring 的事务处理功能,在 Spring 的配置文件中创建一个 DataSourceTransactionManager 对象:

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <constructor-arg ref="dataSource" />
    bean>
    
    • 1
    • 2
    • 3
    @Configuration
    public class DataSourceConfig {
    @Bean
    public DataSourceTransactionManager transactionManager() {
     return new DataSourceTransactionManager(dataSource());
    }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    声明式事务

    • spring-dao.xml中配置事务
      
      • 1
    
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:tx="http://www.springframework.org/schema/tx"
           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/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
            ">
    
    
        
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
        bean>
    
        
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            
            <property name="dataSource" ref="dataSource"/>
    
            
            <property name="configLocation" value="classpath:mybatis-config.xml"/>
            <property name="mapperLocations" value="classpath:com/wei/Mapper/*.xml"/>
        bean>
    
        
    
        
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            
            <constructor-arg ref="dataSource" />
        bean>
    
        
        
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
        
            
            <tx:attributes>
                <tx:method name="add" propagation="REQUIRED"/>
                <tx:method name="delete" propagation="REQUIRED"/>
                <tx:method name="update" propagation="REQUIRED"/>
                <tx:method name="select" propagation="REQUIRED"/>
                <tx:method name="query" read-only="true"/>
                
                <tx:method name="*" propagation="REQUIRED"/>
            tx:attributes>
        tx:advice>
    
        
        <aop:config>
            
            <aop:pointcut id="txPointCut" expression="execution(* com.wei.Mapper.*.*(..))"/>
            
            <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    
    
        aop:config>
    
    beans>
    
    • 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
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 测试类
    import com.wei.Mapper.UserMapper;
    import com.wei.pojo.User;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.util.List;
    
    public class MyTest {
        @Test
        public void test(){
            //解析beans.xml文件,生成管理相应的Bean对象,创建 Spring 的 IOC 容器
            ApplicationContext context = new ClassPathXmlApplicationContext("applicicationContext.xml");
    
            //getBean:参数即为Spring配置文件中的bean的id
            //从IOC容器中获取 bean 的实例
            UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
            List<User> userList = userMapper.selectUser();
    
            for (User user : userList) {
                System.out.println(user);
            }
    
    
        }
    }
    
    • 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
    • isolation:隔离级别

    • no-rollback-for:不回滚

    • propagation:传播行为

      REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务(默认)

      NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务

    • read-only:只读

    • rollback-for:回滚控制

    • timeout:过期时间

    总结

    配置事务原因:

    • 避免数据提交不一致
    • 事务涉及数据一致性和完整性问题

    ▌SqlSessionFactory

    SqlSessionFactory是MyBatis的核心对象,用于初始化MyBatis,读取配置文件,创建SqlSession对象,SqlSessionFactory是全局对象,为保证其在应用中全局唯一,要使用static进行初始化

    SqlSession是MyBatis操作数据库的核心对象,SqlSession使用JDBC方式与数据库交互,同时提供了数据表的CRUD(增删改查)对应的api方法

    导入jar包

    格式:

    <dependency>
    <groupId>org.mybatisgroupId>
    <artifactId>mybatisartifactId>
    <version>x.x.xversion>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    
    <dependency>
     <groupId>org.mybatisgroupId>
     <artifactId>mybatisartifactId>
     <version>3.5.2version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    XML 中构建 SqlSessionFactory

    • 每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心
    • SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得
    • 而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例
    • 获取sqlSessionFaction对象
    String resource = "org/mybatis/example/mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
    • 1
    • 2
    • 3

    获得 SqlSession 的实例

    既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句

    SqlSession sqlSession = sessionFactory.openSession(true);
    
    • 1

    代码实现

    • utils包下创建工具类MybatisUtils类
    package com.wei.utils;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    //sqlSessionFactory  构造  sqlSession
    public class MybatisUtils {
    	//提升作用域:定义SqlSessionFactory全局变量
        private static SqlSessionFactory sqlSessionFactory;
    //静态代码块:执行优先级高于非静态的初始化块,它会在类初始化的时候执行一次,执行完成便销毁,它仅能初始化类变量,即static修饰的数据成员
        static {	
            try {
                //使用Mybatis第一步:获取sqlSessionFactory对象
                
                //定义核心配置文件
                String resource = "mybatis-config.xml";
                //通过IO流加载resource的mybatis-config.xml核心配置文件文件
                InputStream inputStream = Resources.getResourceAsStream(resource);
                //通过build加载inputStream
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
        //SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
        //你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句
        public static SqlSession getSqlSession(){
            return sqlSessionFactory.openSession(true);		//此处设置参数为true时,表示开启自动提交事物功能
        }
    }
    
    • 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
    • 35
    • 36
    • 37

    ▌作用域(Scope)和生命周期

    在这里插入图片描述
    在这里插入图片描述

    所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭

    SqlSessionFactoryBuilder(构造器)

    • 一旦创建了 SqlSessionFactory,就不再需要它了
    • 局部变量

    SqlSessionFactory(工厂)

    • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例
    • 数据库连接池
    • SqlSessionFactory 的最佳作用域是应用作用域
    • 最简单的就是使用单例模式或者静态单例模式

    SqlSession(会话)

    • 连接到SqlSessionFactory(连接池)的一个请求

    • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。

    • 使用完需要赶紧关闭,否则资源被占用 SqlSession.close()


    🌼 结语:创作不易,如果觉得博主的文章赏心悦目,还请——点赞👍收藏⭐️评论📝冲冲冲🤞


    在这里插入图片描述

  • 相关阅读:
    Apollo(阿波罗)分布式配置中心
    Web3 世界的名片
    基于php的物流系统设计与实现
    使用Redis解决高并发方案 以及 思路讲解
    RK3568驱动指南|第五期-中断-第45章 自定义工作队列实验
    双十二买什么牌子电容笔?值得买的平价电容笔推荐
    反射面试题
    Blueprints - 鼠标光标判断相关节点
    react-router-dom v6的几个方法
    低代码平台和无代码平台有什么区别
  • 原文地址:https://blog.csdn.net/weixin_62765017/article/details/127954518