第 7 章 MyBatis 的核心配置

通过上一章的学习,大家对 MyBatis 框架的使用已经有了一个初步的了解,但是要想熟练地使用 MyBatis 框架进行实际开发,只会简单的配置是不行的,我们还需要对框架中的核心对象, 以及映射文件和配置文件有更加深入的了解。 接下来,本章将对这些内容进行详细的讲解。

MyBatis 的核心对象

在使用 MyBatis 框架时,主要涉及两个核心对象: SqlSessionFactory 和 SqlSession ,它们 在 MyBatis 框架中起着至关重要的作用。 本节将对这两个对象进行详细讲解。

  • SqlSessionFactory

SqlSessionFactory 是 MyBatis 框架中十分重要的对象,它是单个数据库映射关系经过编译后的内存镜像,其主要作用是创建 SqlSession。SqlSessionFactory 对象的实例可以通过 SqlSessionFactoryBuilder 对象来构建,而 SqlSessionFactoryBuilder 则可以通过 XML 配置文件或一个预先定义好的 Configuration 实例构建出 SqlSessionFactory 的实例。 我们所讲解的就是通过 XML 配置文件构建出的 SqlSessionFactory 实例,其实现代码如下:

  // 读取配置文件
  InputStream inputStream = Resources.getResourceAsStream("配置文件位置");
  // 根据配置文件构建 Sq1SessionFactory
  SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

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

  • SqlSession

SqlSession 是 MyBatis 框架中另一个重要的对象,它是应用程序与持久层之间执行交互操作的一个单线程对象,其主要作用是执行持久化操作。 SqlSession 对象包含了数据库中所有执 行 SQL 操作的方法,由于其底层封装了 JDBC 连接,所以可以直接使用其实例来执行己映射的 SQL 语句。
每一个线程都应该有一个自己的 SqlSession 实例,并且该实例是不能被共享的。 同时, SqlSession 实例也是线程不安全的,因此其使用范围最好在一次请求或一个方法中,绝不能将其放在一个类的静态字段、实例字段或任何类型的管理范围(如 Servlet 的 HttpSession )中使用。 使用完 SqlSession 对象之后,要及时地关闭它,通常可以将其放在 finally 块中关闭,代码如下所示。

      SqlSession sqlSession = sqlSessionFactory.openSession();
      try{
          //此处执行持久化操作
      }finally{
          sqlSession.close();
      }

SqlSession 对象中包含了很多方法,其常用方法如下所示。

  • <T> T selectOne ( String statement ); 查询方法。 参数 statement 是在配置文件中定义的<select>元素的 id。 使用该方法后,会返 回执行 SOL 语句查询结果的一条泛型对象。

  • <T> T selectOne ( String statement, Object parameter ); 查询方法。 参数 statement 是在配置文件中定义的<selecb元素的 id , parameter 是查询所 需的参数。 使用该方法后,会返回执行 SOL 语句查询结果的一条泛型对象。

  • <E> List<E> selectList ( String statement ); 查询方法。 参数 statement 是在配置文件中定义的<select>元素的 id。 使用该方法后,会返 回执行 SOL 语句查询结果的泛型对象的集合。

  • <E> List<E> selectList ( String statement, Object parameter ); 查询方法。 参数 statement 是在配置文件中定义的<selecb元素的 id , parameter 是查询所 需的参数。 使用该方法后,会返回执行 SOL 语句查询结果的泛型对象的集合。

  • <E> List<E> selectList ( String statement, Object parameter, RowBounds rowBounds ); 查询方法。 参数 statement 是在配置文件中定义的<select>元素的 id , parameter 是查询所 需的参数, rowBounds 是用于分页的参数对象。 使用该方法后,会返回执行 SOL 语句查询结果 的泛型对象的集合。

  • void select ( String statement, Object parameter, ResultHandler handler ); 查询方法。 参数 statement 是在配置文件中定义的<selecb元素的 id , >- parameter 是查询所 需的参数, ResultHandler 对象用于处理查询返回的复杂结果集,通常用于多表查询。

  • int insert ( String statement ); 插入方法。 参数 statement 是在配置文件中定义的<inserb元素的 id。 使用该方法后,会返 回执行 SOL 语句所影响的行数。

  • int insert ( String statement, Object parameter ); 插入方法。 参数 statement 是在配置文件中定义的<inserb元素的 id , parameter 是插入所 需的参数。 使用该方法后,会返回执行 SOL 语句所影响的行数。

  • int update ( String statement ); 更新方法。 参数 statement 是在配置文件中定义的<update>元素的 id。 使用该方法后,会 返回执行 SOL 语句所影响的行数。

  • int update ( String statement, Object parameter ); 更新方法。 参数 statement 是在配置文件中定义的<update>元素的 id , parameter 是更新 所需的参数。 使用该方法后,会返回执行 SOL 语句所影响的行数。
    int delete ( String statement ); 删除方法。 参数 statement 是在配置文件中定义的<delete>元素的 id。 使用该方法后,会返 回执行 SOL 语句所影响的行数。

  • int delete ( String statement, Object parameter ); 删除方法。 参数 statement 是在配置文件中定义的<delete>元素的 id , parameter 是删除所 需的参数。 使用该方法后,会返回执行 SOL 语句所影响的行数。

  • void commit(); 提交事务的方法。

  • void rollback(); 回滚事务的方法。

  • void close(); 关闭 SqlSession 对象。

  • <T> T getMappe r(Class<T> type) ;该方法会返回 Mapper 接口的代理对象,该对象关联了 SqlSession 对象,开发人员可以使 用该对象直接调用方法操作数据库。 参数 type 是 Mapper 的接口类型。 MyBatis 官方推荐通过 Mapper 对象访问 MyBatis。

  • Connection getConnection(); 获取 JDBC 数据库连接对象的方法。

  • 多学一招: 使用工具类创建SqlSession
    在上一节的入门案例中,每个方法执行时都需要读取配直文件,并根据配直文件的信息构建 SqlSessionFactory 对象,然后创建 SqlSession 对象,这导致了大量的重复代码。为了简化开发, 我们可以将上述重复代码封装到一个工具类中,然后通过工具类来创建 SqlSession, 文件如下所示。

