【MyBatis 笔记】MyBatis 相关分析与整理

文前说明

作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录。

MyBatis 的安装


  org.mybatis
  mybatis
  x.x.x

MyBatis 的核心组件

MyBatis 主要可以分为 4 个部分

类名称 说明 生命周期
SqlSessionFactoryBuilder(构造器) 根据配置或代码生成 SqlSessionFactory,采用 Builder 分布构建。 一旦创建了 SqlSessionFactory,就不再需要。
SqlSessionFactory(工厂接口) 工厂生成 SqlSession。 单例,一旦被创建就应该在应用的运行期间一直存在。
SqlSession(会话) 发送 SQL 执行返回结果,获取 Mapper 接口。 每个线程都应该有它自己的 SqlSession 实例。
SQL Mapper(映射器) 负责发送 SQL 执行,并返回结果。 映射器是创建用来绑定映射语句的接口。映射器接口的实例是从 SqlSession 中获得的,与 SqlSession 生命周期一致。

MyBatis 的解析与运行

MyBatis 的运行过程,可以分为两步:第一步,读取配置文件缓存到 Configuration 对象,用来创建 SqlSessionFactory;第二步,执行 SqlSession。

1. 构建 SqlSessionFactory

  • 通过 XMLConfigBuilder 解析配置文件,创建 Configuration 对象(单例模式),将 XML 内容放入对象中。
  • 使用 Configuration 对象,创建 SqlSessionFactory。
SqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
1.1 构建 Configuration 对象
  • 通过 XMLConfigBuilder 解析配置文件,进行初始化。
初始化步骤名称 说明
properties 全局属性
settings 设置
typeAliases 类型别名
objectFactory 对象工厂
plugins 插件
environments 数据库环境变量
dataSource 数据源
databaseIdProvider 数据库厂商标识
typeHandlers 类型处理器
mappers 映射器
1.2 映射器的内部组成
  • MappedStatement 作用保存映射器节点(select|insert|delete|update)的内容。包括配置 SQL 的 id、缓存信息、resultMap、parameterType、resultType、languageDriver 等。还包含 SqlSource,用以获取某条 SQL 的配置信息。
  • SqlSource 提供 BoundSql 对象,是 MappedStatement 的属性,是一个接口,主要实现有 DynamicSqlSource(动态 SQL)、ProviderSqlSource、RawSqlSource、StaticSqlSource 等。
  • BoundSql 是结果对象,是由 SqlSource 对 SQL 和参数解析而获得,包含 sql、parameterObject、parameterMappings 属性。
属性名称 说明
sql 被 SqlSource 解析后的可执行的 SQL 语句。
parameterObject 参数对象本身,传递简单参数、POJO 或者 Map、@Param 注解参数。
parameterMappings 是一个List,对每个参数进行描述包括属性名称、表达式、javaType、jdbcType、typeHandler 等。

2. SqlSession 的运行过程

  • 通过 SqlSessionFactory 获得。
  • Mapper 采用了动态代理方式调用,实际执行了 SqlSession 自身的方法。
  • SqlSession 的执行过程通过 Executor、StatementHandler、ParameterHandler、ResultSetHandler 完成。
对象名称 说明
Executor 执行器,由它调度 StatementHandler、ParameterHandler 和 ResultSetHandler 。
StatementHandler 使用数据库 Statement 完成数据库操作。
ParameterHandler 处理 SQL 参数。
ResultSetHandler 封装数据集(ResultSet)后返回。
  • Executor 包含三种执行器。
执行器名称 说明
SIMPLE 简易执行器,MyBits 默认使用。
REUSE 能够执行重用预处理语句的执行器。
BATCH 能执行重用语句和批量更新的执行器。
  • 在 Executor 中,通过 Configuration 构造 StatementHandler,通过 prepareStatement 方法,对 SQL 编译和参数进行初始化。
  • StatementHandler 作为数据库会话器,实际创建了 RoutingStatementHandler 对象,并且采用了适配模式,寻找对应的 StatementHandler 来执行。
适配 Handler 名称 说明
SimpleStatementHandler 简单处理
PreparedStatementHandler 预编译处理
CallableStatementHandler 存储过程处理
  • Executor 调度 StatementHandler,执行 prepared 预编译 SQL。
  • 执行 parameterize 方法,启用 ParameterHandler 设置参数。
  • 执行查询或者 update 的 SQL 语句,返回通过 ResultSetHandler 封装结果。
  • ParameterHandler 设置参数,是根据类型处理器 typeHandler 处理的。
  • update 的 SQL 语句,返回整数,查询返回通过 typeHandler 处理结果类型,再用 ObjectFactory 提供的规则封装结果对象。

