Spring学习笔记03

1.AOP

1.1 什么是AOP

AOP(Aspect Oriented Programming)意为面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑的各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

1.2 AOP在Spring中的作用

提供声明式事务;允许用户自定义切面

以下名词需要简单了解下:

  • 横切关注点:跨越应用程序多个模块的方法和功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点,如日志,安全,缓存,事务等等
  • 切面(ASPECT):横切关注点被模块化的特殊对象,即,它是一个类。
  • 通知(Advice):切面必须要完成的工作,即它是类中的一个方法
  • 目标(Target):被通知对象
  • 代理(Proxy):向目标对象应用通知后创建的对象
  • 切入点(PointCut):切面通知执行的“地点”的定义
  • 连接点(JointPoint):与切入点匹配的执行点

1.3 使用Spring实现AOP

重点:使用AOP,需要导入一个依赖包

  1. <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
  2. <dependency>
  3. <groupId>org.aspectj</groupId>
  4. <artifactId>aspectjweaver</artifactId>
  5. <version>1.9.4</version>
  6. </dependency>

第一种方式

通过Spring API实现

  1. 首先编写我们的业务接口和实现类

接口

  1. public interface UserService {
  2. public void add();
  3. public void delete();
  4. public void update();
  5. public void select();
  6. }

接口实现类:

  1. public class UserServiceImpl implements UserService {
  2. public void add() {
  3. System.out.println("增加用户");
  4. }
  5. public void delete() {
  6. System.out.println("删除用户");
  7. }
  8. public void update() {
  9. System.out.println("更新用户");
  10. }
  11. public void select() {
  12. System.out.println("查询用户");
  13. }
  14. }
  1. 然后去写我们的增强类,我们编写两个,一个前置增强,一个后置增强

Log.java

  1. public class Log implements MethodBeforeAdvice {
  2. //method:要执行的目标对象的方法
  3. //objects:被调用的方法的参数
  4. //Object:目标对象
  5. public void before(Method method, Object[] objects, Object o) throws Throwable {
  6. System.out.println(o.getClass().getName()+"的"+method.getName()+"方法被执行了");
  7. }
  8. }

AfterLog.java

  1. public class AfterLog implements AfterReturningAdvice {
  2. //o 返回值
  3. //method 被调用的方法
  4. //objects 被调用的方法的对象的参数
  5. //o1 被调用的目标对象
  6. public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
  7. System.out.println("执行了"+o1.getClass().getName()+"的"+method.getName()+"方法,"+"返回值:"+o);
  8. }
  9. }
  1. 最后去spring的文件中注册,并实现aop切入实现,注意导入约束
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. https://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/aop
  8. https://www.springframework.org/schema/aop/spring-aop.xsd">
  9. <!-- 注册bean-->
  10. <bean id="userService" class="com.jcsune.service.UserServiceImpl"/>
  11. <bean id="log" class="com.jcsune.log.Log"/>
  12. <bean id="afterlog" class="com.jcsune.log.AfterLog"/>
  13. <!--aop的配置-->
  14. <aop:config>
  15. <!-- 切入点expression:表达式匹配要执行的方法-->
  16. <aop:pointcut id="pointcut" expression="execution(* com.jcsune.service.UserServiceImpl.*(..))"/>
  17. <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
  18. <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
  19. </aop:config>
  20. </beans>
  1. 测试
  1. @Test
  2. public void test(){
  3. ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
  4. UserService userService = (UserService) context.getBean("userService");
  5. userService.select();
  6. }
  1. 结果

Spring学习笔记03 - 图1

AOP的重要性:很重要 一定要理解其中的思路,主要是思想的理解

Spring的AOP就是将公共的业务(日志,安全等)和领域业务结合起来,当执行领域业务时,将会把公共业务加起来,实现公共业务的重复利用,领域业务更纯碎,程序员专注领域业务,其本质还是动态代理

第二种方式

自定义类来实现AOP

目标业务类不变依旧是userServiceImpl

  1. 写我们自己的一个切入类
  1. public class DiyPointcut {
  2. public void before(){
  3. System.out.println("-------方法执行前-------");
  4. }
  5. public void after(){
  6. System.out.println("-------方法执行后-------");
  7. }
  8. }
  1. 去Spring中配置
  1. <!-- 方式二:自定义类来实现AOP-->
  2. <!-- 注册bean-->
  3. <bean id="diy" class="com.jcsune.diy.DiyPointcut"/>
  4. <!-- aop的配置-->
  5. <aop:config>
  6. <!-- 第二种方式:使用aop的标签实现-->
  7. <aop:aspect ref="diy">
  8. <aop:pointcut id="diyPointcut" expression="execution(* com.jcsune.service.UserServiceImpl.*(..))"/>
  9. <aop:before pointcut-ref="diyPointcut" method="before"/>
  10. <aop:after pointcut-ref="diyPointcut" method="after"/>
  11. </aop:aspect>
  12. </aop:config>
  1. 测试
  1. @Test
  2. public void test(){
  3. ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
  4. UserService userService = (UserService) context.getBean("userService");
  5. userService.add();
  6. }
  1. 结果

