Spring与Mybatis整合一下

什么是 MyBatis-Spring?

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

各个框架之间存在一定的版本联系,如果两者版本对应有问题则那么程序是无法运行的。

MyBatis-Spring 需要以下版本:

MyBatis-Spring MyBatis Spring 框架 Spring Batch Java
2.0 3.5+ 5.0+ 4.0+ Java 8+
1.3 3.4+ 3.2.2+ 2.1+ Java 6+

在maven中需要添加MyBatis-Spring依赖,如下:

<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis-spring</artifactId>
   <version>2.0.2</version>
</dependency>

​ 除了mybatis-Spring依赖外,还需要添加Spring的事务依赖,因为ORM框架中肯定会出现很多事务相关的内容,所以这是后面是必不可免的!

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.2.6.RELEASE</version>
</dependency>

主要配置

​ 整合过程中我们应该把所有的配置放在Spring的配置文件中,也可以配置使用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: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">
</beans>   

配置一个数据源

首先创建一个jdbc.properties文件,里面存储一些连接数据库的信息。

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=1996613nba

然后加载配置文件

<context:property-placeholder location="classpath:jdbc.properties" />

创建数据源

<!--配置数据源:数据源有非常多,可以使用第三方的(比如说c3p0、druid等连接池),也可使使用Spring的-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <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>

创建SqlSessionFactory

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

<!--使用 SqlSessionFactoryBean来创建 SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!--配置数据源-->
    <property name="dataSource" ref="dataSource" />
    <!--配置类型别名-->
    <property name="typeAliasesPackage" value="com.mybatis.pojo"/>
    <!--扫描mapper-->
    <property name="mapperLocations" value="classpath:com/mybatis/mapper/*.xml"/>
    <!--扫描mybatis配置文件-->
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>

​ 在这个<bean>标签中可以配置原来mybatis-config.xml中的一些配置,比如数据源、别名等,甚至可以导入原来的mybatis配置文件。

注册SqlSessionTemplate

​ 在 MyBatis 中,你可以使用 SqlSessionFactory 来创建 SqlSession。一旦你获得一个 session 之后,你可以使用它来执行映射了的语句,提交或回滚连接,最后,当不再需要它的时候,你可以关闭 session。使用 MyBatis-Spring 之后,你不再需要直接使用 SqlSessionFactory 了,因为你的 bean 可以被注入一个线程安全的 SqlSession,它能基于 Spring 的事务配置来自动提交、回滚、关闭 session。

SqlSessionTemplate 是 MyBatis-Spring 的核心。作为 SqlSession 的一个实现,这意味着可以使用它无缝代替你代码中已经在使用的 SqlSessionSqlSessionTemplate 是线程安全的,可以被多个 DAO 或映射器所共享使用。

​ 当调用 SQL 方法时(包括由 getMapper() 方法返回的映射器中的方法),SqlSessionTemplate 将会保证使用的 SqlSession 与当前 Spring 的事务相关。此外,它管理 session 的生命周期,包含必要的关闭、提交或回滚操作。另外,它也负责将 MyBatis 的异常翻译成 Spring 中的 DataAccessExceptions

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

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

<!--注册sqlSessionTemplate , 关联sqlSessionFactory-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <!--利用构造器注入-->
    <constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>

创建一个简单的实例

创建一个pojo类

package com.mybatis.pojo;

import lombok.Data;

import java.util.Date;
/**
 * @author :苑勇
 * @date :Created in 2020/5/30 21:57
 * @description:User实体类
 */
@Data
public class User {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
}

创建Mapper接口

package com.mybatis;

import com.mybatis.pojo.User;

import java.util.List;

/**
 * @author :苑勇
 * @date :Created in 2020/5/30 21:56
 * @description:User接口
 */
public interface UserMapper {
    List<User> select();
}

创建一个Mapper实现类

package com.mybatis;

import com.mybatis.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

/**
 * @author :苑勇
 * @date :Created in 2020/5/30 22:52
 * @description:
 */
