????wei_shuo的学习社区
????Hello World !
文章目录
▌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()
???? 结语:创作不易,如果觉得博主的文章赏心悦目,还请——
点赞
????收藏
⭐️评论
????冲冲冲
????