Spring学习笔记03 - 图2

第三种方式:

使用注解实现:

  1. 编写一个注解实现的增强类
  1. package com.jcsune.config;
  2. import org.aspectj.lang.ProceedingJoinPoint;
  3. import org.aspectj.lang.annotation.After;
  4. import org.aspectj.lang.annotation.Around;
  5. import org.aspectj.lang.annotation.Aspect;
  6. import org.aspectj.lang.annotation.Before;
  7. @Aspect
  8. public class AnnotationPointcut {
  9. @Before("execution(* com.jcsune.service.UserServiceImpl.*(..))")
  10. public void before(){
  11. System.out.println("-----方法执行前-----");
  12. }
  13. @After("execution(* com.jcsune.service.UserServiceImpl.*(..))")
  14. public void after(){
  15. System.out.println("-----方法执行后-----");
  16. }
  17. @Around("execution(* com.jcsune.service.UserServiceImpl.*(..))")
  18. public void around(ProceedingJoinPoint jp) throws Throwable{
  19. System.out.println("环绕前");
  20. System.out.println("签名"+jp.getSignature());
  21. //执行目标方法proceed
  22. Object proceed=jp.proceed();
  23. System.out.println("环绕后");
  24. System.out.println(proceed);
  25. }
  26. }
  1. 在Spring配置文件中,注册bean,并增加支持注解的配置
  1. <!-- 第三种方式:注解实现-->
  2. <bean id="annotationPointcut" class="com.jcsune.config.AnnotationPointcut"/>
  3. <aop:aspectj-autoproxy/>

aop:aspectj-autoproxy:说明

通过aop命名空间的声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面。当然,spring 在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被隐藏起来了

有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。

  1. 结果

Spring学习笔记03 - 图3

2.整合Mybatis

2.1 回忆Mybatis

步骤

  1. 导入相关jar包

junit

  1. <dependency>
  2. <groupId>junit</groupId>
  3. <artifactId>junit</artifactId>
  4. <version>4.12</version>
  5. </dependency>

mybatis

  1. <dependency>
  2. <groupId>org.mybatis</groupId>
  3. <artifactId>mybatis</artifactId>
  4. <version>3.5.2</version>
  5. </dependency>

mysql-connector-java

  1. <dependency>
  2. <groupId>mysql</groupId>
  3. <artifactId>mysql-connector-java</artifactId>
  4. <version>8.0.11</version>
  5. </dependency>

spring相关

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-webmvc</artifactId>
  4. <version>5.1.10.RELEASE</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework</groupId>
  8. <artifactId>spring-jdbc</artifactId>
  9. <version>5.1.10.RELEASE</version>
  10. </dependency>

aspect AOP织入器

  1. <dependency>
  2. <groupId>org.aspectj</groupId>
  3. <artifactId>aspectjweaver</artifactId>
  4. <version>1.9.4</version>
  5. </dependency>

mybatis-spring 整合包(重点)

  1. <dependency>
  2. <groupId>org.mybatis</groupId>
  3. <artifactId>mybatis-spring</artifactId>
  4. <version>2.0.3</version>
  5. </dependency>

Lomcok

  1. <dependency>
  2. <groupId>org.projectlombok</groupId>
  3. <artifactId>lombok</artifactId>
  4. <version>1.18.10</version>
  5. </dependency>
  1. 编写配置文件
  2. 代码实现

