Spring数据库连接池实现原理深入刨析
作者:wei_shuo 发布时间:2024-01-12 17:16:53
Spring事务管理
事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction
和end 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;
}
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);
}
UserMapper.xml接口映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.wei.Mapper.UserMapper">
<!--select查询语句查询全部用户-->
<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>
mybatis-config.xml核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>
<!--引入外部配置文件-->
<!--<properties resource="jdbc.properties"/>-->
<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>
Spring-dao.xml(配置、整合Mybatis)
<?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: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
">
<!--DataSource:使用Spring的数据源替换Mybatis的配置-->
<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>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--配置数据源-->
<property name="dataSource" ref="dataSource"/>
<!--绑定Mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/wei/Mapper/*.xml"/>
</bean>
<!--配置声明式事务-->
<!--要开启 Spring 的事务处理功能,在 Spring 的配置文件中创建一个 DataSourceTransactionManager 对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--<property name="dataSource" ref="dataSource"/>-->
<constructor-arg ref="dataSource" />
</bean>
</beans>
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);
}
}
标准配置
要开启 Spring 的事务处理功能,在 Spring 的配置文件中创建一个 DataSourceTransactionManager
对象:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
@Configuration
public class DataSourceConfig {
@Bean
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
声明式事务
spring-dao.xml中配置事务
<?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: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
">
<!--DataSource:使用Spring的数据源替换Mybatis的配置-->
<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>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--配置数据源-->
<property name="dataSource" ref="dataSource"/>
<!--绑定Mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/wei/Mapper/*.xml"/>
</bean>
<!--配置声明式事务-->
<!--要开启 Spring 的事务处理功能,在 Spring 的配置文件中创建一个 DataSourceTransactionManager 对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--<property name="dataSource" ref="dataSource"/>-->
<constructor-arg ref="dataSource" />
</bean>
<!--结合AOP实现事务的织入-->
<!--配置事务通知advice-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给那些方法配置事务-->
<!--配置事务的传播特性:new propagation -->
<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:配置事务切入-->
<aop:config>
<!--配置事务切入点pointcut-->
<aop:pointcut id="txPointCut" expression="execution(* com.wei.Mapper.*.*(..))"/>
<!--配置事务顾问advisor切入,将事务txAdvice切入到txPointCut-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
测试类
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);
}
}
}
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.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
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);
获得SqlSession的实例
既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句
SqlSession sqlSession = sessionFactory.openSession(true);
代码实现
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时,表示开启自动提交事物功能
}
}
作用域(Scope)和生命周期
所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭
SqlSessionFactoryBuilder(构造器)
一旦创建了 SqlSessionFactory,就不再需要它了
局部变量
SqlSessionFactory(工厂)
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例
数据库连接池
SqlSessionFactory 的最佳作用域是应用作用域
最简单的就是使用单例模式或者静态单例模式
SqlSession(会话)
连接到SqlSessionFactory(连接池)的一个请求
SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
使用完需要赶紧关闭,否则资源被占用 SqlSession.close()
来源:https://blog.csdn.net/weixin_62765017/article/details/127954518


猜你喜欢
- 一、lower():将大写字母全部转为小写字母。如:name='G'b=name.lower()二、title”"
- 服务器系统变量服务器将维护许多表示其配置的系统变量。所有变量均有默认值。可以在命令行中或选项文件设置选项在服务器启动时对它们进行设置。大多数
- 一、引出问题假如有这两张表,它们中的课程可能价格不一样、周期不一样、等等...不一样...,现在有一张价格策略表,怎么就用一张表报保存它们之
- 本文实例讲述了Python面向对象之类和实例用法。分享给大家供大家参考,具体如下:类虽然 Python 是解释性语言,但是它是面向对象的,能
- 由于我在从源码看vue(v2.7.10)的computed的实现原理中详细的讲解过computed的实现,本篇跟computed的原理类似。
- 在我们的生活中,需要接触大量的带有机械按键的物品。当你用手指按下按键的时候。都会或强或弱的感受一股(嗯,也有可能是一丝丝)反作用力传递到你手
- 本文主讲Python中Numpy数组的类型、全0全1数组的生成、随机数组、数组操作、矩阵的简单运算、矩阵的数学运算。尽管可以用python中
- 本文研究的主要是Python enumerate索引迭代的问题,具体介绍如下。索引迭代Python中,迭代永远是取出元素本身,而非元素的索引
- 本文实例讲述了Python实现获取命令行输出结果的方法。分享给大家供大家参考,具体如下:Python获取命令行输出结果,并对结果进行过滤找到
- 如下所示:import numpy as npimport pandas as pd################# 准备数据 #####
- MySQL有6种日志,监控数据库系统的时候必须知道select日志slow select日志变更日志二进制变更日志(binlog) 
- 调整形状 调整形状 reshape, resize, flatten
- 路由跳转了但界面不显示没有在父路由加上router-view,加上下面的代码即可。<!-- 路由匹配到的组件将显示在这里 -->
- import siximport timeit#查找任何特定代码执行的确切时间from ecdsa.curves import curves
- 如果视图定义包括条件(譬如 WHERE 子句)并且其意图是确保任何引用该视图的 INSERT 或 UPDATE 语句都应用 WHERE 子句
- 在进行接口测试的时候,我们会调用多个接口发出多个请求,在这些请求中有时候需要保持一些共用的数据,例如cookies信息。妙用1request
- 前言MYSQL Command Line Client是一款用于输入密码的程序,相信大多数用户在使用这款程序的时候都有遇到这样的一种情况吧?
- 本文实例讲述了php防止sql注入中过滤分页参数的方法。分享给大家供大家参考。具体分析如下:就网络安全而言,在网络上不要相信任何输入信息,对
- Vue3-KeepAlive,多个页面使用keepaliveVue3的生命周期未添加keepAlive的生命周期beforeCreate=&
- 本文主要介绍在 windows 10 系统中安装 Anaconda3 的详细过程。下载Anaconda 官网下载地址目前最新版本是 pyth