前言:前文讲解了 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,如下:

public TypeHandlerRegistry() {
this.register((Class)Boolean.class, (TypeHandler)(new BooleanTypeHandler()));
this.register((Class)Boolean.TYPE, (TypeHandler)(new BooleanTypeHandler()));
this.register((JdbcType)JdbcType.BOOLEAN, (TypeHandler)(new BooleanTypeHandler()));
this.register((JdbcType)JdbcType.BIT, (TypeHandler)(new BooleanTypeHandler()));
this.register((Class)Byte.class, (TypeHandler)(new ByteTypeHandler()));
this.register((Class)Byte.TYPE, (TypeHandler)(new ByteTypeHandler()));
this.register((JdbcType)JdbcType.TINYINT, (TypeHandler)(new ByteTypeHandler()));
this.register((Class)Short.class, (TypeHandler)(new ShortTypeHandler()));
this.register((Class)Short.TYPE, (TypeHandler)(new ShortTypeHandler()));
this.register((JdbcType)JdbcType.SMALLINT, (TypeHandler)(new ShortTypeHandler()));
this.register((Class)Integer.class, (TypeHandler)(new IntegerTypeHandler()));
this.register((Class)Integer.TYPE, (TypeHandler)(new IntegerTypeHandler()));
this.register((JdbcType)JdbcType.INTEGER, (TypeHandler)(new IntegerTypeHandler()));
this.register((Class)Long.class, (TypeHandler)(new LongTypeHandler()));
this.register((Class)Long.TYPE, (TypeHandler)(new LongTypeHandler()));
this.register((Class)Float.class, (TypeHandler)(new FloatTypeHandler()));
this.register((Class)Float.TYPE, (TypeHandler)(new FloatTypeHandler()));
this.register((JdbcType)JdbcType.FLOAT, (TypeHandler)(new FloatTypeHandler()));
this.register((Class)Double.class, (TypeHandler)(new DoubleTypeHandler()));
this.register((Class)Double.TYPE, (TypeHandler)(new DoubleTypeHandler()));
this.register((JdbcType)JdbcType.DOUBLE, (TypeHandler)(new DoubleTypeHandler()));
this.register((Class)Reader.class, (TypeHandler)(new ClobReaderTypeHandler()));
this.register((Class)String.class, (TypeHandler)(new StringTypeHandler()));
this.register((Class)String.class, JdbcType.CHAR, (TypeHandler)(new StringTypeHandler()));
this.register((Class)String.class, JdbcType.CLOB, (TypeHandler)(new ClobTypeHandler()));
this.register((Class)String.class, JdbcType.VARCHAR, (TypeHandler)(new StringTypeHandler()));
this.register((Class)String.class, JdbcType.LONGVARCHAR, (TypeHandler)(new ClobTypeHandler()));
this.register((Class)String.class, JdbcType.NVARCHAR, (TypeHandler)(new NStringTypeHandler()));
this.register((Class)String.class, JdbcType.NCHAR, (TypeHandler)(new NStringTypeHandler()));
this.register((Class)String.class, JdbcType.NCLOB, (TypeHandler)(new NClobTypeHandler()));
this.register((JdbcType)JdbcType.CHAR, (TypeHandler)(new StringTypeHandler()));
this.register((JdbcType)JdbcType.VARCHAR, (TypeHandler)(new StringTypeHandler()));
this.register((JdbcType)JdbcType.CLOB, (TypeHandler)(new ClobTypeHandler()));
this.register((JdbcType)JdbcType.LONGVARCHAR, (TypeHandler)(new ClobTypeHandler()));
this.register((JdbcType)JdbcType.NVARCHAR, (TypeHandler)(new NStringTypeHandler()));
this.register((JdbcType)JdbcType.NCHAR, (TypeHandler)(new NStringTypeHandler()));
this.register((JdbcType)JdbcType.NCLOB, (TypeHandler)(new NClobTypeHandler()));
this.register((Class)Object.class, JdbcType.ARRAY, (TypeHandler)(new ArrayTypeHandler()));
this.register((JdbcType)JdbcType.ARRAY, (TypeHandler)(new ArrayTypeHandler()));
this.register((Class)BigInteger.class, (TypeHandler)(new BigIntegerTypeHandler()));
this.register((JdbcType)JdbcType.BIGINT, (TypeHandler)(new LongTypeHandler()));
this.register((Class)BigDecimal.class, (TypeHandler)(new BigDecimalTypeHandler()));
this.register((JdbcType)JdbcType.REAL, (TypeHandler)(new BigDecimalTypeHandler()));
this.register((JdbcType)JdbcType.DECIMAL, (TypeHandler)(new BigDecimalTypeHandler()));
this.register((JdbcType)JdbcType.NUMERIC, (TypeHandler)(new BigDecimalTypeHandler()));
this.register((Class)InputStream.class, (TypeHandler)(new BlobInputStreamTypeHandler()));
this.register((Class)Byte[].class, (TypeHandler)(new ByteObjectArrayTypeHandler()));
this.register((Class)Byte[].class, JdbcType.BLOB, (TypeHandler)(new BlobByteObjectArrayTypeHandler()));
this.register((Class)Byte[].class, JdbcType.LONGVARBINARY, (TypeHandler)(new BlobByteObjectArrayTypeHandler()));
this.register((Class)byte[].class, (TypeHandler)(new ByteArrayTypeHandler()));
this.register((Class)byte[].class, JdbcType.BLOB, (TypeHandler)(new BlobTypeHandler()));
this.register((Class)byte[].class, JdbcType.LONGVARBINARY, (TypeHandler)(new BlobTypeHandler()));
this.register((JdbcType)JdbcType.LONGVARBINARY, (TypeHandler)(new BlobTypeHandler()));
this.register((JdbcType)JdbcType.BLOB, (TypeHandler)(new BlobTypeHandler()));
this.register(Object.class, this.UNKNOWN_TYPE_HANDLER);
this.register(Object.class, JdbcType.OTHER, this.UNKNOWN_TYPE_HANDLER);
this.register(JdbcType.OTHER, this.UNKNOWN_TYPE_HANDLER);
this.register((Class)Date.class, (TypeHandler)(new DateTypeHandler()));
this.register((Class)Date.class, JdbcType.DATE, (TypeHandler)(new DateOnlyTypeHandler()));
this.register((Class)Date.class, JdbcType.TIME, (TypeHandler)(new TimeOnlyTypeHandler()));
this.register((JdbcType)JdbcType.TIMESTAMP, (TypeHandler)(new DateTypeHandler()));
this.register((JdbcType)JdbcType.DATE, (TypeHandler)(new DateOnlyTypeHandler()));
this.register((JdbcType)JdbcType.TIME, (TypeHandler)(new TimeOnlyTypeHandler()));
this.register((Class)java.sql.Date.class, (TypeHandler)(new SqlDateTypeHandler()));
this.register((Class)Time.class, (TypeHandler)(new SqlTimeTypeHandler()));
this.register((Class)Timestamp.class, (TypeHandler)(new SqlTimestampTypeHandler()));
if(Jdk.dateAndTimeApiExists) {
Java8TypeHandlersRegistrar.registerDateAndTimeHandlers(this);
} this.register((Class)Character.class, (TypeHandler)(new CharacterTypeHandler()));
this.register((Class)Character.TYPE, (TypeHandler)(new CharacterTypeHandler()));
}

  其中 StringTypeHandle,源码如下

