前言:前文讲解了 MyBatis 的配置文件一部分用法,本文将继续讲解 MyBatis 的配置文件的用法。

目录

1、typeHandler 类型处理器

2、ObjectFactory

3、插件

4、environments 配置环境

5、databaseIdProvider 数据库厂商标识

6、引入映射器的方法

1、typeHandler 类型处理器

  MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,或者从结果集(ResultSet)中取出一个值时,都会用注册了的 typeHandle 进行处理。

  由于数据库厂商不同,字段类型就不同,所以从 java 传递参数到数据库,或者从数据库中读取数据到 java,我们都需要进行字段的处理。typeHandle 的作用,就是将参数从 javaType 转化为 jdbcType,或者从数据库中取出结果时把 jdbcType 转化为 javaType。

  typeHandle 和别名一样,也分为 MyBatis 系统定义和用户自定义两种。  

1.1 dtd 规则

  常用的配置:java 类型(javaType)、JDBC 类型(jdbcType)。

1.2 系统定义的 typeHandle

  MyBatis 系统内部就定义了一系列的 typeHandle,源码在 org.apache.ibatis.type.TypeHandlerRegistry,如下:

  1. public TypeHandlerRegistry() {
  2. this.register((Class)Boolean.class, (TypeHandler)(new BooleanTypeHandler()));
  3. this.register((Class)Boolean.TYPE, (TypeHandler)(new BooleanTypeHandler()));
  4. this.register((JdbcType)JdbcType.BOOLEAN, (TypeHandler)(new BooleanTypeHandler()));
  5. this.register((JdbcType)JdbcType.BIT, (TypeHandler)(new BooleanTypeHandler()));
  6. this.register((Class)Byte.class, (TypeHandler)(new ByteTypeHandler()));
  7. this.register((Class)Byte.TYPE, (TypeHandler)(new ByteTypeHandler()));
  8. this.register((JdbcType)JdbcType.TINYINT, (TypeHandler)(new ByteTypeHandler()));
  9. this.register((Class)Short.class, (TypeHandler)(new ShortTypeHandler()));
  10. this.register((Class)Short.TYPE, (TypeHandler)(new ShortTypeHandler()));
  11. this.register((JdbcType)JdbcType.SMALLINT, (TypeHandler)(new ShortTypeHandler()));
  12. this.register((Class)Integer.class, (TypeHandler)(new IntegerTypeHandler()));
  13. this.register((Class)Integer.TYPE, (TypeHandler)(new IntegerTypeHandler()));
  14. this.register((JdbcType)JdbcType.INTEGER, (TypeHandler)(new IntegerTypeHandler()));
  15. this.register((Class)Long.class, (TypeHandler)(new LongTypeHandler()));
  16. this.register((Class)Long.TYPE, (TypeHandler)(new LongTypeHandler()));
  17. this.register((Class)Float.class, (TypeHandler)(new FloatTypeHandler()));
  18. this.register((Class)Float.TYPE, (TypeHandler)(new FloatTypeHandler()));
  19. this.register((JdbcType)JdbcType.FLOAT, (TypeHandler)(new FloatTypeHandler()));
  20. this.register((Class)Double.class, (TypeHandler)(new DoubleTypeHandler()));
  21. this.register((Class)Double.TYPE, (TypeHandler)(new DoubleTypeHandler()));
  22. this.register((JdbcType)JdbcType.DOUBLE, (TypeHandler)(new DoubleTypeHandler()));
  23. this.register((Class)Reader.class, (TypeHandler)(new ClobReaderTypeHandler()));
  24. this.register((Class)String.class, (TypeHandler)(new StringTypeHandler()));
  25. this.register((Class)String.class, JdbcType.CHAR, (TypeHandler)(new StringTypeHandler()));
  26. this.register((Class)String.class, JdbcType.CLOB, (TypeHandler)(new ClobTypeHandler()));
  27. this.register((Class)String.class, JdbcType.VARCHAR, (TypeHandler)(new StringTypeHandler()));
  28. this.register((Class)String.class, JdbcType.LONGVARCHAR, (TypeHandler)(new ClobTypeHandler()));
  29. this.register((Class)String.class, JdbcType.NVARCHAR, (TypeHandler)(new NStringTypeHandler()));
  30. this.register((Class)String.class, JdbcType.NCHAR, (TypeHandler)(new NStringTypeHandler()));
  31. this.register((Class)String.class, JdbcType.NCLOB, (TypeHandler)(new NClobTypeHandler()));
  32. this.register((JdbcType)JdbcType.CHAR, (TypeHandler)(new StringTypeHandler()));
  33. this.register((JdbcType)JdbcType.VARCHAR, (TypeHandler)(new StringTypeHandler()));
  34. this.register((JdbcType)JdbcType.CLOB, (TypeHandler)(new ClobTypeHandler()));
  35. this.register((JdbcType)JdbcType.LONGVARCHAR, (TypeHandler)(new ClobTypeHandler()));
  36. this.register((JdbcType)JdbcType.NVARCHAR, (TypeHandler)(new NStringTypeHandler()));
  37. this.register((JdbcType)JdbcType.NCHAR, (TypeHandler)(new NStringTypeHandler()));
  38. this.register((JdbcType)JdbcType.NCLOB, (TypeHandler)(new NClobTypeHandler()));
  39. this.register((Class)Object.class, JdbcType.ARRAY, (TypeHandler)(new ArrayTypeHandler()));
  40. this.register((JdbcType)JdbcType.ARRAY, (TypeHandler)(new ArrayTypeHandler()));
  41. this.register((Class)BigInteger.class, (TypeHandler)(new BigIntegerTypeHandler()));
  42. this.register((JdbcType)JdbcType.BIGINT, (TypeHandler)(new LongTypeHandler()));
  43. this.register((Class)BigDecimal.class, (TypeHandler)(new BigDecimalTypeHandler()));
  44. this.register((JdbcType)JdbcType.REAL, (TypeHandler)(new BigDecimalTypeHandler()));
  45. this.register((JdbcType)JdbcType.DECIMAL, (TypeHandler)(new BigDecimalTypeHandler()));
  46. this.register((JdbcType)JdbcType.NUMERIC, (TypeHandler)(new BigDecimalTypeHandler()));
  47. this.register((Class)InputStream.class, (TypeHandler)(new BlobInputStreamTypeHandler()));
  48. this.register((Class)Byte[].class, (TypeHandler)(new ByteObjectArrayTypeHandler()));
  49. this.register((Class)Byte[].class, JdbcType.BLOB, (TypeHandler)(new BlobByteObjectArrayTypeHandler()));
  50. this.register((Class)Byte[].class, JdbcType.LONGVARBINARY, (TypeHandler)(new BlobByteObjectArrayTypeHandler()));
  51. this.register((Class)byte[].class, (TypeHandler)(new ByteArrayTypeHandler()));
  52. this.register((Class)byte[].class, JdbcType.BLOB, (TypeHandler)(new BlobTypeHandler()));
  53. this.register((Class)byte[].class, JdbcType.LONGVARBINARY, (TypeHandler)(new BlobTypeHandler()));
  54. this.register((JdbcType)JdbcType.LONGVARBINARY, (TypeHandler)(new BlobTypeHandler()));
  55. this.register((JdbcType)JdbcType.BLOB, (TypeHandler)(new BlobTypeHandler()));
  56. this.register(Object.class, this.UNKNOWN_TYPE_HANDLER);
  57. this.register(Object.class, JdbcType.OTHER, this.UNKNOWN_TYPE_HANDLER);
  58. this.register(JdbcType.OTHER, this.UNKNOWN_TYPE_HANDLER);
  59. this.register((Class)Date.class, (TypeHandler)(new DateTypeHandler()));
  60. this.register((Class)Date.class, JdbcType.DATE, (TypeHandler)(new DateOnlyTypeHandler()));
  61. this.register((Class)Date.class, JdbcType.TIME, (TypeHandler)(new TimeOnlyTypeHandler()));
  62. this.register((JdbcType)JdbcType.TIMESTAMP, (TypeHandler)(new DateTypeHandler()));
  63. this.register((JdbcType)JdbcType.DATE, (TypeHandler)(new DateOnlyTypeHandler()));
  64. this.register((JdbcType)JdbcType.TIME, (TypeHandler)(new TimeOnlyTypeHandler()));
  65. this.register((Class)java.sql.Date.class, (TypeHandler)(new SqlDateTypeHandler()));
  66. this.register((Class)Time.class, (TypeHandler)(new SqlTimeTypeHandler()));
  67. this.register((Class)Timestamp.class, (TypeHandler)(new SqlTimestampTypeHandler()));
  68. if(Jdk.dateAndTimeApiExists) {
  69. Java8TypeHandlersRegistrar.registerDateAndTimeHandlers(this);
  70. }
  71.  
  72. this.register((Class)Character.class, (TypeHandler)(new CharacterTypeHandler()));
  73. this.register((Class)Character.TYPE, (TypeHandler)(new CharacterTypeHandler()));
  74. }

  其中 StringTypeHandle,源码如下

  1. public class StringTypeHandler extends BaseTypeHandler<String> {
  2. public StringTypeHandler() {
  3. }
  4.  
  5. public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
  6. ps.setString(i, parameter);
  7. }
  8.  
  9. public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
  10. return rs.getString(columnName);
  11. }
  12.  
  13. public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
  14. return rs.getString(columnIndex);
  15. }
  16.  
  17. public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
  18. return cs.getString(columnIndex);
  19. }
  20. }

  StringTypeHandle 继承了 BaseTypeHandle。而 BaseTypeHandle 实现了接口 typeHandle,并且自己定义了 4 个抽象方法。

  setParameter 是 PreparedStatement 对象设置参数,它允许我们自己填写变换规则。

  getResult 则分为 ResultSet 用列名(columnName)或者使用列下标(columnIndex)来获取结果数据。其中还包括了 CallableStatement(存储过程)获取结果及数据的方法。

