IDEA项目实践——Spring集成mybatis、spring当中的事务

这篇具有很好参考价值的文章主要介绍了IDEA项目实践——Spring集成mybatis、spring当中的事务。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

系列文章目录

IDEA项目实践——创建Java项目以及创建Maven项目案例、使用数据库连接池创建项目简介

IDEWA项目实践——mybatis的一些基本原理以及案例

IDEA项目实践——动态SQL、关系映射、注解开发

IDEA项目实践——Spring框架简介,以及IOC注解

IDEA项目实践——Spring当中的切面AOP

文章目录

系列文章目录

前言

一 Spring集成mybatis

1.1 MySQL创建数据库ssm,新建表Student表

1.1 MySQL 创建数据库 ssm,新建表 Student

1.1.1 原JDBC建立连接形式的讲解

1)指定数据源 

2) 工具类

1.1.2 创建Maven项目 

1.2 maven 依赖 pom.xml

1.3 定义实体类 Student

1.4 定义 StudentDao 接口

1.5 定义映射文件 mapper

1.6 定义 Service 接口和实现类

1.7 定义 MyBatis 主配置文件

1.8 修改 Spring 配置文件

(1) 数据源的配置(掌握)

 (2) 从属性文件读取数据库连接信息

(3) 注册 SqlSessionFactoryBean

(4) 定义 Mapper 扫描配置器 MapperScannerConfigurer

1.9 向 Service 注入接口名

1.10 Spring 配置文件全部配置

二 Spring 事务

2.1 Spring 的事务管理

2.2 Spring 事务管理 API

(1) 事务管理器接口(重点)

   A、 常用的两个实现类

   B、Spring 的回滚方式(理解)

C、回顾错误与异常(理解)

(2) 事务定义接口

I、事务隔离级别常量

(1)脏读(Dirty read)

(2)不可重复读(Nonrepeatable read)

(3)幻读(Phantom read)

II、事务传播行为常量

a、 PROPAGATION_REQUIRED

b、PROPAGATION_SUPPORTS

c、 PROPAGATION_REQUIRES_NEW

III、事务默认超时时限常量【了解即可】

2.3 程序举例环境搭建

Step0:创建数据库表

​编辑 Step1: maven 依赖 pom.xml

Step2:创建实体类

Step3:定义 dao 接口

Step4:定义 dao 接口对应的 sql 映射文件

Step5:定义异常类

Step6:定义 Service 接口

Step7:定义 service 的实现类

Step8:修改 Spring 配置文件内容

 Step9:定义测试类

2.4 使用 Spring 的事务注解管理事务(掌握)

实现注解的事务步骤:

1. 声明事务管理器

2. 开启注解驱动 transaction-manager:

3. 业务层 public 方法加入事务属性​​​​​​​

第一句是需要有事务

此处事务回滚是发生库存不足和商品为空时的class

​​​​​​​​编辑

2.5 使用 AspectJ 的 AOP 配置管理事务(掌握)

Step1:复制项目

 Step2:maven 依赖 pom.xml

Step3:在容器中添加事务管理器

Step4:配置事务通知

Step5:配置增强器

Step6:修改测试类


前言

本文主要介绍Spring集成mybatis以及spring当中的事务,文章当中的案例仅供参考。

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

一 Spring集成mybatis

将MyBatis 与 Spring进行整合,主要解决的问题就是将SqlSessionFactory对象交由Spring来管理。所以,该整合,只需要将SqlSessionFactory的对象生成器 将与与Spring进行整合,主要解决的问题就是SqlSessionFactoryBean注册在Spring容器中,再将其注入给Dao的实现类即可完成整合。

实现Spring与MyBatis的整合常用的方式:扫描的Mapper动态代理

Spring 像插线板一样,mybatis框架是插头,可以容易的组合到一起。插线板spring插上 mybatis,两个框架就是一个整体。

1.1 MySQL创建数据库ssm,新建表Student表

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

创建实体类student

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

1.1 MySQL 创建数据库 ssm,新建表 Student

1.1.1 原JDBC建立连接形式的讲解

1)指定数据源 

原来的jdbc形式的配置文件

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

指定数据源 

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

2) 工具类

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 mybatis与spring

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 springIDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

1.1.2 创建Maven项目 

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

1.2 maven 依赖 pom.xml

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.26</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.3.26</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.26</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.11</version>
    </dependency>
    <!-- Spring整合MyBatis的依赖 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.1.0</version>
    </dependency>
    <!-- --------------------- -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.29</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.8</version>
    </dependency>
</dependencies>	
 <!--插件:-->
<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

1.3 定义实体类 Student

 创建学生的实体类

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

编辑代码如下:

package com.ambow.pojo;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;
    private int age;
}

1.4 定义 StudentDao 接口

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

此处选择接口,写的时候没有截全

package com.ambow.dao;

import com.ambow.pojo.Student;

import java.util.List;

public interface StudentDao {
    int insertStudent(Student student);
    int updateStudent(Student student);
    int deleteStudent(Student student);