package com.neuedu.utils;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
/**
* 工具类
*/
public class MybatisUtils {
  private static SqlSessionFactory sqlSessionFactory = null;
  //初始化SqlSessionFactory对象
  static{
      try{
          //使用MyBatis提供的Resouces类加载MyBatis的配置文件
          Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
          //构建SqlSessionFactory工厂
          sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
      }catch (Exception e) {
          e.printStackTrace();
      }
  }
  //获取 SqlSession对象的静态方法
  public static SqlSession getSession(){
      return sqlSessionFactory.openSession();
  }
}

这样,我们在使用时就只创建了一个 SqlSessionFactory 对象,并且可以通过工具类的 getSession() 方法,来获取 SqlSession 对象。

配置文件

MyBatis 的核心配置文件中,包含了很多影响 MyBatis 行为的重要信息。 这些信息通常在一 个项目中只会在一个配置文件中编写,并且编写后也不会轻易改动。 虽然在实际项目中需要开发 人员编写或者修改的配置文件不多,但是熟悉配置文件中各个元素的功能还是十分重要的。 接下来的几个小节中,将对 MyBatis 配置文件中的元素进行详细的讲解。

  • 主要元素

在 MyBatis 框架的核心配置文件中, <configuration>元素是配置文件的根元素,其他元素 都要在 <configuration>元素内配置。 在上一章的入门案例中,我们在配置文件内只使用了 <environments>和<mapper>等几个元素,但在实际开发时,通常还会对其他一些元素进行配置。
MyBatis 配置文件中的主要元素如图所示。


从图中可以看到,在 MyBatis 的配置文件中包含了多个元素,这些元素在配置文件中分别发挥着不同的作用。 开发人员所需要熟悉的就是图中<configuration>元素各个子元素的配置。
注意:<configuration>的子元素必须按照上图中由上到下的顺序进行配置,否则 MyBatis 在解析 XML 配置文件的时候会报错。

  • <properties>元素

<properties>是一个配置属性的元素,该元素通常用于将内部的配置外在化,即通过外部的配置来动态地替换内部定义的属性。 例如,数据库的连接等属性,就可以通过典型的 Java 属性 文件中的配置来替换,具体方式如下。
( 1 )在项目的 src 目录下,添加一个全名为 db.properties 的配置文件,编辑后的代码如下所示。

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

( 2 )在 MyBatis 配置文件 mybatis-config.xml 中配置<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>

完成上述配置后, dataSource 中连接数据库的 4 个属性( driver、url、username 和 password) 值将会由 db.properties 文件中对应的值来动态替换。 这样就为配置提供了诸多灵活的选择。
除了可以像上述通过外部配置文件来定义属性值外,还可以通过配置<properties>元素的子元素<property> ,以及通过方法参数传递的方式来获取属性值。 由于使用 properties 配置文件来配置属性值可以方便地在多个配置文件中使用这些属性值,并且方便曰后的维护和修改,所以在实际开发中,使用 properties 配置文件来配置属性值是最常用的方式。 在这里我所使用的就是此种方式,关于其他两种方式,有兴趣大家可自行查找资料学习。

  • <settings>元素

<settings>元素主要用于改变 MyBatis 运行时的行为,例如开启二级缓存、开启延迟加载等。 虽然不配置<settings>元素,也可以正常运行 MyBatis,但是熟悉<settings>的配置内容以及它们的作用还是十分必要的。
<settings>元素中的常见配置及其描述如表所示。