public class StringTypeHandler extends BaseTypeHandler<String> {
public StringTypeHandler() {
} public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter);
} public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getString(columnName);
} public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getString(columnIndex);
} public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getString(columnIndex);
}
}

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

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

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

1.3 自定义 typeHandler

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

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

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

  或者采取包扫描的方式

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

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

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

package com.yule.mybatis.typehandler;

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; /**
* @author yule
* @date 2018/8/12 17:52
*/
@MappedTypes({String.class})
@MappedJdbcTypes(JdbcType.VARCHAR)
public class MyStringTypeHandler implements TypeHandler<String> {
private Logger logger = LoggerFactory.getLogger(MyStringTypeHandler.class); @Override
public void setParameter(PreparedStatement preparedStatement, int i, String s, JdbcType jdbcType) throws SQLException {
logger.info("使用我的 typeHandler");
preparedStatement.setString(i, s);
} @Override
public String getResult(ResultSet resultSet, String s) throws SQLException {
logger.info("使用我的 typeHandler,ResultSet 列名获取字符串");
return resultSet.getString(s);
} @Override
public String getResult(ResultSet resultSet, int i) throws SQLException {
logger.info("使用我的 typeHandler,ResultSet 下标获取字符串");
return resultSet.getString(i);
} @Override
public String getResult(CallableStatement callableStatement, int i) throws SQLException {
logger.info("使用我的 typeHandler,CallableStatement 下标获取字符串");
return callableStatement.getString(i);
}
}

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

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

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

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

  这时运行 sql,就可以了。