具体实现步骤

  1. 编写pojo实体类
  1. package com.jcsune.pojo;
  2. import lombok.Data;
  3. @Data
  4. public class User {
  5. private int id;
  6. private String name;
  7. private String pwd;
  8. }
  1. 实现mybatis的配置文件
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <typeAliases>
  7. <package name="com.jcsune.pojo"/>
  8. </typeAliases>
  9. <environments default="development">
  10. <environment id="development">
  11. <transactionManager type="JDBC"/>
  12. <dataSource type="POOLED">
  13. <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
  14. <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;serverTimezone=Asia/Shanghai&amp;characterEncoding=UTF-8"/>
  15. <property name="username" value="root"/>
  16. <property name="password" value="321074"/>
  17. </dataSource>
  18. </environment>
  19. </environments>
  20. <mappers>
  21. <mapper resource="UserMapper.xml"/>
  22. </mappers>
  23. </configuration>
  1. 接口
  1. package com.jcsune.mapper;
  2. import com.jcsune.pojo.User;
  3. import java.util.List;
  4. public interface UserMapper {
  5. public List<User> selectUser();
  6. }
  1. 接口对应的mapper映射文件
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <!--namespace=绑定一个对应的Dao/Mapper接口-->
  6. <mapper namespace="com.jcsune.mapper.UserMapper">
  7. <!--select查询语句-->
  8. <select id="selectUser" resultType="user">
  9. select * from mybatis.user
  10. </select>
  11. </mapper>
  1. 测试类(与之前不同的是,这次把工具类写在了测试类中)
  1. public class MyTest {
  2. @Test
  3. public void selectUser()throws IOException{
  4. String resource="mybatis-config.xml";
  5. InputStream inputStream = Resources.getResourceAsStream(resource);
  6. SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
  7. SqlSession sqlSession=sqlSessionFactory.openSession();
  8. UserMapper mapper=sqlSession.getMapper(UserMapper.class);
  9. List<User> userList=mapper.selectUser();
  10. for (User user : userList) {
  11. System.out.println(user);
  12. }
  13. sqlSession.close();
  14. }
  15. }
  1. 结果

Spring学习笔记03 - 图4

2.2 整合Mybatis实现方式一

引入Spring之前需要了解Mybatis-Spring包中的一些重要类

官网: https://mybatis.org/spring/zh/index.html

1. 什么是Mybatis-Spring?

Mybatis-Spring会帮助你讲Mybatis代码无缝的整合到Spring中,它将允许Mybatis参与到Spring的事务管理当中,创建映射器mapper和SqlSession并注入到bean中,以及将Mybatis的异常转换为Spring的DataAccessException.最终可以做到应用代码不依赖于Mybatis,Spring或Mybatis-Spring

2.MyBatis-Spring 需要以下版本:

Spring学习笔记03 - 图5

如果使用Maven作为构建工具,仅需要在pom.xml中加入以下代码即可

  1. <dependency>
  2. <groupId>org.mybatis</groupId>
  3. <artifactId>mybatis-spring</artifactId>
  4. <version>2.0.3</version>
  5. </dependency>

要和Spring一起使用Mybatis,需要在Spring应用上下文中定义至少两样东西:一个SqlSessionFactory和至少一个数据映射器类

在Mybatis-Spring中,可使用SqlSessionFactoryBean来创建SqlSessionFactory,要配置这个工厂bean,只需啊要把下面代码放在Spring的xml的配置文件中

  1. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  2. <property name="dataSource" ref="dataSource"/>
  3. </bean>

注意:SqlSessionFactory需要一个DataSource(数据源),这可以是任意的DataSource,只需要和配置其它Spring数据库连接一样配置就可以了

在基础的Mybatis用法中,是通过SqlSessionFactoryBuilder来创建SqlSessionFactory的,而在Mybatis-Spring中,则使用SqlSessionFactoryBean来创建

在Mybatis中,你可以使用SqlSessionFactory来创建SqlSession,一旦你获得一个session,你可以使用它来执行映射了的语句,提交或回滚连接,最后当不再需要它的时候,你可以关闭session

SqlSessionFactory有一个唯一的必要属性:用于JDBC的DataSource,这可以是任意的DataSource对象,它的配置方法和其它Spring数据库连接一样

一个常用的属性是configLocation,它用来指定Mybatis的xml配置文件路径,它在需要修改Mybatis的基础配置非常有用,通常基础配置指的是或元素

需要注意的是,这个配置文件并不需要是一个完整的Mybatis配置,确切的说,任何环境配置,数据源和Mybatis的事务管理器都会被忽略,SqlSessionFactoryBean会创建它自有的Mybatis环境配置(Environment),并按要求设置自定义环境的值

SqlSessionTemplate是mybatis-spring的核心,作为SqlSession的一个实现,这意味着可以使用它无缝代替你代码中已经在使用的SqlSess

模板可以参与到Spring的事务管理中,并且由于其是线程安全的,可以供多个映射器类使用,你应该总是用SqlSessionTemplate来替换Mybatis默认的DefaultSqlSession实现,在同一应用程序的不同类之间混杂使用可能会引起数据一致性的问题

可以使用SqlSessionFactory作为构造方法的参数来创建SqlSessionTemplate对象

  1. <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  2. <constructor-arg index="0" ref="sqlSessionFactory" />
  3. </bean>