设置参数 描述 有效值 默认值
cacheEnabled 该配置影响所苟映射器中配置的缓存全局开关 true 或false false
lazyLoadingEnabled 延迟加载的全局开关。开启时,所有关联对象都会延迟 加载。特定关联关系中可以通过设置 fetchType 属性覆盖该项的开关状态 true 或false true
aggressiveLazyLoading 关联对象属性的延迟加载开关。当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性都会投需加载 true 或false true
multipleResultSetsEnabled 是否允许单一语句返回多结果集(需要兼容驱动) true 或false true
useColumnLabel 使用列标签代替列名 。不同的驱动在这方面离不同的表现。 具体可参考驱动文档或通过测试两种模式来观察所用驱动的行为 true 或false true
useGeneratedKeys 允许 JDBC 支持自动生成主键,需要驱动兼容。如果设置为 true,则这个设置强制使用自动生成主键,尽管一些驱动不兼容但仍可正常工作 true 或false false
autoMappingBehavior 指定 MyBatis 应如何自动映射列到字段或属性。 NONE表示取消自动映射; PARTIAL 只会自动映射没离定义嵌套结果集映射的结果集; FULL 会自动映射任意复杂 的结果集(无论是否嵌套) NONE、PARTIAL、FULL PARTIAL
defaultExecutorType 配置默认的执行器。 SIMPLE 就是普通的执行器;执行器会重用预处理语句 (prepared statements) ; BATCH 执行器将重用语句并执行批量更新 SIMPLE、REUSE、 BATCH SIMPLE
defaultStatementTimeout 设置超时时间, 它决定驱动等待数据库响应的秒数。 当没有设置的时候,它取的就是驱动的默认时间 任何正整数 没有设置
mapUnderscoreToCamelCase 是否开启自动~8峰命名规则( camel case )映射 true 或false false
jdbcTypeForNull 当没有为参数提供特定的 JDBC 类型时,为空值指定JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、 VARCHAR 或 OTHER NULL、VARCHAR、 OTHER OTHER

表中介绍了 <settings>元素中的常见配置,这些配置在配置文件中的使用方式如下。

  <!-- 设置 -->
  <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="true" />
      <setting name= "autoMappingBehavior" value="true" />
      ...
  </settings>

上面所介绍的配置内容大多数都不需要开发人员去配置它,通常在需要时只配置少数几项即可。 这里大家只需要了解这些可设置的参数值及其含义即可。

  • <typeAliases>元素

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

  <!-- 定义别名  -->
  <typeAliases>
      <typeAlias alias="user" type="com.neuedu.po.User"/>
  </typeAliases>

上述示例中, <typeAliases>元素的子元素<typeAlias>中的 type 属性用于指定需要被定义别名的类的全限定名;alias 属性的属性值 user 就是自定义的别名,它可以代替 com.neuedu. po.User 使用在 MyBatis 文件的任何位置。 如果省略 alias 属性, MyBatis 会默认将类名首字母小写后的名称作为别名。
当 POJO 类过多时,还可以通过自动扫描包的形式自定义别名,具体示例如下。

  <!-- 使用自动扫描包来定义别名  -->
  <typeAliases>
      <package name="com.neuedu.po"/> 
  </typeAliases>

上述示例中, <typeAliases>元素的子元素<package>中的 name 属性用于指定要被定义别名的包, MyBatis 会将所有 com.neuedu.po 包中的 POJO 类以首字母小写的非限定类名来作为它的别名,比如 com.neuedu.po.User 的别名为 user , com.neuedu.po.Customer 的别名为 customer 等。
需要注意的是,上述方式的别名只适用于没有使用注解的情况。 如果在程序中使用了注解, 则别名为其注解的值,具体如下。

@Alias(value= "user")
public class User {
  //User 的属性和方法
  ...
}

除了可以使用<typeAliases>元素自定义别名外, MyBatis 框架还默认为许多常见的 Java 类型(如数值、字符串、曰期和集合等)提供了相应的类型别名,如表所示。

别名 映射的类型
_byte byte
_Iong long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
object Object
map Map
hashmap HashMap
list List
arraylist Arraylist
collection Collection
iterator Iterator

表中所列举的别名可以在 MyBatis 中直接使用,但由于别名不区分大小写,所以在使用时要注意重复定义的覆盖问题。

  • <typeHandler>元素

MyBatis 在预处理语句( PreparedStatement )中设置一个参数或者从结果集( ResultSet ) 中取出一个值时,都会用其框架内部注册了的 typeHandler (类型处理器)进行相关处理。 typeHandler 的作用就是将预处理语句中传入的参数从 javaType ( Java 类型)转换为 jdbcType ( JDBC 类型),或者从数据库取出结果时将 jdbcType 转换为 javaType。
为了方便转换, MyBatis 框架提供了一些默认的类型处理器,其常用的类型处理器如表所示。