1.3 自定义 typeHandler

  从上面系统定义的 typeHandler 中来看,其实已经能够应付大部分的场景了,但是有一些特殊情况还是需要自定义 typeHandler。

  这里实现一个字符串参数的 typeHandler。首先配置 XML 文件,确定我们需要处理上面类型的参数和结果。

  1. <!--自定义类型处理器-->
  2. <typeHandlers>
  3. <typeHandler handler="com.yule.mybatis.typehandle.MyStringTypeHandler" javaType="string" jdbcType="VARCHAR"/>
  4. </typeHandlers>

  或者采取包扫描的方式

  1. <!--自定义类型处理器-->
  2. <typeHandlers>
  3. <package name="com.yule.mybatis.typehandler"/>
  4. </typeHandlers>

  源码里的 StringTypeHandler 使用的是继承 BaseTypeHandler,而这里采取实现 TypeHandler 接口来实现。

  自定义的 typeHandler 中配置的 jdbcType,javaType,需要使用注解在 handle 类中绑定。

  1. package com.yule.mybatis.typehandler;
  2.  
  3. import org.apache.ibatis.type.JdbcType;
  4. import org.apache.ibatis.type.MappedJdbcTypes;
  5. import org.apache.ibatis.type.MappedTypes;
  6. import org.apache.ibatis.type.TypeHandler;
  7. import org.slf4j.Logger;
  8. import org.slf4j.LoggerFactory;
  9.  
  10. import java.sql.CallableStatement;
  11. import java.sql.PreparedStatement;
  12. import java.sql.ResultSet;
  13. import java.sql.SQLException;
  14.  
  15. /**
  16. * @author yule
  17. * @date 2018/8/12 17:52
  18. */
  19. @MappedTypes({String.class})
  20. @MappedJdbcTypes(JdbcType.VARCHAR)
  21. public class MyStringTypeHandler implements TypeHandler<String> {
  22. private Logger logger = LoggerFactory.getLogger(MyStringTypeHandler.class);
  23.  
  24. @Override
  25. public void setParameter(PreparedStatement preparedStatement, int i, String s, JdbcType jdbcType) throws SQLException {
  26. logger.info("使用我的 typeHandler");
  27. preparedStatement.setString(i, s);
  28. }
  29.  
  30. @Override
  31. public String getResult(ResultSet resultSet, String s) throws SQLException {
  32. logger.info("使用我的 typeHandler,ResultSet 列名获取字符串");
  33. return resultSet.getString(s);
  34. }
  35.  
  36. @Override
  37. public String getResult(ResultSet resultSet, int i) throws SQLException {
  38. logger.info("使用我的 typeHandler,ResultSet 下标获取字符串");
  39. return resultSet.getString(i);
  40. }
  41.  
  42. @Override
  43. public String getResult(CallableStatement callableStatement, int i) throws SQLException {
  44. logger.info("使用我的 typeHandler,CallableStatement 下标获取字符串");
  45. return callableStatement.getString(i);
  46. }
  47. }

  注解 @MappedTypes 定义的是 JavaType 类型,可以指定哪些 Java 类型被拦截。

  注解 @MappedJdbcTypes 定义的是 JdbcType 类型,它需要满足枚举类 org.apache.ibatis.type.JdbcType 所列的枚举类型。

  到这里,我们还需要去 sql 里标注哪些参数或结果类型去用我们自定义的 TypeHandler 进行转换,因为在没有任何标注的情况,MyBatis 是不会启用自定义的 TypeHandler。可以通过配置 jdbcType 和 javaType,或者直接使用 typeHandler 属性指定。

  1. <select id="queryUserByName" resultType="user">
  2. select t.id, t.name, t.age from t_user t
  3. where t.name = #{name,javaType=String,jdbcType=VARCHAR,typeHandler=com.yule.mybatis.typehandler.MyStringTypeHandler}
  4. </select>

  这时运行 sql,就可以了。

