一. 前期准备

  1. 测试环境:
    IDEA 2021.2
    MySql 8.0
    MyBatis 3.4.1
    Spring 4.3.5.RELEASE
  2. 准备数据库, 建立测试用的数据表.
  3. 创建maven工程 , 导入所有依赖. maven项目配置这里不做详细介绍.

二. 纯MyBatis操作

为方便对比, 先简单演示一遍不使用Spring的Mybatis操作, 对mybatis熟悉的可以直接跳到第六点,具体流程如下:

  1. 测试数据表/测试数据
  2. 如何在idea收集mysql的一列数据_数据库

  3. 根据数据表创建实体类, 类属性名和数据表列名保持一致
public class Person {
    private String id;
    private String name;
    /* 
    构造/getter/setter方法
	...
	 */
}
  1. 创建Dao接口, 定义操作数据库方法
public interface StudentDao {
	//测试方法: 根据ID获取数据行,返回实体类
    Student getById(int id);
}
  1. 创建mapper文件, 编写sql语句
<?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.lqw.mybatis.Dao.PersonDao">
	<!--简单写个select-->
	<select id="getById" resultType="Person">
        select id,name from person where pid=#{id}
    </select>
</mapper>
  1. 创建mybatis主配置文件
<?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"/>
    <!--  日志  -->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"/>
    </plugins>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--配置数据源 创建Connection对象-->
            <dataSource type="POOLED">
                <!--注册驱动-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/jdbctest?useUnicode=true&
                characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!--
    指定其他mapper文件的位置
    使用其中的sql语句
    -->
    <mappers>
        <!--
        使用mapper resource属性指定文件路径
        这个路径从target/classes开启
        一个mapper resource 指定一个mapper文件
        -->
        <mapper resource="com/lqw/mybatis/Dao/PerDao.xml"/>
    </mappers>
</configuration>
  1. 创建测试内容
public class MyTest {
    //测试mybatis执行sql语句
    @Test
    public void testGetById(){
        //调用mybatis某个对象的方法, 执行mapper文件中的sql语句
        //mybatis核心类 : SqlSessionFactory
        //1. 定义mybatis核心配置文件的位置
        String config="mybatis.xml";
        //2. 读取主配置文件,使用mybatis框架中的Resources类
        InputStream inputStream= null;
        try {
            inputStream = Resources.getResourceAsStream(config);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //3. 创建SqlSessionFactory对象,使用SqlSessionFactoryBuilder类
        SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
        //4. 获取SqlSession对象
        SqlSession session=factory.openSession();
        //5. 指定要执行的sql语句的id
        int id=1002;
        //6. 获取代理
        PerDao dao=session.getMapper(PerDao.class);
        Person person=dao.getById(id);
        System.out.println(person);
        //7. 关闭资源
        session.close();
    }
}

三. Mybatis-Spring整合

前四步与之前一致, 这里不做详细演示:

  1. 测试数据表/测试数据
  2. 根据数据表创建实体类
  3. 创建Dao接口, 定义操作数据库方法
  4. 创建mapper文件, 编写sql语句

MyBatis-Spring 会帮助你将 MyBatis 代码整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession 并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException。
讲人话就就是利用Spring的IOC操作实现mybatis中需要用的对象(ExampleDao/SqlSessionFactory/SqlSession等)进行对象创建属性注入.
这里分别用配置文件、注解两种方式演示实现:

基于配置文件mybatis-spring.xml

mybatis-spring.xml需要配置的元素有:

1. 数据源

在mybatis核心配置文件中数据源是在<environments>中配置,

<environments>
        <environment>
            <dataSource>
            <!--数据源-->
            </dataSource>
        </environment>
    </environments>

mybatis-spring配置:

<!-- 引入配置文件 -->
  <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:jdbc.properties" />
  </bean>
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
    <property name="driverClassName" value="${driver}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
    <!-- 初始化连接大小 -->
    <property name="initialSize" value="${initialSize}"/>
    <!-- 连接池最大数量 -->
    <property name="maxActive" value="${maxActive}"/>
    <!-- 连接池最大空闲 -->
    <property name="maxIdle" value="${maxIdle}"/>
    <!-- 连接池最小空闲 -->
    <property name="minIdle" value="${minIdle}"/>
    <!-- 获取连接最大等待时间 -->
    <property name="maxWait" value="${maxWait}"/>
  </bean>

补充知识点:工厂Bean

为方便理解mybatis-spring中的sqlSessionFactoryBean、MapperFactoryBean, 这里先讲解工厂Bean;

在Spring容器中有一类特殊的bean叫工厂bean,普通的bean注入容器内的方式是通过调用其无参构造器创建一个对象导入在容器中,而工厂bean会通过FactoryBean的接口的getObject()方法将对象注册在容器中。
工厂bean在配置文件定义的bean类型可以和返回类型不一样
工厂Bean的实现步骤:
第一步 创建类,让这个类作为工厂bean,实现接口FactoryBean
FactoryBean接口有三个方法:

getObject() //返回需要注册的对象 ,如果为单例,该实例会放到Spring容器中单实例缓存池中
getObjectType() //返回对象的类型
isSingleton() //是否是单例 ,非单例时每次创建都会返回一个新的bean

第二步 实现接口里面的方法,在实现的方法中定义返回的bean类型
通过一个自定义实例来了解工厂Bean

public class MyBean implements FactoryBean<Book> {
    @Override
    public Book getObject() throws Exception {
    	//工厂Bean实际创建的Bean对象为getObject()方法的返回对象
        Book book=new Book();
        return book;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

为什么要使用工厂Bean:
在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。

2. sqlSessionFactoryBean

在基础的 MyBatis 用法中,是通过 SqlSessionFactoryBuilder 来创建 SqlSessionFactory 的。

String config="mybatis.xml";
	InputStream inputStream= Resources.getResourceAsStream(config);
	SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);

而在 MyBatis-Spring 中,则使用 SqlSessionFactoryBean 来创建:

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

SqlSessionFactoryBean 实现了 Spring 的 FactoryBean 接口。 这意味着由 Spring 最终创建的 bean并不是 SqlSessionFactoryBean 本身,而是工厂类(SqlSessionFactoryBean)的 getObject() 方法的返回结果 SqlSessionFactory,并使用 sqlSessionFactory 这个名字存储起来。

sqlSessionFactoryBean的几个重要属性
  1. DataSource: 唯一的必要属性:用于 JDBC 的 这可以是任意的 DataSource 对象,它的配置方法和其它 Spring 数据库连接是一样的。
  2. configLocation: 它用来指定 MyBatis 的 XML 配置文件路径。需要修改 MyBatis 的基础配置( <settings><typeAliases>)时需要使用该属性引入mybatis核心配置文件.
    注意: mybatis.xml中任何环境配置(<environments>),数据源(<DataSource>)和 MyBatis 的事务管理器(<transactionManager>)都会被忽略
    MyBatis默认在映射器类对应的路径下找与之相对应的映射器 XML 文件,如果找不到则需要知道该文件位置这时有两种解决办法:
     (1) 手动在 MyBatis 的 XML 配置文件中的 <mappers> 部分中指定 XML 文件的类路径;
     (2) 设置工厂 bean 的 mapperLocations 属性。
  3. mapperLocations 属性接受多个资源位置。这个属性可以用来指定 MyBatis 的映射器 XML 配置文件的位置。属性的值是一个 Ant 风格的字符串,可以指定加载一个目录中的所有文件,或者从一个目录开始递归搜索所有目录。比如:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="mapperLocations" value="classpath*:sample/config/mappers/**/*.xml" />
</bean>

3. SqlSessionTemplate(可跳过)

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

SqlSession session=factory.openSession();
	/* 数据库操作...*/
	session.close();

MyBatis-Spring不再直接使用 SqlSessionFactory , bean 可以被注入一个线程安全的 SqlSession,它能基于 Spring 的事务配置来自动提交、回滚、关闭 session。

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

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

这个 bean 就可以直接注入到你的 DAO bean 中了。你需要在你的 bean 中添加一个 SqlSession 属性,就像下面这样:

public class UserDaoImpl implements UserDao {

  private SqlSession sqlSession;

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