整合实现方式一:

  1. 引入Spring的配置文件 spring-dao.xml
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. https://www.springframework.org/schema/beans/spring-beans.xsd>
  6. </beans>
  1. 配置数据源替换Mybatis的数据源
  1. <!--配置数据源:数据源有非常多,可以使用第三方的也可以使用Spring的-->
  2. <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  3. <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
  4. <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;serverTimezone=Asia/Shanghai&amp;characterEncoding=UTF-8"/>
  5. <property name="username" value="root"/>
  6. <property name="password" value="321074"/>
  7. </bean>
  1. 配置SqlSessionFactory,关联Mybatis
  1. <!--配置SqlSessionFactory,关联mybatis-->
  2. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  3. <property name="dataSource" ref="datasource"/>
  4. <!-- 关联 Mybatis-->
  5. <property name="configLocation" value="classpath:mybatis-config.xml"/>
  6. <property name="mapperLocations" value="classpath:UserMapper.xml"/>
  7. </bean>
  1. 注册sqlSessionTemplate,关联sqlSessionFactory;
  1. <!-- 注册SqlSessionTemplate,关联SqlSessionFactory-->
  2. <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  3. <!-- 只能用构造器注入sqlSessionFactory,因为它没有set方法-->
  4. <constructor-arg index="0" ref="sqlSessionFactory"/>
  5. </bean>
  1. 增加UserMapper接口的实现类,私有化sqlSessionTemplate
  1. public class UserMapperImpl implements UserMapper {
  2. //我们的所有操作都使用sqlSession来执行,现在都使用SqlSessionTemplate
  3. private SqlSessionTemplate sqlSession;
  4. public void setSqlSession(SqlSessionTemplate sqlSession) {
  5. this.sqlSession = sqlSession;
  6. }
  7. public List<User> selectUser() {
  8. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  9. return mapper.selectUser();
  10. }
  11. }
  1. 注册bean实现
  1. <bean id="userMapper" class="com.jcsune.mapper.UserMapperImpl">
  2. <property name="sqlSession" ref="sqlSession"/>
  3. </bean>
  1. 测试
  1. @Test
  2. public void selectUser()throws IOException{
  3. ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
  4. UserMapper mapper=(UserMapper)context.getBean("userMapper");
  5. for (User user :mapper.selectUser()) {
  6. System.out.println(user);
  7. }
  8. }
  1. 结果

Spring学习笔记03 - 图6

结果成功输出,现在我们mybatis配置文件的状态,发现都可以被Spring整合

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <typeAliases>
  7. <package name="com.jcsune.pojo"/>
  8. </typeAliases>
  9. </configuration>

2.3 整合Mybatis实现方式二

mybatis-spring1.2.3版以上的才有这个

dao继承Support类 , 直接利用 getSqlSession() 获得 , 然后直接注入SqlSessionFactory . 比起方式1 , 不需要管理SqlSessionTemplate , 而且对事务的支持更加友好 . 可跟踪源码查看

测试:

  1. 新建一个接口实现类UserMapperImpl2
  1. public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
  2. public List<User> selectUser() {
  3. UserMapper mapper=getSqlSession().getMapper(UserMapper.class);
  4. return mapper.selectUser();
  5. }
  6. }
  1. 注册bean实现
  1. <bean id="userMapper2" class="com.jcsune.mapper.UserMapperImpl2">
  2. <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
  3. </bean>
  1. 测试
  1. @Test
  2. public void selectUser()throws IOException{
  3. ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
  4. UserMapper mapper=(UserMapper)context.getBean("userMapper2");
  5. for (User user :mapper.selectUser()) {
  6. System.out.println(user);
  7. }
  8. }
  1. 结果

Spring学习笔记03 - 图7

总结:整合到spring以后可以完全不要mybatis的配置文件,除了这些方式可以实现整合之外,我们还可以使用注解来实现,这个等学习SpringBoot的时候还会测试整合

3.声明式事务

3.1 回顾事务

  • 事务在项目开发的过程中非常重要,涉及到数据的一致性问题,不容马虎
  • 事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性

事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用

事务的四个属性ACID

  1. 原子性(atomicity)
    事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用

  2. 一致性(consistency)

  1. 一旦所有事务动作完成,事务就要被提交,数据和资源处于一种满足业务规则的一致性状态中
  1. 隔离性(isolation)

    1. 可能多个事务会同时处理相同的数据,因此每个事务都应该与其它事务隔离开来,防止数据损坏
  2. 持久性(durability)

    事务一旦完成,无论系统发生什么错误,结果都不会受到影响,通常情况下,事务的结果被写到持久化存储器中