类型处理器 Java类型 JDBC类型
BooleanTypeHandler java.lang.Boolean, boolean 数据库兼容的 BOOLEAN
ByteTypeHandler java.lang.Byte, byte 数据库兼容的 NUMERIC 或 BYTE
ShortTypeHandler java.lang.Short, short 数j居库兼容的 NUMERIC 或 SHORT INTEGER
IntegerTypeHandler java.lang.lnteger, int 数据库兼容的 NUMERIC 或 INTEGER
LongTypeHandler java.lang.Long, long 数据库兼容的 NUMERIC 或 LONG INTEGE
FloatTypeHandler java.lang.Float, float 数据库兼容的 NUMERIC 或 FLOAT
Double TypeHandler java.lang.Double, double 数据库兼容的 NUMERIC 或 DOUBLE
BigDecimalTypeHandler java.math.BigDecimal 数据库兼容的 NUMERIC 或 DECIMAL
StringTypeHandler java.lang.String CHAR, VARCHAR
Clob TypeHandler java.lang.String CLOB , LONGVARCHAR
ByteArrayTypeHandler byte[] 数据库兼容的字节流类型
BlobTypeHandler byte[] BLOB , LONGVARBINARY
DateTypeHandler java.util.Date TIMESTAMP
SqlTimestampTypeHandler java.sql.Timestamp TIMESTAMP
SqlDateTypeHandler java.sql.Date DATE
SqlTimeTypeHandler java.sql.Time TIME

当 MyBatis 框架所提供的这些类型处理器不能够满足需求时,还可以通过自定义的方式对类型处理器进行扩展(自定义类型处理器可以通过实现 TypeHandler 接口或者继承 BaseTypeHandle 类来定义 )。 <typeHandler>元素就是用于在配置文件中注册自定义的类型处 理器的。 它的使用方式有两种,具体如下。

  1. 注册一个类的类型处理器
  <typeHandlers>
      <!-- 以单个类的形式配置 -->
      <typeHandler handler="com.neuedu.type.CustomtypeHandler"/>
  </typeHandlers>

上述代码中,子元素<typeHandler>的 handler 属性用于指定在程序中自定义的类型处理器类。

  1. 注册一个包中所有的类型处理器
  <typeHandlers>
      <!-- 注册一个包中所有的 typeHandler,系统在启动时会自动扫描包下的所有文件 -->
      <typeHandler handler="com.neuedu.type" />
  </typeHandlers>

上述代码中,子元素<package>的 name 属性用于指定类型处理器所在的包名,使用此种方式后,系统会在启动时自动地扫描 com.neuedu.type 包下所有的文件,并把它们作为类型处理器。

  • <objectFactory>元素

MyBatis 框架每次创建结果对象的新实例时,都会使用一个对象工厂( ObjectFactory )的实例来完成。 MyBatis 中默认的 ObjectFactory 的作用就是实例化目标类,它既可以通过默认构造方法实例化,也可以在参数映射存在的时候通过参数构造方法来实例化。
在通常情况下,我们使用默认的 ObjectFactory 即可, MyBatis 中默认的 ObjectFactory 是由 org.apache.ibatis.reflection.factory.DefaultObjectFactory 来提供服务的。 大部分场景下都不用配置和修改,但如果想覆盖 ObjectFactory 的默认行为,则可以通过自定义 ObjectFactory 来实现,具体方式如下。
( 1 ) 自定义一个对象工厂。 自定义的对象工厂需要实现 ObjectFactory 接口,或者继承 DefauItObjectFactory 类。 由于 DefaultObjectFactory 类已经实现了 ObjectFactory 接口,所以通过继承 DefaultObjectFactory 类实现即可,示例代码如下所示。

//自定义工厂类
public class MyObjectFactory extends DefaultObjectFactory {
  private static final long serialVersionUID = -5548708841003212961L;
  public <T> T Create(Class<T> type){
      return super.create(type);
  }
  public <T> T Create(Class<T> type,List<Class<?>> constructorArgTypes, List<Object> constructorArgs){
      return super.create(type, constructorArgTypes, constructorArgs); 
  }
  public void setProperties(Properties properties) {
      super.setProperties(properties) ; 
  }
  public <T> boolean isCollection(Class<T> type) { 
      return Collection.class.isAssignableFrom(type); 
  }
}

( 2 ) 在配置文件中使用<objectFactory>元素配置自定义的 ObjectFactory ,如下所示。

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

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

  • <plugins>元素

MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用,这种拦截调用是通过插件来实现的。 <plugins>元素的作用就是配置用户所开发的插件。 如果用户想要进行插件开发,必须要先了解其内部运行原理,因为在试图修改或重写已有方法的行为时,很可能会破坏 MyBatis 原有的核心模块。 关于插件的使用,在这里不做详细讲解, 大家只需了解<plugins>元素的作用即可, 有兴趣的可以查找官方文档等资料自行学习。

  • <environments>元素

在配置文件中, <environments>元素用于对环境进行配置。 MyBatis 的环境配置实际上就是数据源的配置,我们可以通过<environments>元素配置多种数据源,即配置多种数据库。
使用<environments>元素进行环境配置的示例如下。

  <environments default="development">
      <environment id="development">
          <!-- 使用JDBC的事务管理 -->
          <transactionManager type="JDBC" />
          <!-- 数据库连接池 -->
          <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>
      </environment>
      ...
  </environments>