1.4 枚举类型 typeHandler

2、ObjectFactory

  当 MyBatis 在构建一个结果返回的时候,会使用 ObjectFactory(对象工厂)去创建 POJO,在 MyBatis 中可以定制自己的对象工厂。

  一般情况下,我们使用默认的对象工厂即可,MyBatis 中默认的对象工厂是由 org.apache.ibatis.reflection.factory.DefaultObjectFactory 来提供服务的。

  如果特殊情况下,需要定制特定的工厂,xml 中配置如下:

  1. <!--自定义对象工厂-->
  2. <objectFactory type="com.yule.mybatis.objectfactory.MyObjectFactory">
  3. <property name="name" value="MyObjectFactory"/>
  4. </objectFactory>

  MyObjectFactory 可以参考 DefaultObjectFactory 的写法来,这里为了测试方便,直接继承 DefaultObjectFactory 来简化编程。

  1. package com.yule.mybatis.objectfactory;
  2.  
  3. import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
  4.  
  5. import java.util.List;
  6. import java.util.Properties;
  7.  
  8. /**
  9. * @author yule
  10. * @date 2018/8/12 19:34
  11. */
  12. public class MyObjectFactory extends DefaultObjectFactory {
  13.  
  14. private static final long serialVersionUID = -8855120656740914948L;
  15.  
  16. @Override
  17. public void setProperties(Properties properties) {
  18. System.out.println("使用我自己的对象工厂 定制属性");
  19. super.setProperties(properties);
  20. }
  21.  
  22. @Override
  23. public <T> T create(Class<T> type) {
  24. System.out.println("使用我自己的对象工厂 构建单个对象");
  25. return super.create(type);
  26. }
  27.  
  28. @Override
  29. public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
  30. System.out.println("使用我自己的对象工厂 构建对象列表");
  31. return super.create(type, constructorArgTypes, constructorArgs);
  32. }
  33.  
  34. @Override
  35. public <T> boolean isCollection(Class<T> aClass) {
  36. return false;
  37. }
  38. }

  这样我们配置的对象工厂就已经生效。

  大部分情况下,我们使用系统默认的对象工厂即可。