MyBatis 映射文件配置

1. properties

  • 引用 propertis 文件并读取配置信息,可以在 标签中定义属性。

  • 创建一个资源文件 jdbc.properties。

jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521:orcl
jdbc.username=mybatis  
jdbc.password=mybatis
  • mybatis-config.xml 中引入

  • 可以在 标签中定义属性

    

  • 使用 properties 文件里的属性
  
        
        
        
         

  • 配置的加载顺序

在 properties 元素体内指定的属性首先被读取。然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。

2. settings

  • MyBatis 的调整设置,会改变 MyBatis 的运行时行为。
  • 配置方式

  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

常用设置名称 说明 默认值
cacheEnabled 配置影响的所有映射器中配置的缓存的全局开关 true
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 false
aggressiveLazyLoading 开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载 false
logImpl 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 /

3. typeAliases

  • 类型别名。给java类型取一个别名,方便在核心配置、映射配置中来使用这个 java 类型。它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。在 mybatis 中别名是不区分大小写的。

  • 比较(区别看 resultType)不使用别名


  • 使用别名,在核心配置文件中加上配置
  
      
      

  • 或者注解方式,用以避免因为别名重名导致的扫描失败问题。

  


@Alias("user")
public class User {
    ...
}

在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名,若有注解,则别名为其注解值,修改 UserMapper.xml 的配置。


已经为许多常见的 Java 类型内建了相应的类型别名。它们都是大小写不敏感的,需要注意的是由基本类型名称重复导致的特殊处理。

4. typeHandlers

  • 类型处理器,无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。
  • 用途:1)获取数据库的值,以合适的方式转变为对应的 java 类型;2)将java类型,以合适的方式转化为数据库的保存类型。
  • 自定义类型处理器,需要实现 org.apache.ibatis.type.TypeHandler 接口,或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler,然后可以选择性地将它映射到一个 JDBC 类型。
// ExampleTypeHandler.java
@MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler {

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
    ps.setString(i, parameter);
  }

  @Override
  public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
    return rs.getString(columnName);
  }

  @Override
  public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    return rs.getString(columnIndex);
  }

  @Override
  public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    return cs.getString(columnIndex);
  }
}



  

使用这个的类型处理器将会覆盖已经存在的处理 Java 的 String 类型属性和 VARCHAR 参数及结果的类型处理器。

  • 处理枚举类型,若想映射枚举类型 Enum,则需要从 EnumTypeHandler 或者 EnumOrdinalTypeHandler 中选一个来使用,默认情况下,MyBatis 会利用 EnumTypeHandler 来把 Enum 值转换成对应的名字。


  

5. databaseIdProvider

  • 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性,MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库。
  • 当 databaseIdProvider 的 type 属性被配置时,系统会优先取到和数据库配置一致的 SQL。如果没有,则取没有 databaseId 的 SQL,可以把它当作默认值。如果还是取不到,则会抛出异常,说明无法匹配到对应的 SQL。


  
          
  

6. 运行环境(environments)

  • 配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中,尽管可以配置多个环境,每个 SqlSessionFactory 实例只能选择其一。
  • 应用场景:1)为了开发设置不同的数据库配置;2)测试和生产环境数据库不同;3)有多个数据库却共享相同的模式,即对不同的数据库使用相同的SQL映射。
 
      
          
              
              
                  
                  
                  
                   
              
          
        
          
              
              
                  
                  
                  
                   
              
         
    
  • 用 default 指定默认的数据库链接

  • 根据数据库环境,获取 SqlSessionFactory
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment);
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment,properties);

6.1 environment 中的配置

  • transactionManager 事务管理器

type 取值 说明
JDBC 简单的使用JDBC的提交和回滚设置,一览与从数据员得到的链接来管理事务范围。
MANAGED 让容器来管理事务的整个生命周期。
  • dataSource 数据源
  
     
     
     
      