在上述示例代码中, <environments>元素是环境配置的根元素,它包含一个 default 属性, 该属性用于指定默认的环境 ID。 <environment>是<environments>元素的子元素,它可以定义多个,其 id 属性用于表示所定义环境的 ID 值。 在<environment>元素内,包含事务管理和数据源的配置信息,其中<transactionManager>元素用于配置事务管理,它的 type 属性用于指定事 务管理的方式,即使用哪种事务管理器;<dataSource>元素用于配置数据源,它的 type 属性用于指定使用哪种数据源。
在 MyBatis 中 , 可以配置两种类型的事务管理器,分别是 JDBC 和 MANAGED。 关于这两 个事务管理器的描述如下。

  • JDBC : 此配置直接使用 了 JDBC 的提交和回滚设置 , 它依赖于从数据源得到的连接来管理事务的作用域。
  • MANAGED: 此配置从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。 在默认情况下 , 它会关闭连接, 但一些容器并不希望这样, 为此可以将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。
    注意:如果项目 中使用的是 Spring+ MyBatis,则没有必要在 MyBatis 中配置事务管理器,因为实际开发中,会使用 Spring 自带的管理器来实现事务管理。
    对于数据源的配置, MyBatis 框架提供了 UNPOOLED、 POOLED 和 JNDI 三种数据源类型, 具体如下。
  1. UNPOOLED
    配置此数据源类型后,在每次被请求时会打开和关闭连接。 它对没有性能要求的简单应用程序是一个很好的选择。
    UNPOOLED 类型的数据源需要配置 5 种属性,如表所示。
属性 说明
driver JDBC 驱动的 Java 类的完全限定名 ( 并不是 JDBC 驱动中可能包含的数据源类)
url 数据库的 URL 地址
username 登录数据库的用户名
password 登录数据库的密码
defaultTransactionlsolationLevel 默认的连接事务隔离级别
  1. POOLED
    此数据源利用"池"的概念将 JDBC 连接对象组织起来,避免了在创建新的连接实例时所需要初始化和认证的时间。 这种方式使得并发 Web 应用可以快速地响应请求,是当前流行的处理方式(在这里我们使用的就是此种方式)。
    配置此数据源类型时,除了上表中的 5 种属性外,还可以配置更多的属性,如下表所示。
属性 说明
poolMaximumActiveConnections 在任意时间可以存在的活动(也就是正在使用)连接数量,默认值 10
poolMaximumldleConnections 任意时间可能存在的空闲连接数
poolMaximumCheckoutTime 在被强制返回之剧,池中连接被检出( checked out )时间,默认值 :20000 毫秒, 即 20 秒
poolTimeToWait 如果获取连接花费的时间较长,它会给连接池打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直处于无提示的失败) ,默认值, 20000 毫秒, 即 20 秒
poolPingQuery 发送到数据库的侦测查询,用于检验连接是否处在正常工作秩序中。默认是 "NO PING QUERY SET" ,这会导致多数数据库驱动失败时带有一定的错误信息
poolPingEnabled 是否启用侦测查询。若开启,必须使用一个可执行的 SQL 语句设置 poolPingQuery 属性(最好是一个非常快的 SQL) ,默认值 false
poolPingConnectionsNotUsedFor 配置 poolPingQuery 的使用频度。可以被设置成匹配具体的数据库连接超时时间,来避免不必要的侦测,默认值: 0( 表示所有连接每一时刻都被侦测, 只有 poolPingEnabled 的属性值为 true 时适用)
  1. JNDI
    此数据源可以在 EJB 或应用服务器等容器中使用。 容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。
    配置 JNDI 数据源时,只需要配置两个属性,如下所示。
  • initial_context
    此属性主要用于在 InitialContext 中寻找上下文(即 initiaIContext.lookup(initial_context) ) 。 该属性为可选属性,在忽略时, data source 属性会直接从 InitialContext 中寻找
  • data_source
    此属性表示引用数据源实例位置的上下文的路径。如果提供了 initial_context 配置,那么程序会在真返回的上下文中进行查找;如果没有提供,则直接在 InitialContext 中查找
  • <mappers>元素

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

  1. 使用提路径引入
  <mappers>
      <mapper resource="com/neuedu/mapper/UserMapper.xml"></mapper>
  </mappers>
  1. 使用本地文件路径引入
  <mappers>
      <mapper  url="file:///D:/com/neuedu/mapper/UserMapper.xml"></mapper>
  </mappers>
  1. 使用接口类引入
  <mappers>
      <mapper  class="com.neuedu.mapper.UserMapper"/> 
  </mappers>
  1. 使用包名引入
  <mappers>
      <package name="com.neuedu.mapper"/>  
  </mappers>

上述 4 种引入方式非常简单 , 大家可以根据实际项目需要选取使用。

映射文件