1.4 枚举类型 typeHandler

2、ObjectFactory

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

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

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

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

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

package com.yule.mybatis.objectfactory;

import org.apache.ibatis.reflection.factory.DefaultObjectFactory;

import java.util.List;
import java.util.Properties; /**
* @author yule
* @date 2018/8/12 19:34
*/
public class MyObjectFactory extends DefaultObjectFactory { private static final long serialVersionUID = -8855120656740914948L; @Override
public void setProperties(Properties properties) {
System.out.println("使用我自己的对象工厂 定制属性");
super.setProperties(properties);
} @Override
public <T> T create(Class<T> type) {
System.out.println("使用我自己的对象工厂 构建单个对象");
return super.create(type);
} @Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
System.out.println("使用我自己的对象工厂 构建对象列表");
return super.create(type, constructorArgTypes, constructorArgs);
} @Override
public <T> boolean isCollection(Class<T> aClass) {
return false;
}
}

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

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

3、插件

4、environments 配置环境

4.1 概述

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

    <!--配置环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="autoCommit" value="false"/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${datasourceurl}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</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、引入映射器的方法

  引入映射器的几种方式:

    <!-- 引入映射器 的几种方式 -->
<mappers>
<!--使用类注册引入-->
<!--<mapper class="com.yule.user.dao.UserDao"/>-->
<!--使用文件路径引入-->
<mapper resource="com/yule/user/dao/UserDao.xml"/>
<!--使用包名引入映射器-->
<!--<package name="com.yule.user.dao"/>-->
<!--使用 userDao.xml 引入-->
<!--<mapper url="file:F:\IDEAworkspace\sdemo\src\main\java\com\yule\user\dao\UserDao.xml"/>-->
</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. 【学习笔记】dsu on tree

    我也不知道为啥这要起这名,完完全全没看到并查集的影子啊…… 实际上原理就是一个树上的启发式合并. 特点是可以在$O(nlogn)$的时间复杂度内完成对无修改的子树的统计,复杂度优于莫队算法. 局限性也 ...

  2. Django templates html中进行模板渲染时使用python语法的基本方式

    导包(可以在模板中导入python包进行使用): <%!import urllib%> <%! from ** import **%> 使用if for等python语句: % ...

  3. elasticsearch中 refresh 和flush区别

    elasticsearch中有两个比较重要的操作:refresh 和 flush refresh操作 当我们向ES发送请求的时候,我们发现es貌似可以在我们发请求的同时进行搜索.而这个实时建索引并可以 ...

  4. [As3.0] 获取本机信息

    package { import flash.display.Sprite; import flash.events.Event; import flash.net.NetworkInfo; impo ...

  5. JDBC连接数据库7个步骤

    JDBC连接数据库    •创建一个以JDBC连接数据库的程序,包含7个步骤:    1.JDBC所需的四个参数(user,password,url,driverClass) (1)user用户名 ( ...

  6. To be learned

    1.web性能测试工具:LoadRunner:2.web自动化测试工具:selenium QTP:3.安全性测试工具:AppScan4.缺陷管理工具:TestLink+Mantisbt5..抓包工具: ...

  7. java日期加减操作

    1.用java.util.Calender来实现 Calendar calendar=Calendar.getInstance();      calendar.setTime(new Date()) ...

  8. 3、Xamarin Forms 调整安卓TabbedPage 下置

    降低学习成本是每个.NET传教士义务与责任. 建立生态,保护生态,见者有份.   教程晦涩难懂是我的错误. 对于默认的TabbedPage 上面进行页面切换 上面是安卓默认的情况 对我们大部分人来说都 ...

  9. 编写dimgr脚本学到的知识及技巧

    编写dimgr是为了管理手机上的镜像,在此总结下过程中学到的知识及技巧(不讨论具体用法). 参数处理 以往处理脚本参数直接用循环加判断语句,若是脚本只有简单参数,这无疑是简便可行的方法.但当需要处理复 ...

  10. InterView之PHP(2)

    PHP 理论知识 常用的超全局变量(8个) $_GET ----->get传送方式 $_POST ----->post传送方式 $_REQUEST ----->可以接收到get和po ...