开源持久化框架Mybatis保姆级教程(一篇够用)

209 阅读13分钟

image.png 版本3.5.9

课程案例源代码

https://gitee.com/ossbar/mybatis.git

环境要求

  • JDK1.8+
  • MySQL8.0.27
  • Maven 3.6.1
  • IDEA/VSCode

学习建议

MyBatis的学习分为四个阶段:了解---->>入门--->>熟悉--->>拓展

了解阶段:请参考官方指导文档入门学习基础知识。

入门阶段:能把MyBatis技术灵活应用于实际项目中。

熟悉阶段:研究MyBatis原理、 MyBatis源码。

拓展阶段:基于Mybatis框架,进行封装和扩展,例如开发扩展插件:例如Mybatis-plus,Mybatis-generator等。

学习建议:看官方文档,最为详细

mybatis.org/mybatis-3/z…

知识导图

image.png

适宜人群

本教程适合:

  1. 想要深入学习 MyBatis 框架的小伙伴
  2. 零散学习过 MyBatis ,但对 MyBatis 整体了解不够深入的小伙伴
  3. 对 MyBatis 的内部和底层感兴趣的小伙伴
  4. 有意向以后成为高级开发的小伙伴
  5. 有打算自己封装一套属于自己的用来做项目开发脚手架的小伙伴

你会学到什么

  1. 配置文件、Mapper 映射文件的编写和设计
  2. MyBatis 中的注解使用详解
  3. MyBatis 中的缓存、事务、插件等机制
  4. MyBatis 的整体生命周期、执行流程全剖析
  5. MyBatis 中使用到的设计模式详解
  6. 自己动手二次封装 MyBatis

Mybatis简介

Mybatis是什么

MyBatis(前身是iBatis) 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射,可以在实体类和 SQL 语句之间建立映射关系,是一种半自动化的 ORM (Object/Relation Mapping,即对象关系映射)实现。其封装性低于 Hibernate,但性能优秀、小巧、简单易学、应用广泛。

image.png 优点

  • MyBatis 是免费且开源的。
  • 与 JDBC 相比,减少了 50% 以上的代码量。
  • MyBatis 是最简单的持久化框架,小巧并且简单易学。
  • MyBatis 相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL 写在 XML 中,和程序逻辑代码分离,降低耦合度,便于同一管理和优化,提高了代码的可重用性。
  • 提供 XML 标签,支持编写动态 SQL 语句。
  • 提供映射标签,支持对象与数据库的 ORM 字段关系映射。
  • 支持存储过程。MyBatis 以存储过程的形式封装 SQL,可以将业务逻辑保留在数据库之外,增强应用程序的可移植性、更易于部署和测试。

缺点

  • 编写 SQL 语句工作量较大,对开发人员编写 SQL 语句的功底有一定要求。
  • SQL 语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

Mybatis能干什么

MyBatis 专注于 SQL 本身,是一个足够灵活的 DAO 层解决方案。适用于性能要求高,且需求变化较多的项目,如互联网项目。

安装Mybatis

方法一:下载:github.com/mybatis/myb…

点击Mybatis-3.5.9.zip进行下载,下载后解压目录如下:

使用MyBatis框架非常简单,只需在应用程序中引入MyBatis的核心包和lib目录中的依赖包即可。

image.png

注意:如果底层采用的是MySQL数据库,那么还需要将MySQL数据库的驱动JAR包添加到应用程序的类路径中;如果采用其他类型的数据库,则同样需要将对应类型的数据库驱动包添加到应用程序的类路径中。

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
    <scope>runtime</scope>
</dependency>

方法二:如果基于Maven工程使用Mybatis持久化框架,在工程的pom.xml文件中引入如下依赖

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

Mybatis工作原理

使用Mybatis之前,首先要了解Mybatis原理和工作流程。

image.png

MyBatis组件以及执行基本流程

  1. SqlSessionFactoryBuilder(构造器):它会根据配置信息或者代码生成SqlSessionFactory(工厂接口)
  2. SqlSessionFactory:依靠工厂来生成SqlSession。
  3. SqlSession:是一个既可以发送SQL去执行并返回结果的,也可以获取Mapper接口,通过Mapper接口查询并封装数据。
  4. SQL Mapper:它是MyBatis新设计的组件,它是由一个Java接口和XML文件(或者注解)构成的,需要给出对应的SQL和映射规则。它负责发送SQL去执行,并返回结果。

用下图表达上述组件之间的关联

image.png

Mybatis核心对象

什么是SqlSessionFactory?

•SqlSessionFactory是MyBatis框架中十分重要的对象,它是单个数据库映射关系经过编译后的内存镜像,其主要作用是创建SqlSession。有点类似于我们在JDBC中使用的Connection

•SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象来构建,而SqlSessionFactoryBuilder则可以通过XML配置文件或一个预先定义好的Configuration实例构建出SqlSessionFactory的实例。

构建SqlSessionFactory

•通过XML配置文件构建出的SqlSessionFactory实例现代码如下:

InputStream inputStream = Resources.getResourceAsStream("配置文件位置");
SqlSessionFactory sqlSessionFactory =  new SqlSessionFactoryBuilder().build(inputStream);

•SqlSessionFactory对象是线程安全的,它一旦被创建,在整个应用执行期间都会存在。如果我们多次的创建同一个数据库的SqlSessionFactory,那么此数据库的资源将很容易被耗尽。为此,通常每一个数据库都会只对应一个SqlSessionFactory,所以在构建SqlSessionFactory实例时,建议使用单列模式。

什么是SqlSession?

•SqlSession是MyBatis框架中另一个重要的对象,它是应用程序与持久层之间执行交互操作的一个单线程对象,其主要作用是执行持久化操作。它可以发送一条SQL语句去执行,并返回结果,从这个角度来说,它有点类似于PrepareStatement。

使用完SqlSession对象后要及时关闭,通常可以将其放在finally块中关闭。

SqlSession中的方法

查询方法:

<T> T selectOne(String statement);
<T> T selectOne(String statement, Object parameter);
<E> List<E> selectList(String statement);
<E> List<E> selectList(String statement, Object parameter);
<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
void select(String statement, Object parameter, ResultHandler handler);

插入、更新和删除方法:

int insert(String statement);
int insert(String statement, Object parameter);
int update(String statement);
int update(String statement, Object parameter);
int delete(String statement);
int delete(String statement, Object parameter);

其他方法:

void commit();   提交事务的方法。
void rollback();   回滚事务的方法。
void close();   关闭SqlSession对象。
<T> T getMapper(Class<T> type);   返回Mapper接口的代理对象。
Connection getConnection();   获取JDBC数据库连接对象的方法。

使用工具类创建SqlSession

为了简化开发,通常在实际项目中都会使用工具类来创建SqlSession。

public class MybatisUtils {
   private static SqlSessionFactory sqlSessionFactory = null;
   static {
     try {
          Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
          sqlSessionFactory =  new SqlSessionFactoryBuilder().build(reader);
     } catch (Exception e) {
          e.printStackTrace();
     }
   }
   public static SqlSession getSession() {
     return sqlSessionFactory.openSession();
   }
}

Mybatis映射文件

主要元素

在MyBatis框架的核心配置文件中,元素是配置文件的根元素,其他元素都要在元素内配置。

img

元素

是一个配置属性的元素,该元素通常用来将内部的配置外在化,即通过外部的配置来动态的替换内部定义的属性。例如,数据库的连接等属性,就可以通过典型的Java属性文件中的配置来替换,具体方式如下:

1、编写db.properties

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

2、配置<properties... />属性

<properties resource="db.properties" />

3、修改配置文件中数据库连接的信息

<dataSource type="POOLED">
    <!-- 数据库驱动 -->
    <property name="driver" value="${jdbc.driver}" />
    <!-- 连接数据库的url -->
    <property name="url" value="${jdbc.url}" />
    <!-- 连接数据库的用户名 -->
    <property name="username" value="${jdbc.username}" />
    <!-- 连接数据库的密码 -->
    <property name="password" value="${jdbc.password}" />
</dataSource>

元素

元素主要用于改变MyBatis运行时的行为,例如开启二级缓存、开启延迟加载等。

这些配置在配置文件中的使用方式如下:

<!-- 设置 -->  
<settings>     
    <setting name="cacheEnabled" value="true" />
    <setting name="lazyLoadingEnabled" value="true" />
    <setting name="multipleResultSetsEnabled" value="true" />
    <setting name="useColumnLabel" value="true" />
    <setting name="useGeneratedKeys" value="false" />
    <setting name="autoMappingBehavior" value="PARTIAL" />       
    ...
</settings>

小提示:上述配置通常不需要开发人员去配置,作为了解即可。

元素

元素用于为配置文件中的Java类型设置一个简短的名字,即设置别名。别名的设置与XML配置相关,其使用的意义在于减少全限定类名的冗余。

1、使用元素配置别名的方法如下:

<typeAliases>
  <typeAlias alias="user" type="com.creatorblue.po.User"/>
</typeAliases>

2、当POJO类过多时,可以通过自动扫描包的形式自定义别名,具体如下:

<typeAliases>
  <package name="com.creatorblue.po"/>
</typeAliases>

注意:如果在程序中使用了注解,则别名为其注解的值。

MyBatis框架默认为许多常见的Java类型提供了相应的类型别名,如下表所示。

img

元素

typeHandler的作用就是将预处理语句中传入的参数从javaType(Java类型)转换为jdbcType(JDBC类型),或者从数据库取出结果时将jdbcType转换为javaType。

元素可以在配置文件中注册自定义的类型处理器,它的使用方式有两种。

1、注册一个类的类型处理器

<typeHandlers> 
   <typeHandler handler="com.itheima.type.CustomtypeHandler" />
</typeHandlers>

2、注册一个包中所有的类型处理器

<typeHandlers> 
   <package name="com.itheima.type" />
</typeHandlers>

元素

MyBatis中默认的ObjectFactory的作用是实例化目标类,它既可以通过默认构造方法实例化,也可以在参数映射存在的时候通过参数构造方法来实例化。通常使用默认的ObjectFactory即可。

大部分场景下都不用配置和修改默认的ObjectFactory ,如果想覆盖ObjectFactory的默认行为,可以通过自定义ObjectFactory来实现,具体如下:

1、自定义一个对象工厂

public class MyObjectFactoryextends DefaultObjectFactory {
    private static final long serialVersionUID= -4114845625429965832L;
    public <T> T create(Class<T> type) {
        returnsuper.create(type);
    }
    public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
        returnsuper.create(type,constructorArgTypes,constructorArgs);
    }
    public void setProperties(Properties properties) {
        super.setProperties(properties);
    }
    public <T> booleanisCollection(Class<T> type) {
        returnCollection.class.isAssignableFrom(type);
    }
}

2、在配置文件中使用元素配置自定义的ObjectFactory

<objectFactory type="com.creatorblue.factory.MyObjectFactory">
   <property name="name" value="MyObjectFactory"/>
</objectFactory>

注意:由于自定义ObjectFactory在实际开发时不经常使用,这里只需要了解即可。

元素

MyBatis允许在已映射语句执行过程中的某一点进行拦截调用,这种拦截调用是通过插件来实现的。元素的作用就是配置用户所开发的插件。

如果用户想要进行插件开发,必须要先了解其内部运行原理,因为在试图修改或重写已有方法的行为时,很可能会破坏MyBatis原有的核心模块。

元素

元素用于对环境进行配置。MyBatis的环境配置实际上就是数据源的配置,我们可以通过元素配置多种数据源,即配置多种数据库。

使用元素进行环境配置的示例如下:

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

事务管理器的配置

在MyBatis中,可以配置两种类型的事务管理器,分别是JDBC和MANAGED。关于这两个事务管理器的描述如下:

lJDBC:此配置直接使用了JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务的作用域。

lMANAGED:此配置从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。默认情况下,它会关闭连接,但一些容器并不希望这样,为此可以将closeConnection属性设置为false来阻止它默认的关闭行为。

注意:如果项目中使用的是Spring+ MyBatis,则没有必要在MyBatis中配置事务管理器,因为实际开发中,会使用Spring自带的管理器来实现事务管理。

元素

元素用于指定MyBatis映射文件的位置,一般可以使用以下4种方法引入映射器文件,具体如下。

1、使用类路径引入

<mappers>
    <mapper resource="com/creatorblue/mapper/UserMapper.xml"/>
</mappers>

2、使用本地文件路径引入

<mappers>
    <mapper url="file:///D:/com/creatorblue/mapper/UserMapper.xml"/>
</mappers>

3、使用接口类引入

<mappers>
    <mapper class="com.creatorblue.mapper.UserMapper"/>
</mappers>

4、使用包名引入

<mappers>
    <package name="com.creatorblue.mapper"/>
</mappers>

Mybatis入门程序

查询客户

在实际开发中,查询操作通常都会涉及到单条数据的精确查询,以及多条数据的模糊查询。

img

根据客户编号查询客户信息

1、MySQL数据库中,创建一个名为mybatis的数据库,在此数据库中创建一个t_customer表,同时预先插入几条数据。

2、在Eclipse中,创建一个名为chapter06的Web项目,将MyBatis的核心JAR包、lib目录中的依赖JAR包,以及MySQL数据库的驱动JAR包一同添加到项目的lib目录下, 并发布到类路径中。

img

3、由于MyBatis默认使用log4j输出日志信息,所以如果要查看控制台的输出SQL语句,那么就需要在classpath路径下配置其日志文件。在项目的src目录下创建log4j.properties文件。Apache 开源项目 Log4j 的远程代码执行漏洞细节2021年12月被公开,由于 Log4j 的广泛使用,该漏洞一旦被攻击者利用会造成严重危害。据悉,Apache Log4j 2.x <= 2.14.1 版本均回会受到影响,所以建议log4j升级到2.17.0以上版本或使用logback替换log4j

# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.com.creatorblue=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

4、在src目录下,创建一个com.creatorblue.po包,在该包下创建持久化类Customer,并在类中声明id、username、jobs和phone属性,及其对应的getter/setter方法。

public class Customer {
    private Integer id;        
  private String username;  
  private String jobs;       
  private String phone 
            //省略Getter和Setter方法
  @Override
  public String toString() {
     return "Customer [id=" + id + ", username=" + username + 
            ", jobs=" + jobs + ", phone=" + phone + "]";
   }
}

5、在src目录下,创建一个com.creatorblue.mapper包,并在包中创建映射文件CustomerMapper.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.creatorblue.mapper.CustomerMapper"> 
  <select id="findCustomerById" parameterType="Integer"
          resultType="com.creatorblue.po.Customer">
      select * from t_customer where id = #{id}
  </select>
</mapper>

6、在src目录下,创建MyBatis的核心配置文件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> 
    <environments default="mysql"> 
      <environment id="mysql"> 
          <transactionManager type="JDBC" /> 
          <dataSource type="POOLED">
               <property name="driver" value="com.mysql.jdbc.Driver" />
              <property name="url" value="jdbc:mysql://localhost:3306/mybatis" />              
               <property name="username" value="root" />
               <property name="password" value="root" />
          </dataSource>
      </environment>
  </environments> 
  <mappers>
      <mapper resource="com/creatorblue/mapper/CustomerMapper.xml"/>
  </mappers>
</configuration>

7、在src目录下,创建一个com.creatorblue.test包,在该包下创建测试类MybatisTest,并在类中编写测试方法findCustomerByIdTest()。