映射文件是 MyBatis 框架中十分重要的文件, 可以说, MyBatis 框架的强大之处就体现在映射文件的编写上。 接下来的几个小节中,将对 MyBatis 映射文件中的元素进行详细讲解。

  • 主要元素

在映射文件中, <mapper>元素是映射文件的根元素 , 其他元素都是它的子元素。 这些子元素及其作用如图所示。


  • <select>元素

<select>元素用于映射查询语句,它可以帮助我们从数据库中读取出数据,并组装数据给业务开发人员。
使用<select>元素执行查询操作非常简单,其示例如下。

  <select id="findCustomerByld" parameterType="Integer" resultType="com.neuedu.po.Customer">    
      select * from t_customer where id = #{id}  
  </select>

上述语句中的唯一标识为 findCustomerByld ,它接收一个 Integer 类型的参数,并返回一个 Customer 类型的对象。
<select>元素中,除了上述示例代码中的几个属性外,还有其他一些可以配置的属性,如下表所示。

属性 说明
id 表示命名空间中的唯一标识符,常与命名空间组合起来使用。组合后如果不唯一, MyBatis 会抛出异常
parameterType 该属性表示传入 SQL 语句的参数类的全限定名或者别名。它是一个可选属性,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数。其默认值是 unset (依赖于驱动)
resultType 从 SQL 语句中返回的类型的类的全限定名或者别名。如果是集合类型,那么返回的应该是集 合可以包含的类型,而不是集合本身。返回时可以使用 resultType 或 resultMap 之一
resultMap 表示外部 resultMap 的命名引用。返回时可以使用 resultType 或 resultMap 之一
flushCache 表示在调用 SQL 语句之后,是否需要 MyBatis 清空之前查询的本地缓存和二级缓存。其值为布尔类型( true或false) ,默认值为 false。如果设置为 true,则任何时候只要 SQL 语句被调用,都会清空本地缓存和二级缓存
useCache 用于控制二级缓存的开启相关闭。其值为布尔类型( true或false) ,默认值为 true ,表示将查 询结果存入二级缓存中
timeout 用于设置超时参数,单位为秒。超时时将抛出异常
fetchSize 获取记录的总条数设定,真默认值是 unset (依赖于驱动)
statementType 用于设置 MyBatis 使用哪个 JDBC 的 Statement 工作,真值为 STATEMENT、 PREPARED (默认值)或 CALLABLE ,分别对应 JDBC 中的 Statement 、 PreparedStatement 和 CallableStatement
resultSetType 表示结果集的类型,其值可设置为 FORWARD_ONLY 、 SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE ,它的默认值是 unset (依赖于驱动)
  • <insert>元素

<insert>元素用于映射插入语句,在执行完元素中定义的 SQL 语句后,会返回一个表示插入记录数的整数。
<insert>元素的配置示例如下。

  <insert 
          id="addCustomer" 
          parameterType="com.neuedu.po.Customer"
          flushCache="true" 
          statementType="PREPARED"
          keyProperty=""
          keyColumn=""
          useGeneratedKeys=""
          timeout="20">

从上述示例代码中可以看出 , <ínsert>元素的属性与<select>元素的属性大部分相同 , 但还包含了 3 个特有属性,这 3 个属性的描述如表所示。

属性 说明
keyProperty (仅对 insert和 update 有用)此属性的作用是将插入或更新操作时的返回值赋值给 PO 类的某个属性,通常会设置为主键对应的属性。 如果需要设置联合主键,可以在多个值之间用逗号隔开
keyColumn (仅对 insert和 update 有用)此属性用于设置第几列是主键,当主键列不是表中的第一列时需要设置。在需要主键联合时,值可以用逗号隔开
useGeneratedKeys (仅对 insert和 update 有用)此属性会使 MyBatis 使用 JDBC 的 getGeneratedKeys() 方法来获取由数据库内部生产的主键,如 MySQL 和 SQL Server等自动递增的字段,其默认值为 false

执行插入操作后,很多时候我们会需要返回插入成功的数据生成的主键值,此时就可以通过上面所讲解的 3 个属性来实现。
如果使用的数据库支持主键自动增长(如 MySQL ),那么可以通过 keyProperty 属性指定 PO 类的某个属性接收主键返回值 ( 通常会设置到 id 属性上 ),然后将 useGeneratedKeys 的属性值设置为 true , 其使用示例如下。

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

使用上述配置执行插入后,会返回插入成功的行数,以及插入行的主键值。 为了验证此配置, 可以通过如下代码测试。

  @Test
  public void addCustomerTest(){
      SqlSession sqlSession = MybatisUtils.getSession();
      System.out.println(sqlSession);
      Customer customer = new Customer();
      customer.setUsername("rose1");
      customer.setJobs("student1");
      customer.setPhone("13300007777");
      int rows = sqlSession.insert("com.neuedu.mapper.CustomerMapper.addCustomer",customer);
      //输出插入数据的主键 id值
      System.out.println(customer.getId());
      if(rows > 0){
          System.out.println("您成功插入了"+rows+"条数据!");
      }else{
          System.out.println("执行插入数据失败!!!");
      }
      sqlSession.commit(); 
      sqlSession.close();
  }