type 取值 说明
UNPOOLED 每次被请求时打开和关闭连接。速度会有一些慢,适用于简单的应用程序。
POOLED JDBC 链接对象的数据源连接池的实现,用来避免创建新的链接实例时必要的连接和认证时间。适用于当前Web应用程序用来快速响应请求。
JNDI 为了使用如 Spring 或应用服务器这类的容器,容器可以集中或在外部配置数据源,然后设置 JNDI 上下文的引用。
公用配置属性 说明
driver JDBC 驱动的 Java 类的完全限定名(并不是JDBC驱动中可能包含的数据源类)。
url 数据库的 JDBC URL 地址。
username 登录数据库的用户名。
password 登录数据库的密码。
defaultTransactionIsolationLevel 默认的连接事务隔离级别。
POOLED 扩展的配置属性 说明
poolMaximumActiveConnections 在任意时间可以存在的活动(也就是正在使用)连接数量,默认值:10
poolMaximumIdleConnections 任意时间可能存在的空闲连接数。
poolMaximumCheckoutTime 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)
poolTimeToWait 如果获取连接花费的相当长的时间,它会给连接池打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直安静的失败),默认值:20000 毫秒(即 20 秒)。
poolPingQuery 发送到数据库的侦测查询,用来检验连接是否处在正常工作秩序中并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动失败时带有一个恰当的错误消息。
poolPingEnabled 是否启用侦测查询。若开启,也必须使用一个可执行的 SQL 语句设置。poolPingQuery 属性(最好是一个非常快的 SQL),默认值:false。
poolPingConnectionsNotUsedFor 配置 poolPingQuery 的使用频度。这可以被设置成匹配具体的数据库连接超时时间,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用)。
JNDI 扩展的配置属性 说明
initial_context 用来在 InitialContext 中寻找上下文(即,initialContext.lookup(initial_context))。这是个可选属性,如果忽略,那么 data_source 属性将会直接从 InitialContext 中寻找。
data_source 引用数据源实例位置的上下文的路径。提供了 initial_context 配置时会在其返回的上下文中进行查找,没有提供时则直接在 InitialContext 中查找。
  • 通过需要实现接口 org.apache.ibatis.datasource.DataSourceFactory,也可使用任何第三方数据源。
public interface DataSourceFactory {
  void setProperties(Properties props);
  DataSource getDataSource();
}

7. 映射器(mappers)

  • 用于引用定义好的映射定义,告诉 mybatis 去哪里找我们的 sql 定义配置。
  • 直接引用 xml 文件。
  
       

  • 通过绝对路径引用,注意在绝对路径前加上:“file:///”。
 
      

  • 引用 mapper 接口对象的方式。
  
       

  • 引用 mapper 接口包的方式。
 
     

MyBatis 的 mapper XML 文件配置

1. select 标签(映射查询语句)

属性 说明
id 在命名空间中唯一的标识符,可以被用来引用这条语句,必选
parameterType 将会传入这条语句的参数类的完全限定名或别名,可选
parameterMap 这是引用外部 parameterMap 的已经被废弃的方法。使用内联参数映射和 parameterType 属性。
resultType 从语句中返回的期望类型的类的完全限定名或别名,如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用 resultType 或 resultMap,但不能同时使用。
resultMap 外部 resultMap 的命名引用。使用 resultMap 或 resultType,但不能同时使用。
flushCache 将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空。默认值:false
useCache 将其设置为 true,将会导致本条语句的结果被二级缓存,默认值:对 select 元素为 true。
timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)
fetchSize 这是尝试影响驱动程序每次批量返回的结果行数和这个设置值相等,默认值为 unset(依赖驱动)
statementType STATEMENT,PREPARED 或 CALLABLE 的一个,让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement。默认值:PREPARED
resultSetType 设置仅对多结果集的情况适用,它将列出语句执行后返回的结果集并每个结果集给一个名称,名称是逗号分隔的。
databaseId 如果配置了 databaseIdProvider,MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。

2. insert、update 标签

  • 除具备 id、parameterType、parameterMap 、flushCache、timeout、statementType、databaseId 属性外,还具备以下属性。