    Student selectStudentById(int id);
    List<Student> selectAllStudents();
}

1.5 定义映射文件 mapper

在 Dao 接口的包中创建 MyBatis 的映射文件 mapper,命名与接口名相 同,本例为 StudentDao.xml。mapper 中的 namespace 取值也为 Dao 接口 的全限定性名。

项目的路径在此处IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目 

编辑映射文件的代码:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!--添加命名空间-->
<mapper namespace="com.ambow.dao.StudentDao">

    <insert id="insertStudent">
        insert into student values(null,#{name},#{age})
    </insert>
    <update id="updateStudent">
        update student set name = #{name},age = #{age} where id = #{id}
    </update>
    <delete id="deleteStudent">
        delete from student where id = #{id}
    </delete>
    <select id="selectStudentById" resultType="com.ambow.pojo.Student">
        select * from student where id = #{id}
    </select>
    <select id="selectAllStudents" resultType="com.ambow.pojo.Student">
        select * from student
    </select>

</mapper>

1.6 定义 Service 接口和实现类

接口定义:

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

package com.ambow.service;

import com.ambow.pojo.Student;

import java.util.List;

public interface StudentService {
    int addStudent(Student student);
    int modifyStudent(Student student);
    int removeStudent(int id);

    Student findStudentById(int id);
    List<Student> findAllStudents();
}

接口的实现类定义:

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

自动生成接口的实现类  IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

package com.ambow.service.impl;

import com.ambow.dao.StudentDao;
import com.ambow.pojo.Student;
import com.ambow.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("studentService")
public class StudentServiceImpl implements StudentService {

    //引入StudentDao的对象
    @Autowired
    private StudentDao studentDao;
    //Spring有set注入方法
    public void setStudentDao(StudentDao studentDao) {
        this.studentDao = studentDao;
    }

    @Override
    public int addStudent(Student student) {
        return studentDao.insertStudent(student);
    }

    @Override
    public int modifyStudent(Student student) {
        return studentDao.updateStudent(student);
    }

    @Override
    public int removeStudent(Student student) {
        return 0;
    }

    @Override
    public int removeStudent(int id) {
        return studentDao.deleteStudent(id);
    }

    @Override
    public Student findStudentById(int id) {
        return studentDao.selectStudentById(id);
    }

    @Override
    public List<Student> findAllStudents() {
        return studentDao.selectAllStudents();
    }
}

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

1.7 定义 MyBatis 主配置文件

在 src 下定义 MyBatis 的主配置文件,命名为 mybatis.xml。

这里有两点需要注意:

(1)主配置文件中不再需要数据源的配置了。因为数据源要交给 Spring 容器 来管理了。

(2)这里对 mapper 映射文件的注册,使用标签,即只需给出 mapper 映射文件所在的包即可。因为 mapper 的名称与 Dao 接口名相同, 可以使用这种简单注册方式。这种方式的好处是,若有多个映射文件,这里的 配置也是不用改变的。当然,也可使用原来的标签方式。

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

原先的environment数据源将交由Spring来管理 【代管】

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

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>
    <properties resource="jdbc.properties"/>
    
    <typeAliases>
        <package name="com.ambow.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/ssm?serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name ="com.ambow.dao"/>
    </mappers>
</configuration>

jdbc.properties文件:

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
username=root
password=root

可以先测试一下:

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 测试类的代码:

package com.ambow.test;

import com.ambow.dao.StudentDao;
import com.ambow.pojo.Student;
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 org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class SMTest {
    @Test
    public void test01() throws IOException {
        //先找到主配置文件
        String url = "mybatis-config.xml";
        //读取主配置文件
        InputStream inputStream = Resources.getResourceAsStream(url);
        //输入流拿到SqlSessionFactory工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //再次拿到SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //最后拿到StudentDao对象
        StudentDao studentDao = ((SqlSession) sqlSession).getMapper(StudentDao.class);
        //拿到学生对象,进行遍历
        List<Student> students = studentDao.selectAllStudents();
        for (Student student : students) {
            System.out.println(student);
        }
    }
}

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

等价于将原来的mybatis代码写一遍,然后修改

1.8 修改 Spring 配置文件

整合:把MyBatis中的核心对象,放到Spring容器

(1) 数据源的配置(掌握)

使用 JDBC 模板,首先需要配置好数据源,数据源直接以 Bean 的形式配置 在 Spring 配置文件中。根据数据源的不同,其配置方式不同:

Druid 数据源 DruidDataSource Druid 是阿里的开源数据库连接池。是 Java 语言中最好的数据库连接 池。Druid 能够提供强大的监控和扩展功能。Druid 与其他数据库连接池的 最大区别是提供数据库的

官网:GitHub - alibaba/druid: 阿里云计算平台DataWorks(https://help.aliyun.com/document_detail/137663.html) 团队出品,为监控而生的数据库连接池

使用地址:Home · alibaba/druid Wiki · GitHub常见问题

配置连接池:

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

Spring 配置文件:

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目  

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 (2) 从属性文件读取数据库连接信息

为了便于维护,可以将数据库连接信息写入到属性文件中,使 Spring 配置 文件从中读取数据。

属性文件名称自定义,但一般都是放在 src 下。

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
jdbc.username=root
jdbc.password=root

 Spring 配置文件从属性文件中读取数据时,需要在的 value 属性中使用${ },将在属性文件中定义的 key 括起来,以引用指定属性的值。

该属性文件若要被 Spring 配置文件读取,其必须在配置文件中进行注册。 使用<context>标签。

<context:property-placeholder />方式(掌握)

该方式要求在 Spring 配置文件头部加入 spring-context.xsd 约束文件

<context:property-placeholder />标签中有一个属性 location,用于指定属 性文件的位置。

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

(3) 注册 SqlSessionFactoryBean

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

工厂类拿到工厂对象,以及主配置文件

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

(4) 定义 Mapper 扫描配置器 MapperScannerConfigurer

Mapper 扫描配置器 MapperScannerConfigurer 会自动生成指定的基本 包中 mapper 的代理对象。该 Bean 无需设置 id 属性。basePackage 使用分 号或逗号设置多个包。

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--整合:把MyBatis中的核心对象,放到Spring容器-->

    <!--引入属性配置文件-->
    <context:property-placeholder location="classpath:jdbc.properties" />
    <context:component-scan base-package="com.ambow.service" />
    <!--1.DataSource-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>
    <!--2.注册SqlSessionFactoryBean-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--起别名的也可以将其放在这里-->
        <property name="typeAliasesPackage" value="com.ambow.pojo" />
        <!--mapper映射文件的位置,此处的value里面包之间需要使用/分割-->
        <property name="mapperLocations" value="classpath:com/ambow/dao/*.xml" />
    </bean>
    <!--3.mapper的扫描配置器 -> 生成mapper的代理对象-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
        <property name="basePackage" value="com.ambow.dao" />
    </bean>

</beans>

1.9 向 Service 注入接口名

向 Service 注入 Mapper 代理对象时需要注意,由于通过 Mapper 扫描配置器 MapperScannerConfigurer 生成的 Mapper 代理对象没有名称,所以在 向 Service 注入 Mapper 代理时,无法通过名称注入。但可通过接口的简单类名注入,因为生成的是这个 Dao 接口的对象。

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目 补充的地方:

<!--4.向service层注入Dao-->
<!--    <bean id="studentService" class="com.ambow.service.impl.StudentServiceImpl">
        <property name="studentDao" ref="studentDao" />
     </bean>-->

    <!--注入的过程-->
    <!--dataSource -> SqlSessionFactoryBean -> MapperScannerConfigurer(生成Dao代理对象) -> studentService-->

1.10 Spring 配置文件全部配置

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

测试一下:

@Test
    public void test02() throws IOException {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        StudentService studentService = (StudentService) context.getBean("studentService");
        List<Student> allStudents = studentService.findAllStudents();
        System.out.println(allStudents.size());
        for (Student student : allStudents) {
            System.out.println(student);
        }
    }

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 注意事项:

前面的jdbc的配置文件里面需要加上jdbc.的前缀,否则,这个找到的是本机的username,而不是mysql的用户名

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

此处可以看到拿到的并不是mysql的用户,而是电脑主机的用户名。 

再次压缩一下:

原来的mybatis-config文件里面的内容可以整合一下

整合完之后删除mybatis-config文件


前面的第四部可以使用注解的方式来做

实际的开发环境当中。

//自定义的类就可以使用注解的方法来写注入
//非自定义的类就需要在配置文件里面注入

二 Spring 事务

2.1 Spring 的事务管理

事务原本是数据库中的概念,在 Dao 层。但一般情况下,需要将事务提升到业务层,即 Service 层。这样做是为了能够使用事务的特性来管理具体的业务。

在 Spring 中通常可以通过以下两种方式来实现对事务的管理:

(1)使用 Spring 的事务注解管理事务

(2)使用 AspectJ 的 AOP配置管理事务

2.2 Spring 事务管理 API

Spring 的事务管理,主要用到两个事务相关的接口。

(1) 事务管理器接口(重点)

事务管理器是 PlatformTransactionManager 接口对象

其主要用于完成事务的提交、回滚,及获取事务的状态信息。

接口无法直接使用,需要实现类,实际使用的是下面的两个类

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

   A、 常用的两个实现类

PlatformTransactionManager 接口有两个常用的实现类

  • DataSourceTransactionManager:使用 JDBC 或 MyBatis 进行数据库操作时使用。

  • HibernateTransactionManager:使用 Hibernate 进行持久化数据时使用。

   ​​​​​​​B、Spring 的回滚方式(理解)

Spring 事务的默认回滚方式是:发生运行时异常和 error 时回滚,发生受查(编译)异常时提交。不过,对于受查异常,程序员也可以手工设置其回滚方式。

C、回顾错误与异常(理解)

 Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类 (或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java 的 throw 语句抛出。

  1. Error:是程序在运行过程中出现的无法处理的错误,比如 OutOfMemoryError、ThreadDeath、NoSuchMethodError 等。当这些错误发生时,程序是无法处理(捕获或抛出)的,JVM 一般会终止线程。
  2. Exception:程序在编译和运行时出现的另一类错误称之为异常,它是 JVM 通知程序员的一种方式。通过这种方式,让程序员知道已经或可能出现错误,要求程序员对其进行处理。

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

   异常分为运行时异常与受查异常。

运行时异常,是 RuntimeException 类或其子类,即只有在运行时才出现的异常。如,NullPointerException、ArrayIndexOutOfBoundsException、 IllegalArgumentException 等均属于运行时异常。这些异常由JVM抛出,在编译时不要求必须处理(捕获或抛出)。但,只要代码编写足够仔细,程序足够健壮,运行时异常是可以避免的。【因此,运行时异常,也叫非受查异常,编译器无法检查到,需要程序员通过修改代码来解决】

受查异常,也叫编译时异常,即在代码编写时要求必须捕获或抛出的异常,若不处理,则无法通过编译。如 SQLException, ClassNotFoundException,IOException 等都属于受查异常。

RuntimeException 及其子类以外的异常,均属于受查异常。当然,用户自定义的 Exception 的子类,即用户自定义的异常也属受查异常。程序员在定义异常时,只要未明确声明定义的为 RuntimeException 的子类,那么定义的就是受查异常。

Ø 非检查异常(unckecked exception):Error 和 RuntimeException 以及他们的子类。javac在编译时,不会提示和发现这样的异常,不要求程序员必须处理这些异常。在运行阶段,倘若发生Error则虚拟机几乎崩溃,倘若发生RuntimeException若程序员没处理它则一直回溯向上抛给java虚拟机处理。当然,如果程序员愿意的话,也可以编写代码处理(使用try…catch…finally)这样的异常(但是通常情况下不会这样做。需要这样做的情况是比如搞数学运算的这个专业领域要处理ArithmeticException)。对于这些异常,我们应该修正代码,而不是去通过异常处理器处理。这种异常发生的原因多半是代码写的有问题。如除0错误ArithmeticException,错误的强制类型转换错误ClassCastException,数组索引越界ArrayIndexOutOfBoundsException,使用了空对象NullPointerException等等。

Ø 检查异常(checked exception):除了Error和 RuntimeException的其它异常。javac强制要求程序员为这样的异常做预备处理工作(使用try…catch…finally或者throws)。在方法中要么用try-catch语句捕获它并处理,要么用throws子句声明抛出它,否则编译不会通过。这样的异常一般是由程序的运行环境导致的。因为程序可能被运行在各种未知的环境下,而程序员无法干预用户如何使用他编写的程序,于是程序员就应该为这样的异常时刻准备着。如SQLException , IOException,ClassNotFoundException 等。

发生运行时异常才会回滚​​​​​​​

Q&A:为什么添加事务管理器?

答:因为不同的技术管理事务的类不同,比如:

  • JDBC:Connecton con.commit(); con.rollback();
  • MyBatis:SqlSession sqlSession.commit(); sqlSession.rollback();
  • Hibernate:Session session.commit(); session.rollback();

事务管理器用来生成相应技术的连接对象及执行语句。

不同框架提交事务是不同的

(2) 事务定义接口

事务定义接口 TransactionDefinition 中定义了事务描述相关的三类常量:

事务隔离级别、事务传播行为、事务默认超时时限,及对它们的操作。

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

I、事务隔离级别常量

定义了五个事务隔离级别常量(掌握)

在应用程序中,多个事务并发运行,操作相同的数据,可能会引起脏读、不可重复读、幻读等问题。

(1)脏读(Dirty read)

第一个事务访问并改写了数据,尚未提交事务,这时第二个事务进来了,读取了刚刚改写的数据,如果这时第一个事务回滚了,这样第二个事务读取到的数据就是无效的“脏数据”。

(2)不可重复读(Nonrepeatable read)

第一个事务在其生命周期内多次查询同一个数据,在两次查询之间,第二个事务访问并改写了该数据,导致第一个事务两次查询同一个数据得到的结果不一样。

(3)幻读(Phantom read)

幻读和不可重复读类似。它发生在第一个事务在其生命周期进行了两次按同一查询条件查询数据,第一次按该查询条件读取了几行数据,这时第二个事务进来了,且插入或删除了一些数据,然后第一个事务再次按同一条件查询,发现多了一些原本不存在的记录或者原有记录不见了。

为了解决并发问题,TransactionDefinition接口定义了5个事务隔离常量如下:

这些常量均是以 ISOLATION_开头。即形如 ISOLATION_XXX。

  1. ISOLATION_DEFAULT : 采用数据库默认的事务隔离级别 。MySql 的默认为 REPEATABLE_READ(可重复读); Oracle 默认为 READ_COMMITTED(读已提交)。 【REPEATABLE_READ存在幻读的情况,但MySQL的InnoDB解决了幻读】
  2. ISOLATION_READ_UNCOMMITTED:读未提交。允许另外一个事务读取到当前事务未提交的数据,隔离级别最低,未解决任何并发问题,会产生脏读,不可重复读和幻读。
  3. ISOLATION_READ_COMMITTED:读已提交。被一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据。解决脏读,但还存在不可重复读与幻读。
  4. ISOLATION_REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读 
  5. ISOLATION_SERIALIZABLE:串行化读。按时间顺序一一执行多个事务,每次读都需要获得表级共享锁,读写相互都会阻塞,不存在并发问题,最可靠,但性能与效率最低。

从第2到第5,隔离级别越来越高。

II、事务传播行为常量

定义了七个事务传播行为常量(掌握)

所谓事务传播行为是指,处于不同事务中的方法在相互调用时,执行期间事务的维护情况(合并?互斥?)。

如,A 事务中的方法 doSome()调用 B 事务中的方法 doOther(),在调用执行期间事务的维护情况,就称为事务传播行为。事务传播行为是加在方法上的。

事务传播行为常量都是以 PROPAGATION_ 开头,形如 PROPAGATION_XXX。

  1. PROPAGATION_REQUIRED :必须包含事务(增删改必用)

  2. PROPAGATION_REQUIRES_NEW :自己新开一个事务,不管之前是否有事务

  3. PROPAGATION_SUPPORTS :支持事务,如果加入的方法有事务,则支持事务;如果没有,不单开事务

  4. PROPAGATION_NEVER :不能运行在事务中,如果包在事务中,抛异常

  5. PROPAGATION_NOT_SUPPORTED :不支持事务,运行在非事务环境中,如果加入的方法有事务,则会把事务先挂起【不常用】

  6. PROPAGATION_MANDATORY :必须包在事务中,没有事务则抛异常

  7. PROPAGATION_NESTED:嵌套事务

 最后的两个不怎么常用,了解一下即可。

a、 PROPAGATION_REQUIRED

指定的方法必须在事务内执行。若当前存在事务,就加入到当前事务中; 若当前没有事务,则创建一个新事务。这种传播行为是最常见的选择,也是 Spring 默认的事务传播行为。 如该传播行为加在 doOther()方法上。若 doSome()方法在调用 doOther() 方法时就是在事务内运行的,则 doOther()方法的执行也加入到该事务内执行。若 doSome()方法在调用 doOther()方法时没有在事务内执行,则 doOther()方法会创建一个事务,并在其中执行。

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

b、PROPAGATION_SUPPORTS

指定的方法支持当前事务,但若当前没有事务,也可以以非事务方式执行。

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

c、 PROPAGATION_REQUIRES_NEW

总是新建一个事务,若当前存在事务,就将当前事务挂起,直到新事务执行完毕。

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

III、事务默认超时时限常量【了解即可】

定义了默认事务超时时限

常量 TIMEOUT_DEFAULT 定义了事务底层默认的超时时限,及不支持事务超时时限设置的none值。

注意,事务的超时时限起作用的条件比较多,且超时的时间计算点较复杂。所以,该值一般就使用默认值即可。

2.3 程序举例环境搭建

举例:购买商品 trans_sale 项目

本例要实现购买商品,模拟用户下订单,向订单表添加销售记录,从商品表减少库存。

实现步骤:

Step0:创建数据库表

创建两个数据库表 sale , goods

sale 销售表

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

goods 商品表

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 goods 表数据

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

创建项目:

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目 Step1: maven 依赖 pom.xml

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.26</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.3.26</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.26</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.11</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.1.0</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.29</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.8</version>
    </dependency>
</dependencies>	
 <!--插件:-->
<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

Step2:创建实体类

创建实体类 Sale 与 Goods

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 ​​​​​​​goods实体类

package com.ambow.pojo;
//dao是数据访问层
//service是业务层
public class Goods {
    private Integer id;
    private String nname;
    private Integer amount;
    private float price;
}

sale实体类

package com.ambow.pojo;

public class Sale {
    private Integer id;
    private Integer gid;
    private Integer nums;
}

​​​​​​​Step3:定义 dao 接口

定义两个 dao 的接口 SaleDao , GoodsDao

 goodsdao数据访问层

package com.ambow.dao;

import com.ambow.pojo.Goods;

public interface GoodsDao {
    int updateGoods(Goods goods);
    Goods selectGoodsById(int id);
}

saledao数据访问层:

package com.ambow.dao;

import com.ambow.pojo.Sale;

public interface SaleDao {
    int insertSale(Sale sale);
}

Step4:定义 dao 接口对应的 sql 映射文件

SaleDao.xml

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ambow.dao.SaleDao">

    <insert id="insertSale">
        insert into sale (gid,nums) values (#{gid},#{nums})
    </insert>
</mapper>

GoodsDao.xml

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ambow.dao.GoodsDao">

    <update id="updateGoods">
        update goods
        set amount = amount - #{amount}
        where id = #{id};
    </update>
    <select id="selectGoodsById" resultType="com.ambow.pojo.Goods">
        select * from goods where id = #{id}
    </select>
</mapper>

update返回的是影响的行数 

业务描述: 

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

Step5:定义异常类

定义 service 层可能会抛出的异常类 NotEnoughException

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

package com.ambow.exception;
//库存不足的时候的异常抛出
public class NotEnoughException extends RuntimeException{
    public NotEnoughException(){
        super();
    }

    public NotEnoughException(String msg){
        super(msg);
    }
}

Step6:定义 Service 接口

定义 Service 接口 BuyGoodsService

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

package com.ambow.service;

public interface BuyGoodsService {
    public void buy(Integer goodsId,Integer amount);
}

Step7:定义 service 的实现类

定义 service 层接口的实现类 BuyGoodsServiceImpl

1)类定义

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 2)Dao 属性

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 3)Buy 方法

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 完整代码段:

package com.ambow.service.impl;

import com.ambow.dao.GoodsDao;
import com.ambow.dao.SaleDao;
import com.ambow.exception.NotEnoughException;
import com.ambow.pojo.Goods;
import com.ambow.pojo.Sale;
import com.ambow.service.BuyGoodsService;
import org.springframework.transaction.annotation.Transactional;

public class BuyGoodsServiceImpl implements BuyGoodsService {

    //1.SaleDao - 添加销售记录
    private SaleDao saleDao;
    //2.GoodsDao - 修改库存
    private GoodsDao goodsDao;
    //添加两个set方法
    public void setSaleDao(SaleDao saleDao) {
        this.saleDao = saleDao;
    }

    public void setGoodsDao(GoodsDao goodsDao) {
        this.goodsDao = goodsDao;
    }

    //购买商品
    @Transactional
    @Override
    public void buy(Integer goodsId, Integer amount) {
        //1.添加销售记录
        Sale sale = new Sale();
        sale.setGid(goodsId);
        sale.setNums(amount);

        saleDao.insertSale(sale);
        //验证商品库存是否存在和商品的库存是否不足
        Goods goods = goodsDao.selectGoodsById(goodsId);
        if (goods == null){
            throw new NullPointerException("无此商品");
        }
        if (goods.getAmount() < amount){
            throw new NotEnoughException("库存不足");
        }
        //2.修改库存
        goods = new Goods();
        goods.setId(goodsId);
        goods.setAmount(amount);

        goodsDao.updateGoods(goods);
    }
}

Step8:修改 Spring 配置文件内容

声明Mybatis 对象

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

<?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:context="http://www.springframework.org/schema/context" 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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--整合:把MyBatis中的核心对象,放到Spring容器-->

    <!--引入属性配置文件-->
    <context:property-placeholder location="classpath:jdbc.properties" />
    <context:component-scan base-package="com.ambow.service" />
    <!--1.DataSource-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>
    <!--2.注册SqlSessionFactoryBean-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="typeAliasesPackage" value="com.ambow.pojo" />
        <property name="mapperLocations" value="classpath*:com/ambow/dao/*.xml" />
    </bean>
    <!--3.mapper的扫描配置器 -> 生成mapper的代理对象-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
        <property name="basePackage" value="com.ambow.dao" />
    </bean>

    <!--4.向service层注入Dao-->
    <bean id="buyGoodsService" class="com.ambow.service.impl.BuyGoodsServiceImpl">
        <property name="saleDao" ref="saleDao" />
        <property name="goodsDao" ref="goodsDao" />
     </bean>

    <!--注入的过程-->
    <!--dataSource -> SqlSessionFactoryBean -> MapperScannerConfigurer(生成Dao代理对象) -> studentService-->

    <!--声明事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!--声明事务的注解驱动-->
    <tx:annotation-driven transaction-manager="transactionManager" />

</beans>

声明业务层对象

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 Step9:定义测试类

定义测试类 MyTest。现在就可以在无事务代理的情况下运行了。

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 原先的库存数量:

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 执行测试代码:

package com.ambow.test;

import com.ambow.service.BuyGoodsService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TransTest {
    @Test
    public void test01(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BuyGoodsService buyGoodsService = (BuyGoodsService) context.getBean("buyGoodsService");
        buyGoodsService.buy(1001,15);//正常购买
//        buyGoodsService.buy(1008,10);//无此商品
        //buyGoodsService.buy(1001,100);//库存不足
    }
}

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

数据库里面的数量: 

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 对应的sale表里面:

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 另外一种情况:

当没有此商品编号时会出现异常

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 最后一种情况:

当此商品库存不足的时候也会出现异常

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

2.4 使用 Spring 的事务注解管理事务(掌握)

通过@Transactional 注解方式,可将事务织入到相应 public 方法中,实现事务管理。

@Transactional 的所有可选属性如下所示:

  • propagation:用于设置事务传播属性。该属性类型为 Propagation 枚举, 默认值为 Propagation.REQUIRED。

  • isolation:用于设置事务的隔离级别。该属性类型为 Isolation 枚举,默认 值为 Isolation.DEFAULT。

  • readOnly:用于设置该方法对数据库的操作是否是只读的。该属性为 boolean,默认值为 false【可修改】。

  • timeout:用于设置本操作与数据库连接的超时时限。单位为秒,类型为 int, 默认值为-1,即没有时限。

  • rollbackFor:指定需要回滚的异常类。类型为 Class[],默认值为空数组。 当然,若只有一个异常类时,可以不使用数组。

  • rollbackForClassName:指定需要回滚的异常类类名。类型为 String[],默 认值为空数组。当然,若只有一个异常类时,可以不使用数组。

  • noRollbackFor:指定不需要回滚的异常类。类型为 Class[],默认值为空数 组。当然,若只有一个异常类时,可以不使用数组。

  • noRollbackForClassName:指定不需要回滚的异常类类名。类型为 String[], 默认值为空数组。当然,若只有一个异常类时,可以不使用数组。

  • 需要注意的是,@Transactional 若用在方法上,只能用于 public 方法 上。对于其他非 public 方法,如果加上了注解@Transactional,虽然 Spring 不会报错,但不会将指定事务织入到该方法中。因为 Spring 会忽略掉所有非 public 方法上的@Transaction 注解。
  • 若@Transaction 注解在类上,则表示该类上所有的方法均将在执行时织入事务。

实现注解的事务步骤:

复制 trans_sale 项目,新项目 trans_sale_annotation

1. 声明事务管理器

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 要实现事务管理,需要先添加事务管理器声明。

基于mybatis的项目需要使用datasourcetransactionmanager,此处的属性四指定数据源

2. 开启注解驱动 transaction-manager:

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 上述的内容在前面2.3.8里面已经写了

此处注意选择第四个tx开头的这个 

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

事务管理器 bean 的 id与1.相同

3. 业务层 public 方法加入事务属性​​​​​​​

第一句是需要有事务

此处事务回滚是发生库存不足和商品为空时的class

​​​​​​​IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 此处可以直接写下面注释的那部分即可

//默认的已有rollbackfor事务回滚,此处可以直接省略
    @Transactional(Propagation = Propagation.REQUIRED,
                    rollbackFor = {NotEnoughException.class,
                                    NullPointerException.class})
   // @Transactional

2.5 使用 AspectJ 的 AOP 配置管理事务(掌握)

使用 XML 配置事务代理的方式的不足是,每个目标类都需要配置事务代 理。当目标类较多,配置文件会变得非常臃肿。

使用 XML 配置顾问方式可以自动为每个符合切入点表达式的类生成事务代 理。其用法很简单,只需将前面代码中关于事务代理的配置删除,再替换为如 下内容即可。

Step1:复制项目

复制 trans_sale 项目,并重命名为 trans_sal_aspectj。在此基础上修改。此处直接新建一个项目

​​​​​​​IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 Step2:maven 依赖 pom.xml

新加入 aspectj 的依赖坐标

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.26</version>
</dependency>

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目  

Step3:在容器中添加事务管理器

<!--声明事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

Step4:配置事务通知

为事务通知设置相关属性。用于指定要将事务以什么方式织入给哪些方法。 例如,应用到 buy 方法上的事务要求是必须的,且当 buy 方法发生异常后要回滚业务。

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 可以将全部的都在此处配置,配置完成之后,修改起来只要修改此处即可

<!--声明事务的注解驱动-->
    <!--<tx:annotation-driven transaction-manager="transactionManager" />-->
    <!--添加通知 通知的ID是购买的参数-->
    <tx:advice id="buyAdvice" transaction-manager="transactionManager">
        <!-- 增强 先添加事务propagation 其isolation选择默认即可 回滚直接写类名,还有我们自己创建的一个事务回滚 两个事务之间使用逗号隔开-->
        <tx:attributes>
            <tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT"
            rollback-for="java.lang.NullPointerException,com.ambow.exception.NotEnoughException"/>
            <!--在开发时有许多的add方法,直接写全部的,在发生异常时全部回滚-->
            <tx:method name="add*" propagation="REQUIRED" isolation="DEFAULT"
            rollback-for="java.lang.Exception"/>
            <!--给所有的方法度加入method-->
            <tx:method name="*" propagation="SUPPORTS" />
        </tx:attributes>
    </tx:advice>

Step5:配置增强器

指定将配置好的事务通知,织入给谁。【次粗通过aop织入】

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 此处指定切入点表达式,指定传进来的包【此处为任意包里面的任意service里面的任意方法,以及对应的方法名】,再加入增强的通知

<aop:config>
        <aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>
        <aop:advisor advice-ref="buyAdvice" pointcut-ref="servicePt" />
    </aop:config>

Step6:修改测试类

测试类中要从容器中获取的是目标对象。

 IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 此处将原来的注解方式先注释,接着运行测试类可以看到aop的方式也可以

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

 接着运行测试即可 

IDEA项目实践——Spring集成mybatis、spring当中的事务,IDEA软件的使用与相关项目的操作,intellij-idea,mybatis,java,spring,IDEA,Maven,Java项目

总结

以上就是今天的内容~

欢迎大家点赞👍,收藏⭐,转发🚀,
如有问题、建议,请您在评论区留言💬哦。

最后:转载请注明出处!!​​​​​​​文章来源地址https://www.toymoban.com/news/detail-649965.html

到了这里,关于IDEA项目实践——Spring集成mybatis、spring当中的事务的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Mybatis事务如何跟Spring结合到一起?

    在Java Web开发中,MyBatis和Spring是两个常用的框架,它们可以有效地结合在一起,提供强大的数据库事务管理功能。在本文中,我们将从数据库事务特性和Spring事务管理源码两个角度来分析MyBatis事务如何与Spring结合到一起的原理。 首先,我们需要了解数据库事务的特性。一个

    2024年01月22日
    浏览(38)
  • Java Spring和Spring集成Mybatis

    1.Spring 2.Spring 集成Mybatis 1.Spring 特性 IOC :控制反转 AOP :面向切面 Spring 组成部分 在SMM中起到的作用(粘合剂) Spring 理念 OOP 核心思想【万物皆对象】 Spring 核心思想【万物皆Bean组件】 Spring 优势 低侵入式 独立于应用服务器 低耦合度 面向切面(集中式处理) 与第三方框架

    2024年02月16日
    浏览(44)
  • mybatis与spring集成与spring aop集成pagehelper插件

    Mybatis与Spring的集成 Mybatis是一款轻量级的ORM框架,而Spring是一个全栈式的框架,二者的结合可以让我们更加高效地进行数据持久化操作。 Mybatis与Spring的集成主要有两种方式:使用Spring的Mybatis支持和使用Mybatis的Spring支持。 使用Spring的Mybatis支持: 1. 在Spring的配置文件中配置数

    2024年02月11日
    浏览(50)
  • MyBatis与spring集成

    目录 MyBatis与Spring集成 导入pom依赖 导入generatorConfig.xml 导入spring-mybatis.xml 自动生成mapper文件  编写接口类:BookBiz  aop整合PageHelper分页插件 编写分页查询 编写pagebean 编写PagerAspect类 测试结果   导入pom依赖 导入generatorConfig.xml 导入spring-context.xml 导入spring-mybatis.xml 自动生成m

    2024年02月11日
    浏览(35)
  • 一文吃透Spring集成MyBatis

    个人主页: 几分醉意的CSDN博客_传送门 spring能集成很多的框架,是spring一个优势功能。通过集成功能,让开发人员使用其他框架更方便。集成使用的是spring ioc 核心技术。 使用mybatis,需要创mybatis框架中的某些对象,使用这些对象,就能使用mybatis提供的功能了。 1.创建实体类

    2024年02月06日
    浏览(49)
  • Mybatis与Spring集成配置

    目录 具体操作 1.1.添加依赖 1.2创建spring的配置文件 1.3. 注解式开发  Aop整合pagehelper插件 1. 创建一个AOP切面 2. @Around(\\\"execution(* *..*xxx.*xxx(..))\\\") 表达式解析                      前言: 上篇我们讲解了关于Mybatis的分页,今天我们讲Mybatis与Spring集成配置。 特别提示: 关于数

    2024年02月11日
    浏览(52)
  • Spring与MyBatis框架集成

    尽管Spring本身提供了Spring JDBC作为对JDBC的抽象和简化,但与MyBatis集成可以提供更多的功能和灵活性。MyBatis是一款优秀的持久层框架,它通过XML或注解的方式将SQL语句与Java方法进行绑定,提供了更直观和便捷的方式来管理数据库操作。集成Spring和MyBatis可以发挥两者的优势,

    2024年02月08日
    浏览(37)
  • transaction 事务 开启 关闭 不使用 手动控制 spring springboot mybatis

    spring springboot mybatis 事务配置 Transactional的Propagation 开启事务 关闭事务_globalcoding 单元测试时,发现默认是使用事务。想要关闭事务,使用: 做单元测试的时候,发现默认是使用事务的。代码和日志如下: 日志: 通过日志发现,默认用了事务transaction,这会有一个现象,就是

    2024年02月03日
    浏览(43)
  • 实现Spring Boot集成MyBatis

    在Java开发中,Spring Boot和MyBatis是非常常用的框架。Spring Boot是一个快速开发应用程序的框架,而MyBatis是一个持久化框架,可以方便地操作数据库。本文将介绍如何使用Idea集成Spring Boot和MyBatis,并创建一个简单的示例项目。 步骤1:创建Spring Boot项目 1、打开Idea,点击\\\"Create N

    2024年02月09日
    浏览(43)
  • 【推荐】Spring与Mybatis集成整合

    目录 1.概述 2.集成 2.1代码演示: 3.整合  3.1概述 3.2 进行整合分页 接着上两篇,我已经写了Mybatis动态之灵活使用,mybatis的分页和特殊字符的使用方式接下来把它们集成起来,是如何的呢👇👇👇。 集成是指将不同的组件、系统或框架整合在一起,使它们能够协同工作,共同

    2024年02月11日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包