前言: 事务处理的本质
在学习事务处理前,需要明确一点:
数据库操作最终都要使用到JDBC,那么无论上层如何封装,底层都是调用Connection的commit,rollback来完成
烦人的事务处理:在日常开发中,数据访问层(DAO)必然需要进行事务的处理,但是我们会发现,事务处理的代码通常是简单的重复的,编写这样的重复代码会浪费大量的时间,所以我们需要找到一种方案可以将这些重复的代码进行抽取,以便与管理维护和复用,
我们的需求:在一系列数据库操作上的方法上增加额外的事务处理代码,让原来的方法中只关注具体的数据处理,即在原本以及存在的数据库操作方法上添加额外的事务处理逻辑
到这里你应该想到AOP了,没错! 这样的场景下AOP是最好的解决方案;
解决方案:AOP回顾一下Spring的AOP:在结合目前的需求
1.将目标对象(DAO)放入Spring容器
2.告知Spring你的通知代码是什么(事务处理)
3.告知Spring 哪些方法(DAO的CRUD)要应用那些通知(不同的事务处理代码)
4.从Spring中获取代理对象来完成原本的CRUD,代理对象会自动完成事务处理
Spring 事务处理APISpring作为框架,需要进行详细的设计,全方位的考虑事务处理的各个方面,而不仅是简单的帮你执行commit,rollback;
Spring对事务处理进行了抽象定义,形成了一套具体的API结构,如下:
TransactionDefinition:定义事务的具体属性,如隔离级别,超时设置,传播行为等
TransactionStatus: 用于获取当前事务的状态信息
PlatformTransactionMananger: 主要的事务管理接口,提供三个实现类对应不同场景
类型 场景DataSourceTransactionManager 使用Spring JDBC或 iBatis 进行持久化数据时使用
HibernateTransactionManager 使用Hibernate3.0版本 进行持久化数据时使用
JpaTransactionManager 使用JPA进行持久化时 使用
JtaTransactionManager 使用一个JTA实现来管理事务,跨数据源时使用
注意其分布在不同的jar包中,使用时根据需要导入对应jar包
事务的传播行为控制这是一个新概念但是也非常简单,即在一个执行sql的方法中调用了另一个方法时,该如何处理这两个方法之间的事务
Spring定义了7种不同的处理方式:
常量名 含义PROPAGATION_REQUIRED 支持当前事务。如果 A 方法已经在事 务中,则 B 事务将直接使用。否则将 创建新事务
PROPAGATION_SUPPORTS 支持当前事务。如果 A 方法已经在事 务中,则 B 事务将直接使用。否则将 以非事务状态执行
PROPAGATION_MANDATORY 支持当前事务。如果 A 方法没有事 务,则抛出异常
PROPAGATION_REQUIRES_NEW 将创建新的事务,如果 A 方法已经在 事务中,则将 A 事务挂起
PROPAGATION_NOT_SUPPORTED 不支持当前事务,总是以非事务状态 执行。如果 A 方法已经在事务中,则 将其挂起
PROPAGATION_NEVER 不支持当前事务,如果 A 方法在事务 中,则抛出异常
PROPAGATION.NESTED 嵌套事务,当外层出现异常则连同内层一起回滚,若外层正常而内部异常,仅回滚内部操作
上述涉及的挂起,意思是开启一个独立的事务,已存在的事务暂停执行,等待新事务执行完毕后继续执行,两个事务不会互相影响
Spring 整合MyBatis在开始前我们先完成一个基础的CURD功能,后续开发中Spring + MyBatis项目是很常见的,那要将MyBatis整合到Spring中来,要明确一下两者的关系和定位
Spring Java开发框架,其本质是一个对象容器,可以帮助我们完成IOC,DI,AOP
MyBatis是一个持久层框架,用于简化对数据库的操作
将两者整合起来,就是将MyBatis中的对象交给Spring来管理,且将这些对象的依赖也交给Spring来管理;
添加依赖:Spring 3.0 的开发在 MyBatis 3.0 官方发布前就结束了,于是MyBatis社区自己召集开发者完成了这一部分工作,于是有了mybatis-spring项目,后续Spring也就没有必要在开发一个新的模块了,所以该jar是MyBatis提供的
<!-- Spring整合MyBatis依赖 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.3</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!--JDBC--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.44</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.2.RELEASE</version> </dependency> <!--Spring JDBC--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.2.RELEASE</version> </dependency> <!--事务管理--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.2.RELEASE</version> </dependency> <!--AspectJ--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.0</version> </dependency> SM基础使用 配置文件 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 加载properties--> <context:property-placeholder location="jdbc.properties"/> <!-- 数据源 后续可更换为其他更方便的数据源--> <bean> <property value="${url}"/> <property value="${usr}"/> <property value="${password}"/> <property value="${driver}"/> </bean> <!-- MyBatis核心对象SqlSessionFactory--> <bean> <property ref="dataSource"/> </bean> <!-- 扫描Mapper 将代理对象放入Spring--> <bean> <property value="com.yh.dao"/> </bean> </beans>