3、插件

4、environments 配置环境

4.1 概述

  配置环境可以注册多个数据源(dataSource),每一个数据源分为两大部分:数据源的配置和数据库事务(transactionManager)的配置。

  1. <!--配置环境-->
  2. <environments default="development">
  3. <environment id="development">
  4. <transactionManager type="JDBC">
  5. <property name="autoCommit" value="false"/>
  6. </transactionManager>
  7. <dataSource type="POOLED">
  8. <property name="driver" value="${driver}"/>
  9. <property name="url" value="${datasourceurl}"/>
  10. <property name="username" value="${username}"/>
  11. <property name="password" value="${password}"/>
  12. </dataSource>
  13. </environment>
  14. </environments>

  environments 中的属性 default,标明在缺省的情况下,我们将启用哪个数据源配置。

  environment 元素是配置一个数据源,属性 id 是设置这个数据源的唯一标识,以便 MyBatis 上下文使用它。

  transactionManager 配置的是数据库事务,其中 type 属性有 3 中配置方式:

  (1)JDBC,采用 JDBC 方式管理事务,在独立编码中我们常常使用。

  (2)MANAGED,采用容器方式管理事务,在 JNDI 数据源中常用。

  (3)自定义,由使用者自定义数据库事务管理方式,适用于特殊应用。

  property 元素则是可以配置数据源的各类属性,我们这个配置了 autoCommit = false,则是要求数据源不自动提交。

  dataSource 标签,是配置数据源连接的信息,type 属性是提供我们队数据库连接方式的配置,同样 MyBatis 提供几种配置方式:

  (1)UNPOOLED,非连接池数据库(UnpooledDataSource)。

  (2)POOLED,连接池数据库(PooledDataSource)。

  (3)自定义数据源。

  其中,配置的 property 元素,就是定义数据库的各类参数。