测试:将上一节的代码拷贝到一个新项目中

  1. 在之前的案例中,给UserMapper接口新增两个方法,删除和增加用户
  1. //添加一个用户
  2. int addUser(User user);
  3. //根据id删除用户
  4. int deleteUser(int id);
  1. mapper文件,故意把deletes写错,测试!
  1. <insert id="addUser" parameterType="user">
  2. insert into mybatis.user(id, name, pwd) values(#{id},#{name},#{pwd})
  3. </insert>
  4. <delete id="deleteUser" parameterType="int">
  5. deletes from mybatis.user where id = #{id}
  6. </delete>
  1. 编写接口的实现类
  1. public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
  2. public List<User> selectUser() {
  3. User user=new User(10,"小明","111222");
  4. UserMapper mapper=getSqlSession().getMapper(UserMapper.class);
  5. mapper.addUser(user);
  6. mapper.deleteUser(10);
  7. return mapper.selectUser();
  8. }
  9. public int addUser(User user) {
  10. UserMapper mapper=getSqlSession().getMapper(UserMapper.class);
  11. return mapper.addUser(user);
  12. }
  13. public int deleteUser(int id) {
  14. UserMapper mapper=getSqlSession().getMapper(UserMapper.class);
  15. return mapper.deleteUser(id);
  16. }
  17. }
  1. 测试
  1. @Test
  2. public void selectUser()throws IOException{
  3. ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext.xml");
  4. UserMapper mapper=(UserMapper)context.getBean("userMapper2");
  5. for (User user :mapper.selectUser()) {
  6. System.out.println(user);
  7. }
  8. }
  1. 结果

Spring学习笔记03 - 图8

显示报错:sql异常,delete写错了

但是数据却插入成功了!

Spring学习笔记03 - 图9

以上就是没有进行事务的管理如果我们想让他们都成功才成功,有一个失败,就都失败,我们就需要事务!

以前我们都需要手动管理事务,十分麻烦

但是Spring给我们提供了事务管理,我们只需要配置即可

3.2 Spring的事务管理

Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring的事务管理机制,Spring支持编程式事务和声明式的事务管理

编程式事务管理

  • 将事务管理代码嵌入到业务方法中来控制事务的提交和回滚
  • 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码

声明式事务管理:

  • 一般情况下比编程式事务管用
  • 将事务管理代码从业务方法中分离出来,以声明的方式来实现业务管理
  • 将事务管理作为横切关注点,通过aop方法模块化,Spring中通过Spring AOP框架支持 声明式事务管理

事务管理器:

  • 无论使用Spring的哪种事务管理策略(编程式或者声明式)事务管理器都是必须的
  • 就是Spring的核心事务管理抽象,管理封装了一组独立于技术的方法

使用Spring管理事务,注意头文件的约束导入:tx

  1. xmlns:tx="http://www.springframework.org/schema/tx"
  2. http://www.springframework.org/schema/tx
  3. https://www.springframework.org/schema/tx/spring-tx.xsd

JDBC事务

  1. <bean id="transactionManager"
  2. class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  3. <property name="dataSource" ref="datasource"/>
  4. </bean>

配置好事务管理器后我们需要去配置事务的通知

  1. <!-- 配置事务通知-->
  2. <tx:advice id="txAdvice" transaction-manager="transactionManager">
  3. <tx:attributes>
  4. <!-- 配置哪些方法使用什么样的事务,配置事务的传播特性-->
  5. <tx:method name="add" propagation="REQUIRED"/>
  6. <tx:method name="delete" propagation="REQUIRED"/>
  7. <tx:method name="update" propagation="REQUIRED"/>
  8. <tx:method name="select" propagation="REQUIRED"/>
  9. <tx:method name="*" propagation="REQUIRED"/>
  10. </tx:attributes>
  11. </tx:advice>

配置AOP

  1. <!-- 配置Aop织入事务-->
  2. <aop:config>
  3. <aop:pointcut id="txPointcut" expression="execution(* com.jcsune.mapper.*.*(..))"/>
  4. <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
  5. </aop:config>

测试:删掉之前插入的数据,再次测试

  1. @Test
  2. public void selectUser()throws IOException{
  3. ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext.xml");
  4. UserMapper mapper=(UserMapper)context.getBean("userMapper2");
  5. for (User user :mapper.selectUser()) {
  6. System.out.println(user);
  7. }
  8. }

显示报错!数据也没有插入进去

Spring学习笔记03 - 图10

为什么要配置事务?

  • 如果不配置,就需要我们手动提交控制事务
  • 事务在项目开发过程中非常重要,涉及到数据的一致性的问题,不容马虎