执行程序后,控制台的输出结果如图所示。



如果使用的数据库不支持主键自动增长(如 Oracle ),或者支持增长的数据库取消了主键自增的规则时,也可以使用 MyBatis 提供的另一种方式来自定义生成主键,具体配置示例如下。

 <insert id="insertCustomer" parameterType="com.neuedu.po.Customer">
  <selectKey keyProperty="id" resultType="Integer">
      select if(max(id) is null,1,max(id)+1) as newId from t_customer
  </selectKey>
  insert into t_customer(id,username,jobs,phone)
   values(#{id},#{username},#{jobs},#{phone}) 
 </insert>

在执行上述示例代码时, <selectKey>元素会首先运行,它会通过自定义的语句来设置数据 表中的主键(如果 t_customer 表中没有记录,则将 id 设置为 1 ,否则就将 id 的最大值加 1 ,来作为新的主键),然后再调用插入语句。
<selectKey>元素在使用时可以设置以下几种属性。

  <selectKey keyProperty="id" 
             resultType="Integer"
             order="BEFORE"
             statementType="STATEMENT">

在上述<selectKey>元素的几个属性中, keyProperty、 resultType 和 statementType 的作用与前面讲解的相同,这里不重复介绍。 order 属性可以被设置为 BEFORE 或 AFTER。 如果设置 为 BEFORE ,那么它会首先执行<selectKey>元素中的配置来设置主键,然后执行插入语句;如果设置为 AFTER ,那么它会先执行插入语句,然后执行<selectKey>元素中的配置内容。

  • <update>元慧和<delete>元素

<update>和<delete>元素的使用比较简单,它们的属性配置也基本相同( <delete>元素中不包含上面提到的 3 个属性),其常用属性如下所示。

  <update 
          id="updateCustomer"
          parameterType="com.neuedu.po.Customer"
          flushCache="true"
          statementType="PREPARED"
          timeout="20">
  <delete 
          id="deleteCustomer" 
          parameterType="Integer"
          flushCache="true"
          statementType="PREPARED"
          timeout="20">

从上述配置代码中可以看出, <update>和<delete>元素的属性基本与<select>元素中的属性一致。 与<insert>元素一样, <update>和<delete>元素在执行完之后,也会返回一个表示影响记录条数的整数,其使用示例如下。

  <!-- 更新信息  -->
  <update id="updateCustomer">
      update t_customer set
      username=#{username},jobs=#{jobs},phone=#{phone}
      where id=#{id}
  </update>
  <!-- 删除信息  -->
  <delete id="deleteCustomer" parameterType="Integer">
      delete from t_customer where id=#{id}
  </delete>
  • <sql>元素

在一个映射文件中,通常需要定义多条 SQL 语句,这些 SQL 语句的组成可能有一部分是相 同的(如多条 select 语句中都查询相同的 id、 username、 jobs 字段),如果每一个 SQL 语句都重写一遍相同的部分,势必会增加代码量,导致映射文件过于腕肿。 那么有没有什么办法将这些 SQL 语句中相同的组成部分抽取出来,然后在需要的地方引用呢?答案是肯定的,我们可以在映射文件中使用 MyBatis 所提供的<sql>元素来解决上述问题。
<sql>元素的作用就是定义可重用的 SQL 代码片段,然后在其他语句中引用这一代码片段。 例如,定义一个包含 id、 username、 jobs 和 phone 字段的代码片段如下。

  <sql id="customerColumns">id,username,jobs,phone</sql>

这一代码片段可以包含在其他语句中使用,具体如下。

  <select id="findCustomerByld" parameterType="Integer" resultType="com.neuedu.po.Customer">    
      select <include refid="customerColumns" />
      from t_customer 
      where id = #{id}  
  </select>

在上述代码中,使用<include>元素的 refid 属性引用了自定义的代码片段, refid 的属性值为自定义代码片段的 id。
上面示例只是一个简单的引用查询。 在实际开发中,可以更加灵活地定义 SOL 片段,其示例如下。

<!-- 定义表的前缀名 -->
<sql id="tablename"> 
  ${prefix}customer 
</sql> 
<sql id="someinclude"> 
from 
<include refid="${include_target}" /> 
</sql> 
<!--定义查询列--> 
<sql id="customarColumns"> 
id,username,jobs,phone 
</sql>
  <!-- 根据id获取客户信息  -->
  <select id="findCustomerByld" parameterType="Integer" resultType="com.neuedu.po.Customer">    
      select 
      <include refid="customarColumns" />
      <include refid="someinclude">
          <property name="prefix" value="t_"/>
          <property name="include_target" value="tablename"/>
      </include>
      where id = #{id}
  </select>

上述代码中,定义了 3 个代码片段,分别为表的前缀名、要查询的表和需要查询的列。前两个代码片段中,分别获取了 <include>子元素<property> 中的值,其中第 1 个代码片段中的 "${prefix) "会获取 name 为 prefix 的值 "t_" ,获取后所组成的表名为 "t_customer" ; 而第 2 个代码片段中的 "${include_target)"会获取 name 为 include_target 的值 "tablename" ,由于 tablename 为第 1 个 SOL 片段的 id 值,所以最后要查询的表为 "t_customer"。所有的 SOL 片段在程序运行时,都会由 MyBatis 组合成 SOL 语句来执行需要的操作。
执行程序后,控制台的输出结果如图所示。


  • <resultMap>元素

<resultMap>元素表示结果映射集,是 MyBatis 中最重要也是最强大的元素。它的主要作回是定义映射规则、级联的更新以及定义类型转化器等。
<resultMap>元素中包含了一些子元素,它的元素结构如下所示。



<resultMap>元素的 type 属性表示需要映射的 POJO , id 属性是这个 resultMap 的唯一标识。 它的子元素<constructor>用于配置构造方法(当一个 POJO 中未定义无参的构造方法时,就可 以使用<constructor>元素进行配置)。 子元素<id>用于表示哪个列是主键,而<result>用于表示 POJO 和数据表中普通列的映射关系。 <association>和<collection>用于处理多表时的关联关 系,而<discriminator>元素主要用于处理一个单独的数据库查询返回很多不同数据类型结果集的情况。
在默认情况下, MyBatis 程序在运行时会自动地将查询到的数据与需要返回的对象的属性进行匹配赋值(需要表中的列名与对象的属性名称完全一致)。 然而实际开发时,数据表中的列和需要返回的对象的属性可能不会完全一致,这种情况下 MyBatis 是不会自动赋值的。 此时,就可以使用<resultMap>元素进行处理。
接下来,通过一个具体的案例来演示<resultMap>元素在此种情况的使用,具体步骤如下。
( 1 )在 mybatis 数据库中,创建一个 t_user 表,并插入几条测试数据。



( 2 )在 com.neuedu.po 包中,创建持久化类 User,并在类中定义 id、 name 和 age 属性, 以及其 getter/setter 方法和 toString()方法,文件如下所示。
package com.neuedu.po;
public class User {
  private Integer id;
  private String name;
  private Integer age;
  public Integer getId() {
      return id;
  }
  public void setId(Integer id) {
      this.id = id;
  }
  public String getName() {
      return name;
  }
  public void setName(String name) {
      this.name = name;
  }
  public Integer getAge() {
      return age;
  }
  public void setAge(Integer age) {
      this.age = age;
  }
  @Override
  public String toString() {
      return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
  }   
}

( 3 )在 com.neuedu.mapper 包下,创建映射文件 UserMapper.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.neuedu.mapper.UserMapper.xml">
  <resultMap type="com.neuedu.po.User" id="resultMap">
      <id property="id" column="t_id"/>
      <result property="name" column="t_name"/>
      <result property="age" column="t_age"/>
  </resultMap>
  <select id="findAllUser" resultMap="resultMap">
      select * from t_user
  </select>
</mapper>

在上述文件中, <resultMap>的子元素<id>和<result>的 property 属性表示 User 类的属性名, column 属性表示数据表 t_user 的列名。 <select>元素的 resultMap 属性表示引用上面定义的 resultMap。
( 4 )在配置文件 mybatis-config.xml 中,引入 UserMapper.xml。
( 5 )在测试类中,编写测试方法 findAIIUserTest() ,代码如下所示。

  @Test
  public void findAllUserTest() {
      // 1.读取配置文件
      SqlSession sqlSession = MybatisUtils.getSession();
      // 2.SqlSession 执行映射文件中定义的 SQL,并返回映射结果
      List<User> users = sqlSession.selectList("com.neuedu.mapper.UserMapper.findAllUser");
      for (User user : users) {
          System.out.println(user);
      }
      //3.关闭 SqlSession
      sqlSession.close();
  }

使用 JUnit4 执行上述方法后,控制台的输出结果如图所示。



从图可以看出,虽然 t_user 表的列名与 User 对象的属性名完全不一样,但查询出的数据还是被正确地封装到了 User 对象中。
除此之外,还可以通过<resultMap>元素中的<association>和<collection>处理多表时的关联关系。 关于关联关系的内容,将在后面章中详细讲解,这里就不再叙述。

本章小结

本章主要对 MyBatis 中的核心对象和核心文件进行了详细讲解。首先讲解了 MyBatis 中的两个重要核心对象 SqlSessionFactory 和 SqlSession ;然后介绍了配置文件中的元素及其使用;最后对映射文件中的几个主要元素进行了详细讲解。 通过本章的学习,大家将能够了解 MyBatis 中两个核心对象的作用,熟悉配置文件中常用元素的使用,并掌握映射文件中常用元素的使用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容