4.2 数据源

  MyBatis 内部提供了 3 中数据源的实现方式:

  (1)UNPOOLED,非连接池,使用org.apache.ibatis.datasource.unpooled.UnpooledDataSource 实现。

  (2)POOLED,连接池,使用 org.apache.ibatis.datasource.pooled.PooledDataSource 实现。

  (3)JNDI,使用 org.apache.ibatis.datasource.jndi.JndiDataSourceFactory 来获取数据源。

  这 3 中方式实现比较简单,只需要在 dataSource 标签的 type定义为 UNPOOLED,POOLED,JNDI 即可。

  如果还需要其他的数据源,可以自定义一个类 MyDataSourceFactory,实现 org.apache.ibatis.datasource.DataSourceFactory 接口,可以参考 JndiDataSourceFactory,然后在 dataSource 标签中配置 type="xxx.xxx.MyDataSourceFactory",即可。

5、databaseIdProvider 数据库厂商标识

  如果 MyBatis 需要运行在不同厂商的数据库中,会需要使用到数据库厂商标识,它为此提供一个数据库标识,并提供自定义,作用在于指定 SQL 到对应的数据库厂商提供的数据库中运行。

  用的很少,所以就不先不在这里讲解。

6、引入映射器的方法

  引入映射器的几种方式:

  1. <!-- 引入映射器 的几种方式 -->
  2. <mappers>
  3. <!--使用类注册引入-->
  4. <!--<mapper class="com.yule.user.dao.UserDao"/>-->
  5. <!--使用文件路径引入-->
  6. <mapper resource="com/yule/user/dao/UserDao.xml"/>
  7. <!--使用包名引入映射器-->
  8. <!--<package name="com.yule.user.dao"/>-->
  9. <!--使用 userDao.xml 引入-->
  10. <!--<mapper url="file:F:\IDEAworkspace\sdemo\src\main\java\com\yule\user\dao\UserDao.xml"/>-->
  11. </mappers>