public class MybatisTest {
    @Test
    public void findCustomerByIdTest() throws Exception {                      
      String resource = "mybatis-config.xml";
      InputStream inputStream = Resources.getResourceAsStream(resource
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);  
    SqlSession sqlSession = sqlSessionFactory.openSession();
     Customer customer = sqlSession.selectOne("com.creatorblue.mapper.CustomerMapper.findCustomerById”, 1);
     System.out.println(customer.toString());
     sqlSession.close();
  }
}

img

根据客户名模糊查询客户信息

只需要在映射文件CustomerMapper.xml中,添加根据客户名模糊查询客户信息列表的SQL语句。

<select id="findCustomerByName" parameterType="String" resultType="com.creatorblue.po.Customer">
   select * from t_customer where username like '%${value}%'
</select>

添加客户

添加操作是通过元素来实现的。例如,向数据库中的t_customer表中插入一条数据可以通过如下配置来实现。

<insert id="addCustomer"  parameterType="com.creatorblue.po.Customer">
  insert into t_customer(username,jobs,phone) values(#{username},#{jobs},#{phone})
</insert>

在测试类MybatisTest中,添加测试方法addCustomerTest()。

public void addCustomerTest() throws Exception{
  …
    Customer customer = new Customer();
  customer.setUsername("rose");
  customer.setJobs("student");
  customer.setPhone("13333533092");
  int rows = sqlSession.insert("com.creatorblue.mapper.CustomerMapper.addCustomer", customer);
  …
}

更新客户

更新操作在映射文件中是通过配置元素来实现的。

<update id="updateCustomer" parameterType="com.creatorblue.po.Customer">
   update t_customer set username=#{username},jobs=#{jobs},phone=#{phone} where id=#{id}
</update>

在测试类MybatisTest中,添加测试方法updateCustomerTest(),

将id为4的用户职业修改为programmer,电话修改为13311111111。

public void updateCustomerTest() throws Exception{
  …
  Customer customer = new Customer();
  customer.setId(4);
  customer.setUsername("rose");
  customer.setJobs("programmer");
  customer.setPhone("13311111111"); 
  int rows = sqlSession.update("com.creatorblue.mapper.CustomerMapper.updateCustomer", customer);
  …
}

删除客户

删除操作在映射文件中是通过配置元素来实现的。

<delete id="deleteCustomer" parameterType="Integer">
   delete from t_customer where id=#{id}
</delete>

在测试类MybatisTest中,添加测试方法deleteCustomerTest(),该方法用于将id为4的客户信息删除。

public void deleteCustomerTest() throws Exception{
  …
  int rows = sqlSession.delete("com.creatorblue.mapper.CustomerMapper.deleteCustomer", 4);
  …
}

动态SQL语句

动态SQL有什么作用?

开发人员在使用JDBC或其他类似的框架进行数据库开发时,通常都要根据需求去手动拼装SQL,这是一个非常麻烦且痛苦的工作,而MyBatis提供的对SQL语句动态组装的功能,恰能很好的解决这一麻烦工作。

动态SQL是MyBatis的强大特性之一,MyBatis3采用了功能强大的基于OGNL的表达式来完成动态SQL。动态SQL主要元素如下表所示:

img

IF元素

在MyBatis中,元素是最常用的判断语句,它类似于Java中的if语句,主要用于实现某些简单的条件选择。其基本使用示例如下:

select * from t_customer where 1=1 
     <if test="username !=null and username !=''">
          and username like concat('%',#{username}, '%')
     </if>
     <if test="jobs !=null and jobs !=''">
          and jobs= #{jobs}
     </if>

使用元素对username和jobs进行非空判断,并动态组装SQL

在实际应用中,我们可能会通过多个条件来精确的查询某个数据。例如,要查找某个客户的信息,可以通过姓名和职业来查找客户,也可以不填写职业直接通过姓名来查找客户,还可以都不填写而查询出所有客户,此时姓名和职业就是非必须条件。

choose及其子元素

 select * from t_customer where 1=1
      <choose>
           <when test="username !=null and username !=''">
                       and username like concat('%',#{username}, '%')
           </when>
           <when test="jobs !=null and jobs !=''">
                       and jobs= #{jobs}
           </when>
           <otherwise>
                   and phone is not null
           </otherwise>
      </choose>

使用及其子元素依次对条件进行非空判断,并动态组装SQL

where、Trim元素

在前两个小节的案例中,映射文件中编写的SQL后面都加入了“where 1=1”的条件,那么到底为什么要这么写呢?如果将where后“1=1”的条件去掉,那么MyBatis所拼接出来的SQL将会如下所示:

select * from t_customer where and username like concat('%',?, '%')

可以看出上面SQL语句明显存在SQL语法错误,而加入了条件“1=1”后,既保证了where后面的条件成立,又避免了where后面第一个词是and或者or之类的关键词。不过“where 1=1”这种写法对于初学者来将不容易理解,并且也不够雅观。

针对上述情况中“where 1=1”,在MyBatis的SQL中就可以使用或元素进行动态处理。

img

select * from t_customer
<where>
    <if test="username !=null and username !=''">
      and username like concat('%',#{username}, '%')
  </if>
  <if test="jobs !=null and jobs !=''">
    and jobs= #{jobs}
  </if>
</where>
select * from t_customer
<trim prefix="where" prefixOverrides="and">
    <if test="username !=null and username !=''">
         and username like concat('%',#{username}, '%')
    </if>
    <if test="jobs !=null and jobs !=''">
         and jobs= #{jobs}
    </if>
</trim>

set元素

在Hibernate中,想要更新某个对象,就需要发送所有的字段给持久化对象,这种想更新的每一条数据都要将其所有的属性都更新一遍的方法,其执行效率是非常差的。为此,在MyBatis中可以使用动态SQL中的元素进行处理:

<update id="updateCustomer"  parameterType="com.creatorblue.po.Customer">
        update t_customer 
        <set>
            <if test="username !=null and username !=''">
                  username=#{username},
            </if>
            <if test="jobs !=null and jobs !=''">
                  jobs=#{jobs},
            </if>
        </set>
        where id=#{id}
</update>

使用和元素对username和jobs进行更新判断,并动态组装SQL。这样就只需要传入想要更新的字段即可

foreach元素

假设如下需求:

在一个客户表中有1000条数据,现在需要将id值小于100的客户信息全部查询出来,这要怎么做呢?

img

针对上述需求,理想的解决方法就是使用MyBatis中动态SQL的元素进行处理。其基本使用示例如下所示:

<select id="findCustomerByIds" parameterType="List" resultType="com.creatorblue.po.Customer">
     select * from t_customer where id in
     <foreach item="id" index="index" collection="list" 
              open="(" separator="," close=")">
         #{id}
     </foreach>
</select>

关于上述示例中元素中使用的几种属性的描述具体如下:

item:配置的是循环中当前的元素。

index:配置的是当前元素在集合的位置下标。

collection:配置的list是传递过来的参数类型(首字母小写),它可以是一个array、list(或collection)、Map集合的键、POJO包装类中数组或集合类型的属性名等。

open和close:配置的是以什么符号将这些集合元素包装起来。

separator:配置的是各个元素的间隔符。

在使用时最关键也是最容易出错的就是collection属性,该属性是必须指定的,而且在不同情况下,该属性的值是不一样的。主要有以下3种情况:

1、如果传入的是单参数且参数类型是一个数组或者List的时候,collection属性值分别为array和list(或collection)。

2、如果传入的参数是多个的时候,就需要把它们封装成一个Map了,当然单参数也可以封装成Map集合,这时候collection属性值就为Map的键。

3、如果传入的参数是POJO包装类的时候,collection属性值就为该包装类中需要进行遍历的数组或集合的属性名。

bind元素

还记得入门案例中模糊查询的SQL语句么?

select * from t_customer where username like '%${value}%'

上述SQL语句有什么不妥?

1、如果使用“${}”进行字符串拼接,则无法防止SQL注入问题;

2、如果改用concat函数进行拼接,则只针对MySQL数据库有效;

3、如果改用“||”进行字符串拼接,则只针对Oracle数据库有效。

select * from t_customer where username like concat('%',#{value},'%')

小提示:这样,映射文件中的SQL就要根据不同的情况提供不同形式的实现,这显然是比较麻烦的,且不利于项目的移植。为了减少这种麻烦,就可以使用MyBatis的元素来解决这一问题。

MyBatis的元素可以通过OGNL表达式来创建一个上下文变量,其使用方式如下:

     <select id="findCustomerByName" parameterType="com.creatorblue.po.Customer"
                 resultType="com.creatorblue.po.Customer">
          <bind name="pattern_username" value="'%'+_parameter.getUsername()+'%'" />
           select * from t_customer 
           where 
           username like #{pattern_username}
     </select>

_parameter.getUsername()表示传递进来的参数(也可以直接写成对应的参数变量名,如username)

需要的地方直接引用元素的name属性值即可

Mybatis的关联映射

为什么学习MyBatis关联关系?

实际的开发中,对数据库的操作常常会涉及到多张表,这在面向对象中就涉及到了对象与对象之间的关联关系。针对多表之间的操作,MyBatis提供了关联映射,通过关联映射就可以很好的处理对象与对象之间的关联关系。本章中,将对MyBatis的关联关系映射进行详细的讲解。

在关系型数据库中,多表之间存在着三种关联关系,分别为一对一、一对多和多对多,如下图所示:

img

在Java中,通过对象也可以进行关联关系描述,如图下图所示:

img

1对1关系

在现实生活中,一对一关联关系是十分常见的。例如,一个人只能有一个身份证,同时一个身份证也只会对应一个人。

img

那么使用MyBatis是怎么处理图中的这种一对一关联关系的呢?

在前面章节所讲解的元素中,包含了一个子元素,MyBatis就是通过该元素来处理一对一关联关系的。

在元素中,通常可以配置以下属性:

img

使用元素进行一对一关联映射非常简单,只需要参考如下两种示例配置即可。

img

1对多关系

开发人员接触更多的关联关系是一对多(或多对一)。例如,一个用户可以有多个订单,同时多个订单归一个用户所有。

img

那么使用MyBatis是怎么处理这种一对多关联关系的呢?

在前面章节所讲解的元素中,包含了一个子元素,MyBatis就是通过该元素来处理一对多关联关系的。

子元素的属性大部分与元素相同,但其还包含一个特殊属性--ofType 。

img

img

多对多关系

在实际项目开发中,多对多的关联关系也是非常常见的。以订单和商品为例,一个订单可以包含多种商品,而一种商品又可以属于多个订单。

img

在数据库中,多对多的关联关系通常使用一个中间表来维护,中间表中的订单id作为外键参照订单表的id,商品id作为外键参照商品表的id。

img

在MyBatis中,多对多的关联关系查询,同样可以使用前面介绍的元素进行处理(其用法和一对多关联关系查询语句用法基本相同)。

别名的定义

在MyBatis的映射文件中,如果参数类型是一个实体类对象,在parameterType中需要使用此对象类型的全称,类的全称一般都比较长,在编写时即繁琐又容易出错。如下TypeMapper.xml的insert元素

<insert id="insertType" parameterType="com.cbmv.domain.Type">
   ................
</insert>

此时可以为这些类型定义别名,在xml中对应的位置使用别名,别名的定义使用MyBatis配置文件中typeAliases元素,它的子元素typeAlias用于定义每一个别名,

typeAlias元素的属性

type类或接口的全称
alias别名

示例

<typeAliases>
    <typeAlias type="com.cbmv.domain.Type" alias="Type"/>
</typeAliases>


修改TypeMapper.xml的insert元素,参数使用别名

<insert id="insertType" parameterType="Type">
    ................
</insert>

如果要定义别名的类型很多,也可以使用package元素进行定义,package的name属性指定类或接口所在的包的名称,此时类和接口的别名为它们的短名称(去掉包名后的名称)。

示例

<typeAliases>
    <package name="com.cbmv.domain"/>
</typeAliases>


TypeMapper.xml的insert元素

<insert id="insertType" parameterType="Type">
  ................
</insert>

自定义类型转换器

MyBatis在对实体属性和表字段映射时会根据双方的类型自动进行类型转换,但是有些情况,比如实体中的日期为字符串,并且包含中文,而数据库中使用的是datetime。此时mybatis无法自动实现转换。需要自定义类型转换器

MyBatis的类型转换器需要实现org.apache.ibatis.type.TypeHandler接口,并实现如下几个方法

public T getResult(ResultSet rs, String columnName) throws SQLException从结果集中获取值,并转换成需要的数据 rs : 数据集 columnName : 字段名
public String getResult(ResultSet rs, int index) throws SQLException从结果集中获取值,并转换成需要的数据 rs : 数据集 index: 字段的位置,从1开始
public String getResult(CallableStatement callback, int index) throws SQLException从数据库函数的返回值中获取值,并转换成需要的数 据 callback : 执行对象 index : 返回值在结果集中的位置
public void setParameter(PreparedStatement ps, int index, String value, JdbcType type) throws SQLException把参数的值传递能JDBC执行对象 ps : 执行对象 index : 参数的位置,从1开始 value : 参数的值 type : 数据库中此字段的mybaits类型,

示例

实现日期转换器,Type类中添加createTime属性,类型字符串,日期格式为“yyyy年MM月dd日”,在t_type表中定义create_time字段,类型为datetime。

  • 定义类型转换器

创建包:com.creatorblue.handler,创建类DateConverStringHandler,实现TypeHandler接口

public class DateConverStringHandler implements TypeHandler<String> {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd");
//从数据库取出日期转成字符串
@Override
public String getResult(ResultSet arg0, String arg1) throws SQLException {

return sdf.format(arg0.getDate(arg1));
}
        //从数据库取出日期转成字符串
@Override
public StringgetResult(ResultSet arg0, int arg1) throws SQLException {
// TODO Auto-generated method stub
return  sdf.format(arg0.getDate(arg1));
}
            //此方法不实现
@Override
public String getResult(CallableStatement arg0, int arg1) throws SQLException {
// TODO Auto-generated method stub
return null;
}
        //把字符串转成数据库的日期
@Override
public void setParameter(PreparedStatement arg0, int arg1, String arg2, JdbcType arg3) throws SQLException {

arg0.setDate(arg1, new java.sql.Date(sdf.parse(arg2).getTime()));
}
}

类型转换器在使用时,分为全局和局部两种方式

全局转换器的使用

全局转换器是在Mybatis的配置文件中通过typeHandlers定义,当Mybatis在执行的过程中遇到全局转换所指定的类型时,会自动调用此转换器进行转换,MyBatis中内置的转换器都是全局转换器。

typeHandlers的子元素typeHandler用于定义每一个全局转换器,它的属性有:

handler转换器类的全称,也可以是typeAliases元素定义的别名
jdbcType字段的类型,必须是org.apache.ibatis.type.JdbcType枚举的值
javaTypejava类型

示例

<typeHandlers>
<typeHandler handler="com.creatorblue.handler.DateConverStringHandler" jdbcType="TIMESTAMP" javaType="java.lang.String"/>
</typeHandlers>

设置全局转换器后,不需要再做其它设置,当遇到所指定的类型时,MyBatis会自动调用此转换器进行转换。

局部转换器的使用

局部转换器是指在映射文件中特定的位置显示的使用类型转换器,如在resultMap元素的某一个字段映射上使用,以及在传参赋值时调用

字段映射

<result column="create_time" property="createTime" typeHandler="DateConverStringHandler"/>

赋值调用

<insert id="insertType" parameterType="type">
...............
#{createTime,typeHandler=DateConverStringHandler}
..........
</insert>

分页的实现

在MyBatis要实现分页查询非常简单,MyBatis提供了PageHelper接口用于实现分页查询,本教程使用5.1.2版本。

1、导包

引入pagehelper-5.1.2.jar包到项目中,此包可以在repo1.maven.org/maven2/com/…下找到

还需要引用关联的包jsqlparser-0.9.5.jar,此包可以在repo1.maven.org/maven2/com/…下找到

2、在Mabatis的配置文件中设置插件

<plugins>
    <!-- com.github.pagehelper为PageHelper类所在包名 -->
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!-- 数据库的类型 -->
            <property name="helperDialect" value="mysql" />
            <!-- 该参数默认为false -->
            <!-- 设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用 -->
            <!-- 和startPage中的pageNum效果一样 -->
            <property name="offsetAsPageNum" value="true" />
            <!-- 该参数默认为false -->
            <!-- 设置为true时,使用RowBounds分页会进行count查询 -->
            <property name="rowBoundsWithCount" value="true" />
            <!-- 设置为true时,如果pageSize=0或者RowBounds.limit = 0就会查询出全部的结果 -->
            <!-- (相当于没有执行分页查询,但是返回结果仍然是Page类型) -->
            <property name="pageSizeZero" value="true" />
            <!-- 3.3.0版本可用 - 分页参数合理化,默认false禁用 -->
            <!-- 启用合理化时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页 -->
            <!-- 禁用合理化时,如果pageNum<1或pageNum>pages会返回空数据 -->
            <property name="reasonable" value="false" />
            <!-- 3.5.0版本可用 - 为了支持startPage(Object params)方法 -->
            <!-- 增加了一个`params`参数来配置参数映射,用于从Map或ServletRequest中取值 -->
            <!-- 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值 -->
            <!-- 不理解该含义的前提下,不要随便复制该配置 -->
            <property name="params" value="pageNum=start;pageSize=limit;" />
            <!-- always总是返回PageInfo类型,check检查返回类型是否为PageInfo,none返回Page -->
            <property name="returnPageInfo" value="check" />
    </plugin>
</plugins>

3、分页查询

查询方法的前一行调用PageHelper.startPage静态方法,常用带两个参数的重载,第一个参数为当前页码,第二个参数为每页显示数。

PageHelper.startPage(1, 10); //第一页显示10条记录
List<Type> list =session.getMapper(TypeMapper.class).selectAll(type);

4、处理分页结果

PageInfo<Type> page = new PageInfo<Type>(list);
System.out.println("总页数:" + page.getPages() 
    + "\r总记录数:" + page.getTotal()
    + "\r当前页码" + page.getPageNum()
    + "\r每页显示数:" + page.getSize()
    + "\r数据集合中的元素:" + page.getList().get(0).getTypeCode());

使用接口和注解实现

接口实现

使用接口来实现调用可以更好的简化代码

SqlSession对象的getMapper方法可以获得定义的接口对象,此接口的名称与映射文件中的namespace相同,MyBatis能通过此名称方便的找到映射文件中对应的mapper元素

以下以配件商城的类型管理为例讲解使用接口如何实现Mybaits的调用

实现步骤

定义接口

在com.cashop.dao.mapper包中定义接口TypeMapper,并在接口中声明数据访问方法

public interface TypeMapper {
/**
 * 查询总记录数
 * @return
 */
int selectCount();
/**
 * 分页查询所有分类
 * @param list
 * @return
 */
List<Type> selectAll(List<Object> list);
/**
 * 根据ID查询分类
 * @param typeId
 * @return
 */
Type selectById(int typeId);
/**
 * 保存分类 
 * @param type
 * @return
 */
int saveType(Type type);
/**
 * 修改分类 
 * @param type
 * @return
 */
int updateType(Type type);
/**
 * 删除分类 
 * @param typeId
 * @return
 */
int deleteType(int typeId);
}

修改TypeMpper.xml文件

其中mapper元素的namespace属性值为接口的全称。

xml中sql定义的id与接口中的方法名相同,parameterType与接口方法的参数相同,resultType与接口方法的返回值类型一致

img

在测试类中添加方法TypeMapperTest

.........
TypeMapper mapper = session.getMapper(TypeMapper.class); //获取TypeMapper接口的实例
int count = mapper.deleteType(1);//删除ID为1的分类
........

指导练习

修改cbmv项目数据访问层,使用mybatis接口实现数据

添加事务控制

修改BaseDao

声明本地线程,用于存放当前线程的Mybaits查询会话,

//本地线程缓存,相当于一个map集合,key为线程的ID,value为指定的泛型对象
private static ThreadLocal<SqlSession> sessionCache = new ThreadLocal<>();

定义方法获取Mapper接口

protected <T> T getMapper(Class<T> cls){
SqlSession session = null;
if((session = sessionCache.get()) == null){
session = getSession();
sessionCache.set(session);
}
T mapper =  session.getMapper(cls);
return mapper;
}

定义事务控制的方法

//事务提交方法
public static void commit(){
SqlSession session = null;
if((session = sessionCache.get()) != null){
session.commit();
}
}
//事务回滚方法
public static void rollback(){
SqlSession session = null;
if((session = sessionCache.get()) != null){
session.rollback();
}
}

定义会话关闭方法

public static void close(){
SqlSession session = null;
if((session = sessionCache.get()) != null){
session.close();
sessionCache.remove();
}
}

修改TypeDaoImpl类的方法

在类中定义TypeMapper的实现类对象引用

private TypeMapper typeMapper= getMapper(TypeMapper.class);

修改查询方法

/**
 * 查询记录总数
 * @return
 */
 int count = 0;
try {
count = typeMapper.selectCountByType(t);
} finally{
close();
}
return count;

事务控制

只有增、删、改方法需要事务控制,查询不需要事务控制

以下是分别在Dao和Servcie中实现事务控制的方法

在Dao的实现类中实现事务控制

修改新增方法addType

int count = 0;
 try{
     count = typeMapper.insertType(t);
     commit(); //提交事务
 }catch(Exception e){
     rollback();//异常时回滚事务;
     throw new SQLException(e);
 }finally{
    close();
 }

在service中实现事务控制

修改TypeDao的addType方法

int count = typeMapper.insertType(t);


修改TypeServiceImpl类的insertType方法

int count = 0;
try{
    count = typeDao.typeMapper(t);
    BaseDao.commit();
}catch(SQLException e){
    BaseDao.rollback();
    trhow e;
}finally{
    BaseDao.close();
}

注意: 经过此改进后,可以发现Dao层已经没有太多的代码,基本都是一行代码实现功能,在许多的项目框架中都会去掉Dao层,直接在Service层中调用Mapper。也就是使用Mapper接口替代Dao层。

注解实现

MyBatis除了可以使用映射文件来实现语句的配置,还可以使用注解的实现

注解的实现是直接在接口的方法上定义语句的注解,如下所示

img

在MyBatis的配置文件中mapper再使用resource属性映射xml配置文件,而是使用class属性映射接口

img

常用注解

@select

@select注解对应xml映射文件中的select元素。用于定义select语句,语句中参数的获取与在xml文件中相同

示例

@Select("select count(*) from t_type")
int selectCount();

@Results和@Result

@Results

@Results注解对应xml映射文件中的resultMap元素,用于定义记录与对象的转换规则。

@Results的常用属性

id:相当于xml中resultMap元素的id属性,用于给映射集指定一个唯一的名称。

value:@Result注解的数组,用于定义每个字段与实体属性的映射

@Result

@Result注解对应xml映射文件中resultMap元素的子元素result,用于字段与属性之间的转换

@Result的常用属性

column:表的字段名

property:实体的属性名

id:是否是主键,如果是主键,则设置为true,默认为false

javaType:实体属性的数据类型

jdbcType:表中字段的数据类型,此类型为org.apache.ibatis.type.JdbcType枚举的值。

one:实现一对一的映射,类型为@One注解

many:实现一对多的映射,类型为@Many注解

typeHandler:自定义类型转换器

示例

@Select("select type_id,type_name,type_code,type_remark,create_time from"
+ " t_type limit #{list[0]},#{list[1]}")
@Results(id="typeMap",value={@Result(id=true,column="type_id",property="typeId")
,@Result(column="type_name",property="typeName")
,@Result(column="type_code",property="typeCode")
,@Result(column="type_remark",property="typeRemark")
,@Result(column="create_time",property="createTime",typeHandler=DateTypeHandler.class)})
List<Type> selectAll(List<Object> list);

@One

用于实现一对一及多对一的映射,相当于xml中的association元素

常用属性

fetchType:FetchType枚举类型,可选择EAGER和LAZY

select:关联的查询方法,可以是xml中select元素的id ,也可以是一个接口中的方法名,如果是本接口中的方法可以直接写方法名,如果是引用xml中的id或是其它接口中的方法,则需要写全称。

示例

@Select("")
@Results(id="proMap",value={@Result(column="type_id",
property="type",javaType=Type.class,
one=@One(select="com.cashop.dao.mapper.TypeAnnocationMapper.selectById"))})
List<Product> selectAll(Map<String,Object> map);

@Mony

用于一对多的映射,相同于xml中的collection元素

常用属性与@One相同

示例

@Result(column="type_id",property="proList",javaType=ArrayList.class
,many=@Many(select="com.cashop.dao.mapper.ProductAnnocationMapper.selectByTypeId"))

@ResultMap

用于引用已存在的Results注解或xml中resultMap元素的id,相当于xml中select元素的resultMap属性,如果引用的不是本接口中定义的@Results的id,则需要使用全称

@Select("select type_id,type_name,type_code,type_remark,create_time"
+ " from t_type where type_id=#{value}")
@ResultMap("typeMap")
Type selectById(int typeId);

@Insert

相当于xml中的insert元素,用于定义新增语句

@Insert("insert into t_type(type_name,type_code,type_remark,create_time)"
+ " values(#{typeName},#{typeCode},#{typeRemark},select now())")
int saveType(Type type);

@Update

相当于xml中的update元素,用于定义修改语句

@Update("update t_type set type_name = #{typeName},type_code = #{typeCode},"
+ "type_remark = #{typeRemark},where type_id = #{typeId} ")
int updateType(Type type);

@Delete

相当于xml中的delete元素,用于定义删除语句

@Delete("delete from t_type where type_id=#{value}")
int deleteType(int typeId);

注解扩展

  • 使用注解方式的语句无法使用条件判断,可以使用Provider注解调用Java类来实现语句的拼接。

@selectProvider注解

属性

type:用于生成语句的类的类型

method:在类中用于生成语句的方法

示例

@SelectProvider(type=TypeMapperProvider.class,method="selectCount")
int selectCount();

public class TypeMapperProvider {

    public String selectCount(){
        return "select count(*) from t_type";
    }
}

方法参数的规则

    • 如果Mapper接口的方法没有参数,则Provider方法也没有参数

    • 如果Mapper接口的方法是一个实体类型参数,则Provider方法的参数可以是此实体的类型

    • 其它的参数类型在Provider中当应当使用Map集合做为参数

      • 如果Mapper接口的方法是一个或一组基本类型参数,则应当使用@Param注解来指定参数名,Provider方法的参数为Map集合,key为@Param注解指定的名称
      • 如果Mapper接口的方法是Map参数,则Provider方法的参数为Map
      • 如果Mapper接口的方法是List参数,则Provider方法的参数为Map,key为list和collection
      • 如果Mapper接口的方法是数组参数,则Provider方法的参数为Map,key为array

Provider类中方法总是返回一个String类型,即生成的sql语句

语句的生成方法常用的有三种

直接使用字符串拼接

return "select count(*) from t_type";

使用SQL对象的方法组合

return new SQL().SELECT("count(*)").FROM("t_type").WHERE("1=1").toString();

使用SQL对象子类对象

return new SQL(){
        {
SELECT("count(*)");
FROM("t_type");
WHERE("1=1");
}

@InsertProvider、@UpdateProvider、@DeleteProvider和@SelectProvider的使用方法一致。

Mybatis与Spring整合

整合环境搭建

准备所需JAR包

要实现MyBatis与Spring的整合,很明显需要这两个框架的JAR包,但是只使用这两个框架中所提供的JAR包是不够的,还需要其他的JAR包来配合使用,整合时所需准备的JAR包具体如下。

1、Spring框架所需的JAR包

img

注意:核心容器依赖的commons-logging的JAR在MyBatis框架的lib包中已经包含!

2、MyBatis框架所需的JAR包

img

3、MyBatis与Spring整合的中间JAR

•mybatis-spring-1.3.1.jar

4、数据库驱动JAR(MySQL)

•mysql-connector-java-5.1.40-bin.jar

编写配置文件

1、创建项目(chapter10),引入JAR包

在Eclipse中,创建一个名称为chapter10的Web项目,将上一小节中所准备的全部JAR包添加到项目的lib目录中,并发布到类路径下。

2、编写db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root
jdbc.maxTotal=30
jdbc.maxIdle=10
jdbc.initialSize=5

3、编写Spring配置文件applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
... 
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
     <property name="driverClassName" value="${jdbc.driver}"/>
     <property name="url" value="${jdbc.url}" />
     <property name="username" value="${jdbc.username}" />
     <property name="password" value="${jdbc.password}" />
     <property name="maxTotal" value="${jdbc.maxTotal}" />
     <property name="maxIdle" value="${jdbc.maxIdle}" />
     <property name="initialSize" value="${jdbc.initialSize}" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     <property name="dataSource" ref="dataSource" /> 
</bean>  
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
     <property name="dataSource" ref="dataSource" />
     <property name="configLocation" value="classpath:mybatis-config.xml"/> 
</bean>
</beans>

4、编写MyBatis配置文件mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?><configuration> 
  <typeAliases>
      <package name="com.creatorblue.po" />
  </typeAliases> 
   <mappers> 
    ...
   </mappers>
</configuration>

5、引入log4j.properties

# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.com.creatorblue=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

MapperFactoryBean是MyBatis-Spring团队提供的一个用于根据Mapper接口生成Mapper对象的类,该类在Spring配置文件中使用时可以配置以下参数:

mapperInterface:用于指定接口;

SqlSessionFactory:用于指定SqlSessionFactory;

SqlSessionTemplate:用于指定SqlSessionTemplate。如果与SqlSessionFactory同时设定,则只会启用SqlSessionTemplate。

虽然使用Mapper接口编程的方式很简单,但是在具体使用时还是需要遵循一些规范。

img

在实际的项目中,DAO层会包含很多接口,如果每一个接口都在Spring配置文件中配置,不但会增加工作量,还会使得Spring配置文件非常臃肿。为此,可以采用自动扫描的形式来配置MyBatis中的映射器——采用MapperScannerConfigurer类。

MapperScannerConfigurer类在Spring配置文件中可以配置以下属性:

basePackage:指定映射接口文件所在的包路径,当需要扫描多个包时可以使用分号或逗号作为分隔符。指定包路径后,会扫描该包及其子包中的所有文件。

annotationClass:指定了要扫描的注解名称,只有被注解标识的类才会被配置为映射器。

sqlSessionFactoryBeanName:指定在Spring中定义的SqlSessionFactory的Bean名称。

sqlSessionTemplateBeanName:指定在Spring中定义的SqlSessionTemplate的Bean名称。如果定义此属性,则sqlSessionFactoryBeanName将不起作用。

markerInterface:指定创建映射器的接口。

MapperScannerConfigurer的使用非常简单,只需要在Spring的配置文件中编写如下代码:

<!-- Mapper代理开发(基于MapperScannerConfigurer) -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
     <property name="basePackage" value="com.creatorblue.mapper" />
</bean>

通常情况下,MapperScannerConfigurer在使用时只需通过basePackage属性指定需要扫描的包即可,Spring会自动的通过包中的接口来生成映射器。这使得开发人员可以在编写很少代码的情况下,完成对映射器的配置,从而提高开发效率。