博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入理解MyBatis的原理(三):配置文件用法(续)
阅读量:5057 次
发布时间:2019-06-12

本文共 13310 字,大约阅读时间需要 44 分钟。

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

目录

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()));    }
View Code

  其中 StringTypeHandle,源码如下

public class StringTypeHandler extends BaseTypeHandler
{ 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 文件,确定我们需要处理上面类型的参数和结果。

  或者采取包扫描的方式

  源码里的 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
{ 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 属性指定。

  这时运行 sql,就可以了。

1.4 枚举类型 typeHandler

2、ObjectFactory

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

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

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

  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 create(Class
type) { System.out.println("使用我自己的对象工厂 构建单个对象"); return super.create(type); } @Override public
T create(Class
type, List
> constructorArgTypes, List
constructorArgs) { System.out.println("使用我自己的对象工厂 构建对象列表"); return super.create(type, constructorArgTypes, constructorArgs); } @Override public
boolean isCollection(Class
aClass) { return false; }}

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

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

3、插件

4、environments 配置环境

4.1 概述

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

  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、引入映射器的方法

  引入映射器的几种方式:

 

转载于:https://www.cnblogs.com/yuxiaole/p/9464019.html

你可能感兴趣的文章
LeetCode 342. Power of Four
查看>>
「PKUWC2018」随机游走
查看>>
resteasy json
查看>>
个人理解的javascript作用域链与闭包
查看>>
ASP.NET ASHX 一般处理程序教程
查看>>
angular6 跨域问题
查看>>
Linux中JDK环境配置
查看>>
maven安装、配置及创建工程
查看>>
原生js简单实现定时抢月饼
查看>>
尝试向树莓派3B引入Drbian 9 arm64-PART 1
查看>>
Redis相关
查看>>
kvm 实际使用(转)
查看>>
CSP201612-1:中间数
查看>>
Android手机令牌,WEB安全之硬件绑定变向思路
查看>>
C++类的公用继承输入日志标题
查看>>
Loadrunner上传与下载文件脚本
查看>>
(水题)洛谷 - P2089 - 烤鸡
查看>>
Codeforces - 773A - Success Rate - 二分 - 简单数论
查看>>
select into from与insert into select区别
查看>>
git学习(一)----基础知识
查看>>