属性 说明
useGeneratedKeys 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。
keyProperty 唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
keyColumn 通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
  • 通常主键的生成都是让数据库自动生成的,比如 mysql 中主键设置 auto_increment,主流的数据库一般都支持。

  • 数据库支持自动生成主键,可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置到目标属性上。


  insert into Author (username,password,email,bio)
  values (#{username},#{password},#{email},#{bio})

  • 数据库不支持自动生成主键,在 insert 中使用 selectKey 语句。随机生成一个 ID做为主键,selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用。这给你了一个和数据库中来处理自动生成的主键类似的行为,避免了使 Java 代码变得复杂。

3. sql 标签

  • 这个标签可以被用来定义可重用的 SQL 代码段,可以包含在其他语句中。它可以被静态地(在加载参数) 参数化. 不同的属性值通过包含的实例变化。
  • 属性值可以用于包含的refid属性或者包含的字句里面的属性值。
 ${alias}.id,${alias}.username,${alias}.password 

4. resultMap 标签

一级标签 二级标签 三级标签 说明
constructor 类在实例化时,用来注入结果到构造方法中。
idArg ID 参数,标记结果作为 ID 可以帮助提高整体效能。
arg 注入到构造方法的一个普通结果。
id 一个 ID 结果,标记结果作为 ID 可以帮助提高整体效能。
result 注入到字段或 JavaBean 属性的普通结果。
association 一个复杂的类型关联,许多结果将包成这种类型。
嵌入结果映射 结果映射自身的关联,或者参考一个。
collection 复杂类型的集
嵌入结果映射 结果映射自身的集,或者参考一个。
discriminator 使用结果值来决定使用哪个结果映射
case 基于某些值的结果映射
嵌入结果映射 这种情形结果也映射它本身,因此可以包含很多相同的元素,或者它可以参照一个外部的结果映射。

4.1 discriminator(鉴别器)

  • 有时一个单独的数据库查询也许返回很多不同 (但是希望有些关联) 数据类型的结果集,表现很像 Java 语言中的 switch 语句

    
    
    
    
  

5. cache(缓存)标签

  • 要开启二级缓存,需要在 SQL 映射文件中添加一行 ,效果如下。
    • 映射语句文件中的所有 select 语句将会被缓存。
    • 映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。
    • 缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。
    • 根据时间表(比如 no Flush Interval,没有刷新间隔), 缓存不会以任何时间顺序 来刷新。
    • 缓存会存储列表集合或对象(无论查询方法返回什么)的 1024 个引用。
    • 缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而 且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,默认的是 LRU。

收回策略 说明
LRU 最近最少使用的,移除最长时间不被使用的对象。
FIFO 先进先出,按对象进入缓存的顺序来移除它们。
SOFT 软引用,移除基于垃圾回收器状态和软引用规则的对象。
WEAK 弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象

6. 动态 SQL

6.1 if 标签

  • 做条件判断的,如果我们不使用这个标签,我们肯定会在代码中判断如查询的元素是否为空,传入的元素是否为空,而这时我们直接使用这个标签,就减少了代码的书写。
  • 动态 SQL 通常要做的事情是有条件地包含 where 子句的一部分。

6.2 choose (when, otherwise) 标签

  • 采用多个选项中找一个,就像单项选择题,但是你不会都选择,只会从中选择1个来作为条件。就有点类似于switch。。case。

6.3 trim (where, set) 标签

  • 如果使用第一个if语句的话,就会发现没有写 where 标签就会报错。而这类标签通常是搭配条件标签使用的。where 一般可以用 1=1 来解决。

6.4 foreach 标签

  • 用于循环,用于遍历,如果我们传入的参数是一个数组或者集合类,那么这个标签可以循环遍历。一般我们都是使用 sql 中的 in 语句时才使用。

  • 可以将任何可迭代对象(如列表、集合等)和任何的字典或者数组对象传递给 foreach 作为集合参数
  • 当使用可迭代对象或者数组时,index 是当前迭代的次数,item 的值是本次迭代获取的元素。

7 #{} 和 ${} 的区别

7.1 #{}

  • 使用 #{} 格式的语法在 mybatis 中使用 Preparement 语句来安全的设置值。
  • # 方式能够很大程度防止 sql 注入。

7.2 ${}

  • 只是想直接在 SQL 语句中插入一个不改变的字符串。
  • $ 将传入的数据直接显示生成在 sql 中。
  • 使用 $ 要么不允许用户输入这些字段,要么自行转义并检验。
  • 一般能用 # 的就别用 $。

参考资料

http://www.mybatis.org/mybatis-3/zh/index.html
http://www.broadview.com.cn/book/80
http://www.jianshu.com/p/06b73e8d9f56
http://www.jianshu.com/p/8867e21655da

你可能感兴趣的:(【MyBatis 笔记】MyBatis 相关分析与整理)