Spring整合MyBatis、声明式事务详解

文章目录

  • 整合MyBatis
    • 整合方式一
    • 整合方式二
  • 声明式事务
    • 回顾事务
    • 代码示例
    • Spring中的事务管理

整合MyBatis

  • Spring整合MyBatis的步骤为:

1、导入相关jar包:

junit、mybatis、mysql数据库、Spring相关、AOP织入、mybatis-spring包【新的包】、Spring操作数据库需要一个Spring-jdbc的包;

<dependencies>
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.16</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.3</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.3</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.9.2</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
</dependencies>

mybatis-spring包的官网:http://mybatis.org/spring/zh/index.html
后面学习SpringBoot框架的时候:引入mybatis/spring-boot-starter包,官网地址为:https://github.com/mybatis/spring-boot-starter

【注意】:

jar包搭配的时候,遵循官网的建议:

在这里插入图片描述

2、回忆MyBatis:

(1)编写实体类

@Data
public class Stu {
     
    private String sid;
    private String sname;
    private Integer age;
    private String gender;

    编写get和set访问器……
}

(2)编写核心配置文件

<?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="db.properties"></properties>

    <typeAliases>
        <package name="org.westos.pojo"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${db.driver}"/>
                <property name="url" value="${db.url}"/>
                <property name="username" value="${db.username}"/>
                <property name="password" value="${db.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--加载mapper映射文件-->
    <mappers>
        <package name="org.westos.mapper"/>
    </mappers>
</configuration>

----用到的db.properties
db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://127.0.0.1:3306/enducation?serverTimezone=UTC&characterEncoding=utf-8
db.username=root
db.password=123456

(3)编写接口

public interface StuMapper {
     
    public List<Stu> selectStu();
}

(4)编写mapper.xml




<mapper namespace="org.westos.mapper.StuMapper">
    <select id="selectStu" resultType="Stu">
        select * from stu
    select>
mapper>

(5)测试

@Test
public void test() throws IOException {
     
    String resources = "mybatis-config.xml";
    InputStream stream = Resources.getResourceAsStream(resources);
    SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(stream);
    SqlSession sqlSession = sessionFactory.openSession(true);

    StuMapper mapper = sqlSession.getMapper(StuMapper.class);
    List<Stu> list = mapper.selectStu();

    for (Stu stu : list) {
     
        System.out.println(JSON.toJSONString(stu, true));
    }

    sqlSession.close();
}

Spring整合MyBatis、声明式事务详解_第1张图片

整合方式一

创建mapper接口:

public interface StuMapper {
     
    public List<Stu> selectStu();
}

创建mapper.xml配置文件:




<mapper namespace="org.westos.mapper.StuMapper">
    <select id="selectStu" resultType="Stu">
        select * from stu
    select>
mapper>

编写mapper接口的实现类:

public class StuMapperImpl implements StuMapper {
     

    //我们的所有操作都是用SqlSession来执行,现在都使用SqlSessionTemplate
    private SqlSessionTemplate sqlSessionTemplate;

    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
     
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    public List<Stu> selectStu() {
     
        StuMapper stuMapper = sqlSessionTemplate.getMapper(StuMapper.class);
        return stuMapper.selectStu();
    }
}

我们不再使用SqlSession对象,而是使用SqlSessionTemplate对象代替它;

applicationContext.xml核心配置文件:


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:p="http://www.springframework.org/schema/p"
       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
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">


    
    <context:annotation-config/>

    <context:component-scan base-package="org.westos"/>

    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="url"
                  value="jdbc:mysql://127.0.0.1:3306/enducation?serverTimezone=UTC&characterEncoding=utf-8"/>
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    bean>

    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        
        
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    bean>

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

    
    <bean id="stuMapper" class="org.westos.mapper.StuMapperImpl">
        <property name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
    bean>
beans>

测试:

@Test
public void test1(){
     
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    StuMapper stuMapper = (StuMapper) context.getBean("stuMapper");
    List<Stu> list = stuMapper.selectStu();
    for (Stu stu : list) {
     
        System.out.println(stu);
    }
}

Spring整合MyBatis、声明式事务详解_第2张图片

现在这个环境中,MyBatis就彻底不见了,整个代码非常的简洁;

  • SqlSessionTemplate 是 MyBatis-Spring 的核心。作为 SqlSession 的一个实现,这意味着可以使用它无缝代替你代码中已经在使用的 SqlSession。
  • SqlSessionTemplate 是线程安全的,可以被多个 DAO 或映射器所共享使用。
  • 当调用 SQL 方法时(包括由 getMapper() 方法返回的映射器中的方法),SqlSessionTemplate 将会保证使用的 SqlSession 与当前 Spring 的事务相关。 此外,它管理 session 的生命周期,包含必要的关闭、提交或回滚操作。另外,它也负责将 MyBatis 的异常翻译成 Spring 中的 DataAccessExceptions
  • 可以使用 SqlSessionFactory 作为构造方法的参数来创建 SqlSessionTemplate 对象。

整合方式二

  • SqlSessionDaoSupport 是一个抽象的支持类,用来为你提供 SqlSession。调用 getSqlSession() 方法你会得到一个 SqlSessionTemplate,之后可以用于执行 SQL 方法;

首先,创建一个Mapper接口的实现类,该类继承了SqlSessionDaoSupport类:

public class StuMapperImpl2 extends SqlSessionDaoSupport implements StuMapper {
     
    public List<Stu> selectStu() {
     
        SqlSession sqlSession = getSqlSession();
        return sqlSession.getMapper(StuMapper.class).selectStu();
    }
}