  public User getUser(String userId) {
    return sqlSession.selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
  }
}

按下面这样,注入 SqlSessionTemplate

<bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
  <property name="sqlSession" ref="sqlSession" />
</bean>

4. 注入映射器

使用 SqlSessionTemplate 还需要手工编写数据访问对象 (DAO)的代码, Mybatis-spring提供封装好的动态代理实现: 注入映射器, 当使用映射器时, 不需要编写任何 DAO 实现的代码,因为 MyBatis-Spring 将会为你创建代理。
这一步相当于基础mybatis中获取代理:

PerDao dao=session.getMapper(PerDao.class);
(1)注册映射器MapperFactoryBean

MyBatis-Spring 提供了一个动态代理的实现:MapperFactoryBean。这个类可以让你直接注入数据映射器接口到你的 service 层 bean 中。
简而言之就是手动为每个Dao接口获取代理, 配置方式:

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

sqlSessionFactoryBean配置一致, 如果映射器接口 UserMapper 在相同的类路径下有对应的 MyBatis XML 映射器配置文件(推荐的),将会被 MapperFactoryBean 自动解析。不需要在 MyBatis 配置文件中显式配置映射器.

注意 MapperFactoryBean 需要配置一个 SqlSessionFactorySqlSessionTemplate。它们可以分别通过 sqlSessionFactorysqlSessionTemplate 属性来进行设置。
优先级:sqlSessionFactory > sqlSessionTemplate

(2)发现映射器 MapperScannerConfigurer

与注册映射器相比, 发现映射器不需要一个个地注册你的所有映射器。你可以让 MyBatis-Spring 对类路径进行扫描来发现它们。
有几种办法来发现映射器:

  • 使用\<mybatis:scan/>元素
  • 使用 @MapperScan 注解
  • 在经典 Spring XML 配置文件中注册一个 MapperScannerConfigurer\<mybatis:scan/>@MapperScan都在 MyBatis-Spring 1.2.0 中被引入。@MapperScan需要你使用 Spring 3.1+。

这里使用MapperScannerConfigurer演示
MapperScannerConfigurer可以作为一个 bean包含在经典的 XML 应用上下文中。 配置:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>

如果你需要指定 sqlSessionFactorysqlSessionTemplate,那你应该要指定的是 bean 名而不是 bean 的引用,因此要使用 value 属性而不是通常的 ref 属性:

<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
完整mybatis-spring.xml
<?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-4.0.xsd    
                        http://www.springframework.org/schema/context    
                        http://www.springframework.org/schema/context/spring-context-4.0.xsd">
  <context:annotation-config />
  <!-- 自动扫描 -->
  <context:component-scan base-package="com.lqw" />

  <!-- 引入配置文件 -->
  <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:jdbc.properties" />
  </bean>


  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
    <property name="driverClassName" value="${driver}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
    <!-- 初始化连接大小 -->
    <property name="initialSize" value="${initialSize}"/>
    <!-- 连接池最大数量 -->
    <property name="maxActive" value="${maxActive}"/>
    <!-- 连接池最大空闲 -->
    <property name="maxIdle" value="${maxIdle}"/>
    <!-- 连接池最小空闲 -->
    <property name="minIdle" value="${minIdle}"/>
    <!-- 获取连接最大等待时间 -->
    <property name="maxWait" value="${maxWait}"/>
  </bean>

  <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <!--mapper文件和接口文件不在同一目录下,需要加载mybatis主配置文件或 mapperLocations属性-->
<!--    <property name="configLocation" value="mybatis.xml"/>-->
    <property name="mapperLocations" value="classpath:mapper/UserMapper.xml" />
  </bean>

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

  <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <!--指定要映射的mapper接口的全限定名-->
    <property name="mapperInterface" value="对应接口全类名"/>
    <!--指定sqlSessionFactory-->
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
<!--    <property name="sqlSessionTemplate" ref="sqlSession"/>-->
  </bean>

  <!-- DAO接口所在包名,Spring会自动查找其下的类 -->
  <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="存放dao接口的全包名" />
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
  </bean>

  <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
  <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
  </bean>
</beans>

5. 创建测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath*:applicationContext.xml")
public class TestMapper {

   @Autowired
   public UserMapper userMapper;
   @Test
   public void test01(){
       User user=new User();
       user.setUser_id(11111);
       user.setName("name");
       user.setPassword("123456");
       user.setEmail("123456@qq.com");
       userMapper.insert(user);
   }
}