public class UserMapperImpl  implements UserMapper {
    /**
     * sqlSession不用我们自己创建了,Spring来管理
     */
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    @Override
    public List<User> select() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.select();
    }
}

创建mapper.xml文件

<?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.mybatis.UserMapper">
    <!--虽然返回的值是List<User> Mybatis会根据实际情况将返回值判断是User或List<User>-->
    <select id="select" resultType="user">
        select * from user where 1 = 1
    </select>
</mapper>

注入 SqlSessionTemplate

<!--注册bean实现-->
<bean id="userMapperImpl" class="com.mybatis.UserMapperImpl">
    <property name="sqlSession" ref="sqlSession" />
</bean>

测试类进行测试

import com.mybatis.pojo.User;
import com.mybatis.UserMapper;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;
/**
 * @author :苑勇
 * @date :Created in 2020/5/30 22:29
 * @description:
 */
public class MybatisSpringTest {
    @Test
    public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper mapper = (UserMapper) context.getBean("userMapperImpl");
        List<User> user = mapper.select();
        System.out.println(user);
    }
}

测试结果

JDBC Connection [com.mysql.jdbc.JDBC4Connection@3c7c886c] will not be managed by Spring
==>  Preparing: select * from user where 1 = 1 
==> Parameters: 
<==    Columns: id, username, birthday, sex, address
<==        Row: 1, CodeYuan-Y, null, 男, 山东青岛
<==        Row: 10, 张三, 2014-07-10, 1, 北京市
<==        Row: 16, 张小明, null, 1, 河南郑州
<==        Row: 22, 陈小明, null, 1, 河南郑州
<==        Row: 24, 张三丰, null, 1, 河南郑州
<==        Row: 25, 陈小明, null, 1, 河南郑州
<==        Row: 26, 王五, null, null, null
<==        Row: 35, CodeYuan-Y, 2020-03-23, 男, 青岛市
<==      Total: 8
Closing non transactional SqlSession 

另一种实现方式

SqlSessionDaoSupport 是一个抽象的支持类,用来为你提供 SqlSession。调用 getSqlSession() 方法你会得到一个 SqlSessionTemplate

​ 然后我们可以将上面的UserMapperImpl类改为以下

package com.mybatis;

import com.mybatis.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

/**
 * @author :苑勇
 * @date :Created in 2020/5/30 22:52
 * @description:
 */
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {

    @Override
    public List<User> select() {
        UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
        return mapper.select();
    }
}

​ 然后可以把applicationContext.xml中的关于SqlSessionTemplatebean去掉,而且注册bean应改为以下方式。

<!--注册bean实现-->
<bean id="userMapperImpl" class="com.mybatis.UserMapperImpl">
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

事务

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

编程式事务管理

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

声明式事务管理

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

事务管理器

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

开启Spring的事务管理

<!--引入Spring事务-->
<bean id="transactionManager" 		        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

然后配置事务的通知

<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!--* 代表所有-->
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

spring事务传播特性:

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

  • required:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
  • supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
  • mandatory:使用当前事务,如果没有当前事务,就抛出异常。
  • required_new:新建事务,如果当前存在事务,把当前事务挂起。
  • supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • never:以非事务方式执行操作,如果当前事务存在则抛出异常。
  • nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与required类似的操作

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

最后将其织入AOP

<!--配置AOP织入事务-->
<aop:config>
    <aop:pointcut id="txPointcut" expression="execution(* com.mybatis.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>

一个小例子

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {

	@Override
    public List<User> select() {
        User user = new User();
        user.setUsername("小明");

        User user2 = new User();
        user2.setId(16);
        user2.setUsername("小明");

        UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
        mapper.insert(user);
        mapper.insert(user2);
        return mapper.select();
    }
}

​ id为16得数据已经存在于数据库当中,上面代码当没有配置事务时,执行这个方法可以成功得将user对象得数据插入到数据库当中,但是user2并不能,但是当事务开启时,user得数据也不能插入,这就符合了事务得原子性。

猜你喜欢

转载自blog.csdn.net/WX_1218639030/article/details/106479563