编写核心配置文件:


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="url"
                  value="jdbc:mysql://127.0.0.1:3306/enducation?serverTimezone=UTC&characterEncoding=utf-8"/>
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    bean>

    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    bean>

    
    <bean id="stuMapper2" class="org.westos.mapper.StuMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    bean>
beans>

测试:
Spring整合MyBatis、声明式事务详解_第3张图片

  • 可以看到,使用这个方式,比前者更简单,不需要创建sqlSessionTemplate对象,直接给mapper接口的实现类注入sqlSessionFactory对象即可;而且对事务的支持更加友好 . 可跟踪源码查看;

  • 除了这些方式可以实现整合之外,我们还可以使用注解来实现;

  • 更详细的介绍在我的另一篇文章中,点击这里跳转;

声明式事务

回顾事务

  • 事务的特点把一组业务当成一个业务来做,要么都成功,要么都失败!事务在项目开发中十分重要,涉及到数据一致性问题,不能马虎!确保数据的完整性和一致性;
  • 事务的ACID原则:

原子性
一致性
隔离性:多个业务能操作同一个资源,防止数据损坏;
持久性:事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写入存储器中;

代码示例

创建Mapper接口文件:

public interface StudentMapper {
     
    public List<Stu> selectStu();

    //添加用户
    public int addStu(Stu stu);

    //删除用户
    public int deleteStu(String id);
}

编写mapper配置文件:




<mapper namespace="org.westos.mapper.StudentMapper">
    <select id="selectStu" resultType="Stu">
        select * from stu
    select>

    <insert id="addStu" parameterType="Stu">
        insert into stu(sid,sname,age,gender)
        values(#{sid},#{sname},#{age},#{gender})
    insert>

    
    <delete id="deleteStu" parameterType="java.lang.String">
        deletes from stu where id=#{id}
    delete>
mapper>

定义Mapper接口的实现类:

public class StuMapperImpl extends SqlSessionDaoSupport implements StudentMapper {
     
    public List<Stu> selectStu() {
     
        Stu stu = new Stu("00001","张小小", 20, "male");
        StudentMapper stuMapper = getSqlSession().getMapper(StudentMapper.class);
        addStu(stu);
        deleteStu("00001");
        return stuMapper.selectStu();
    }

    public int addStu(Stu stu) {
     
        return getSqlSession().getMapper(StudentMapper.class).addStu(stu);
    }

    public int deleteStu(String id) {
     
        return getSqlSession().getMapper(StudentMapper.class).deleteStu(id);
    }
}

Spring核心文件内容:


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="url"
                  value="jdbc:mysql://127.0.0.1:3306/enducation?serverTimezone=UTC&characterEncoding=utf-8"/>
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    bean>

    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        
        
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    bean>

    
    <bean id="stuMapper" class="org.westos.mapper.StuMapperImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    bean>
beans>

测试:

@Test
public void test() throws IOException {
     
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    StuMapperImpl stuMapper = (StuMapperImpl) context.getBean("stuMapper");
    List<Stu> list = stuMapper.selectStu();

    for (Stu stu : list) {
     
        System.out.println(stu);
    }
}

结果:

报错:sql异常,delete写错了;但是插入数据成功!这是因为没有进行事务的管理。我们想让添加人和删除人都成功,有一个失败,就都失败,这时候就需要用都事务。

  • 以前我们都需要自己手动管理事务,十分麻烦!但是Spring给我们提供了事务管理,我们只需要配置即可;

Spring中的事务管理

  • 使用 MyBatis-Spring 的其中一个主要原因是它允许 MyBatis 参与到 Spring 的事务管理中,而不是给 MyBatis 创建一个新的专用事务管理器,MyBatis-Spring 借助了 Spring 中的 DataSourceTransactionManager 来实现事务管理。

  • 一旦配置好了 Spring 的事务管理器,你就可以在 Spring 中按你平时的方式来配置事务。并且支持 @Transactional 注解和 AOP 风格的配置。在事务处理期间,一个单独的 SqlSession 对象将会被创建和使用。当事务完成时,这个 session 会以合适的方式提交或回滚。

  • 事务配置好了以后,MyBatis-Spring 将会透明地管理事务,这样在你的 DAO 类中就不需要额外的代码了。

  • Spring的事务管理分为两种:

编程式事务管理

将事务管理代码嵌到业务方法中来控制事务的提交和回滚

【缺点】:必须在每个事务操作业务逻辑中包含额外的事务管理代码;

声明式事务管理

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

标准配置

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

xmlns:tx="http://www.springframework.org/schema/tx"

http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

2、事务管理器

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

JDBC事务

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

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


<tx:advice id="txAdvice" transaction-manager="transactionManager">
   <tx:attributes>
       
       <tx:method name="add" propagation="REQUIRED"/>
       <tx:method name="delete" propagation="REQUIRED"/>
       <tx:method name="update" propagation="REQUIRED"/>
       <tx:method name="search*" propagation="REQUIRED"/>
       <tx:method name="get" read-only="true"/>
       <tx:method name="*" propagation="REQUIRED"/>
   tx:attributes>
tx:advice>

spring事务传播特性:

  • 事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为:

propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。

propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。

propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。

propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。

propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。

propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与

propagation_required类似的操作

  • Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况。

4、配置AOP:导入aop的头文件!


<aop:config>
    <aop:pointcut id="txPointCut" expression="execution(* org.westos.mapper.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
aop:config>

5、进行测试

@Test
public void test() throws IOException {
     
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    StuMapperImpl stuMapper = (StuMapperImpl) context.getBean("stuMapper");
    List<Stu> list = stuMapper.selectStu();

    for (Stu stu : list) {
     
        System.out.println(stu);
    }
}
  • 为什么需要配置事务?

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

你可能感兴趣的:(Java,EE)