深入理解MyBatis的原理(三):配置文件用法(续)的更多相关文章

  1. 深入理解MyBatis的原理:整个体系

    前言:工作中虽然用到了 MyBatis,可完全不知道为什么,再不学习就晚了,这里将记录我的学习笔记,整个 MyBatis 的体系. 一.简介 1.传统的JDBC JDBC 是一种典型的桥接模式. 使用 ...

  2. 深入理解MyBatis的原理(三):配置文件(上)

    前言:前文提到一个入门的demo,从这里开始,会了解深入 MyBatis 的配置,本文讲解 MyBatis 的配置文件的用法. 目录 1.properties 元素 2.设置(settings) 3. ...

  3. 深入理解MyBatis的原理(四):映射器的用法

    前言:继续深入学习 mybatis 的用法及原理,还是先会用再学习原理. 映射器的主要元素有:select.insert.update.delete.parameterMap(即将被删除,不建议使用) ...

  4. 深入理解MyBatis的原理(一): 独立的入门demo

    前言:不结合spring,只有 mybatis+maven.数据库使用 oracle.不尝试永远不知道会发生什么事,其中遇到两个小问题,也记录下来了.转载请注明出处:https://www.cnblo ...

  5. 深入理解Mybatis技术与原理

    目录 第1章 Mybatis简介 1.1 传统的JDBC编程 1.2 ORM模型 1.4 MyBatis 1.5 什么时候用MyBatis 第2章 MyBatis入门 2.2 MyBatis构成 2. ...

  6. 《深入理解mybatis原理》 Mybatis初始化机制具体解释

    对于不论什么框架而言.在使用前都要进行一系列的初始化,MyBatis也不例外. 本章将通过下面几点具体介绍MyBatis的初始化过程. 1.MyBatis的初始化做了什么 2. MyBatis基于XM ...

  7. 《深入理解mybatis原理》 MyBatis的架构设计以及实例分析

    作者博客:http://blog.csdn.net/u010349169/article/category/2309433 MyBatis是目前非常流行的ORM框架,它的功能很强大,然而其实现却比较简 ...

  8. 深入理解mybatis原理, Mybatis初始化SqlSessionFactory机制详解(转)

    文章转自http://blog.csdn.net/l454822901/article/details/51829785 对于任何框架而言,在使用前都要进行一系列的初始化,MyBatis也不例外.本章 ...

  9. 《深入理解mybatis原理2》 Mybatis初始化机制详解

    <深入理解mybatis原理> Mybatis初始化机制详解 对于任何框架而言,在使用前都要进行一系列的初始化,MyBatis也不例外.本章将通过以下几点详细介绍MyBatis的初始化过程 ...

随机推荐

  1. IAP远程在线升级

    IAP远程在线升级 在上一篇中实现了LWIP网口通讯,那么肯定要加个在线升级功能,这个功能所占用的资源很少,但在物联网中很重要也很实用.在线升级就是像手机一样,先下载好系统,然后点击升级~然后就没然后 ...

  2. 698. Partition to K Equal Sum Subsets

    Given an array of integers nums and a positive integer k, find whether it's possible to divide this ...

  3. ajax post 400 bad request

    是前端ajax没有加声明:contentType:'application/json',

  4. iOS 关于布局问题的一些认识

    ///更新约束和布局 更新约束布局相关的API - (void)updateConstraintsIfNeeded  调用此方法,如果有标记为需要重新布局的约束,则立即进行重新布局,内部会调用upda ...

  5. POJ 1101

    #include <iostream> #include <string> #define MAXN 78 #define min _min #define inf 12345 ...

  6. Seqlist L 与 Seqlist *L的区别

     Seqlist L结构体变量,SeqlistInsert之后不可以带回新的插入数据.  Seqlist *L 是传结构体指针 用SeqlistInsert之后可以有新的插入.

  7. c#连接oracle遇到的问题

    1.最近在做项目,发现一个很有意思的现象.我在项目中引用System.Data.OracleClient进行oracle库的远程连接,一直出错.后来无意中,将.net framework 4.0框架改 ...

  8. (转)用Python写堡垒机项目

    原文:https://blog.csdn.net/ywq935/article/details/78816860 前言 堡垒机是一种运维安全审计系统.主要的功能是对运维人员的运维操作进行审计和权限控制 ...

  9. android Service 学习总结

    学习android开发已经四五个月,由于项目中职责的原因一直没有接触过Service的实际项目,今天重新学一遍Service用法. 问题: 作为四大组件,为什么需要Service? 它与Thread又 ...

  10. Git&GitHub学习日志

    Git是一个开源的分布式版本控制系统,用以有效.高速的处理从很小到非常大的项目版本管理. Git是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源码的版本控制软件.作为一个 ...