mybatis精讲(三)--标签及TypeHandler使用
话引
- 前两张我们分别介绍了Mybatis环境搭建及其组件的生命周期。这些都是我们Mybatis入门必备技能。有了前两篇的铺垫我们今天就来深入下Mybatis, 也为了填下之前埋下的坑。
XML配置标签
概览
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--引入外部配置文件-->
<properties resource=""/>
<!--设置-->
<settings/>
<!--定义别名-->
<typeAliases>
<package name=""/>
</typeAliases>
<!--类型处理器-->
<typeHandlers/>
<!--对象工厂-->
<objectFactory/>
<!--插件-->
<plugins/>
<!--定义数据库信息,默认使用development数据库构建环境-->
<environments default="development">
<environment id="development">
<!--jdbc事物管理-->
<transactionManager type="JDBC"/>
<!--配置数据库连接信息-->
<dataSource type="POOLED"/>
</environment>
</environments>
<!--数据库厂商标识-->
<databaseIdProvider/>
<mappers/>
</configuration>
- 上面模板列出了所有xml可以配置的属性。这里plugins是一个让人哭笑不得的东西。用的好是利器,用的不好就是埋坑。接下来我们来看看各个属性的作用
properties
- 该标签的作用就是引入变量。和maven的properties一样。在这里定义的变量或者引入的变量,在下面我们是可以童工${}使用的。
子标签property
<properties>
<property name="zxhtom" value="jdbc:mysql://localhost:3306/mybatis"/>
</properties>
<dataSource type="POOLED">
<property name="driver" value="${zxhtom}"/>
<dataSource>
- 上述的配置就可以直接使用zxhtom这个变量。
resource
- 除了上述方法我们还可以通过引入其他properties文件,就可以使用文件里的配置变量了。
<properties resource="mybatis.properties"/>
程序注入
- 最后还有一种我们在构建SqlSessionFactory的时候重新载入我们的Properties对象就可以了。另外三者的优先级是从低到高
settings
configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
configuration.setDefaultEnumTypeHandler(resolveClass(props.getProperty("defaultEnumTypeHandler")));
configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
configuration.setLogPrefix(props.getProperty("logPrefix"));
configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
- 上面代码是我们在XMLConfigBuilder解析settings标签的代码。从这段代码中我们了解到settings子标签。
参数 | 功能 | 可选值 | 默认值 |
---|---|---|---|
autoMappingBehavior |
指定Mybatis应如何自动映射列到字段上。 NONE : 表示取消自动映射 PARTIAL:只会自动映射没有定义嵌套结果集映射的结果集 FULL : 自动映射任意复杂的结果集 |
NONE、PARTIAL、FULL | PARTIAL |
autoMappingUnknownColumnBehavior |
指定识别到位置列或属性的时间 NONE : 什么都不做 WARNING:日志会报警(前提是日志设置了显示权限) FAILING : 抛出异常。 |
NONE, WARNING, FAILING | NONE |
cacheEnabled |
该配置影响的所有映射器中配置的缓存的全局开关 | true|false | true |
proxyFactory |
指定Mybatis创建具有延迟加载能力的对象所用到的代理工具未指定时将自动查找 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | not set |
lazyLoadingEnabled |
延时加载全局开关 开启时:级联对象会延时加载;级联标签中可以通过fetchType来定制覆盖此选项 |
true|false | false |
aggressiveLazyLoading |
启用时:对任意延迟属性的调用会使带有延迟加载属性的对象分层性质完整加载,反之按需加载 | true|false | true |
multipleResultSetsEnabled |
是否允许单一语句返回多结果集 | true|false | true |
useColumnLabel |
确切的说当映射找不到参数时会使用列标签(数据库列名)代替别名去映射 | true|false | true |
useGeneratedKeys |
允许 JDBC 支持自动生成主键,需要驱动兼容。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby) | true|false | false |
defaultExecutorType |
配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新 | SIMPLE REUSE BATCH | SIMPLE |
defaultStatementTimeout |
设置超时时间,决定驱动等待数据库响应的秒数 | 整数 | null |
defaultFetchSize |
设置数据库resultSet读取数据方式,默认全部加载进内存,设置该属性可以设置一次性读多少条数据进内存 | 整数 | null |
mapUnderscoreToCamelCase |
是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 | true|false | false |
safeRowBoundsEnabled |
-允许在嵌套语句中使用分页 | true|false | false |
localCacheScope |
一级缓存。mybatis默认对同一个sqlsession中数据是共享的。一个sqlsession调用两次相同查询实际只会查询一次。就是因为该属性为SESSION , STATEMENT则针对的是每一条sql | SESSION|STATEMENT | SESSION |
jdbcTypeForNull |
当没有为参数提供特定的jdbc类型时,为空值则指定JDBC类型。在新增时我们没有设置参数,这个时候就会根据此参数天长。加入设置VARCHAR,那么我们新增的数据没传参数则为空字符 | NULL|VARCHAR|OTHER | OTHER |
lazyLoadTriggerMethods |
指定具体方法延时加载 | 方法 | equals,clone,hashCode,toString |
safeResultHandlerEnabled |
允许在嵌套语句中使用分页 | true|false | true |
defaultScriptingLanguage |
动态SQL生成的默认语言 | org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver |
|
defaultEnumTypeHandler |
mybatis默认的枚举处理类 | ||
callSettersOnNulls |
指定当结果集中值为null的时候是否调用映射对象的setter(put)方法。 | ||
useActualParamName |
允许使用他们的编译后名称来映射,3.4.2后默认true.在xml中#{0}则报错。设置为false,则#{0}代表第一个参数#{n}第n个 | true|false | true |
returnInstanceForEmptyRow |
当返回行的所有列都是空时,MyBatis默认返回 null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集 (如集合或关联)。(新增于 3.4.2) | true|false | false |
logPrefix |
指定 MyBatis 增加到日志名称的前缀。 |
别名
- 别名是mybatis为我们项目中类起的一个名字,类名往往会很长所以别名就方便我们平时的开发。Mybatis为我们内置了一些类的别名:byte、short、int、long、float、double、boolean、char等基础类型的别名。还有其的封装类型、String,Object,Map,List等等常用的类。
org.apache.ibatis.type.TypeAliasRegistry
这个类中帮我们内置了别名。可以看下。自定义别名也是通过这个类进行注册的。我们可以通过settings中typeAliases配置的方式结合@Alias。或者扫描包也可以的。
TypeHandler
- 这个接口就四个方法
public interface TypeHandler<T> {
/**
* 设置参数是用到的方法
*/
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
- 可以理解成拦截器。它主要拦截的是设置参数和获取结果的两个节点。这个类的作用就是将Java对象和jdbcType进行相互转换的一个功能。同样的在
org.apache.ibatis.type.TypeHandlerRegistry
这个类中mybatis为我们提供了内置的TypeHandler。基本上是对于基本数据和分装对象的转换。 - 下面我们随便看一个TypeHandler处理细节
public class BooleanTypeHandler extends BaseTypeHandler<Boolean> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType)
throws SQLException {
ps.setBoolean(i, parameter);
}
@Override
public Boolean getNullableResult(ResultSet rs, String columnName)
throws SQLException {
boolean result = rs.getBoolean(columnName);
return !result && rs.wasNull() ? null : result;
}
@Override
public Boolean getNullableResult(ResultSet rs, int columnIndex)
throws SQLException {
boolean result = rs.getBoolean(columnIndex);
return !result && rs.wasNull() ? null : result;
}
@Override
public Boolean getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
boolean result = cs.getBoolean(columnIndex);
return !result && cs.wasNull() ? null : result;
}
}
- setParameter是PreparedStatement进行设置成boolean类型。getResult分别通过三种不同方式获取。在这些方法里我们可以根据自己也无需求进行控制。常见的控制是枚举的转换。传递参数过程可能是枚举的name,但是传递到数据库中要枚举的index.这种需求我们就可以在TypeHandler中实现。我们书写的typeHandler之后并不能被识别,还需要我们在resultMap中的result标签中通过typeHandler指定我们的自定义Handler.
自定义TypeHandler
- 承接上文我们说道枚举的转换。下面我们还是已学生类为例。学生中性别之前是boolean类型。现在我们采用枚举类型。但是数据库中存的还是数据,01.
EnumTypeHandler
- 在TypeHandlerRegister类中申明了默认的枚举类处理器是
private Class<? extends TypeHandler> defaultEnumTypeHandler = EnumTypeHandler.class;
。
@Override
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
String s = rs.getString(columnName);
return s == null ? null : Enum.valueOf(type, s);
}
- 我们通过这个方法可以看出,这个枚举处理器适合已枚举名称存储的方式
EnumOrdinalTypeHandler
在Enum中还有一个属性oridinal。这个表示枚举中的索引。然后我们通过查看Mybatis提供的处理器发现有个叫
EnumOrdinalTypeHandler
。我们很容易联想到的就是这个处理器是通过枚举的所以作为数据库内容的。在SexEnum中MALE存储到数据库中则为0.注意这个0不是我们的index.而是MALE的索引。如果将MALE和FEMAEL调换。那么MALE索引则为1.因为默认的是EnumTypeHandler。所以想用EnumOrdinalTypeHandler的话我们要么在resultMap中sex字段指定该处理器。要不就通过配置文件typeHandlers注册进来。(将处理器与Java类进行绑定。mybatis遇到这个Java对象的时候就知道用什么处理器处理)
<typeHandlers>
<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.github.zxhtom.enums.SexEnum"/>
</typeHandlers>
SexTypeHandler
- 上面的不管是通过名称存储还是通过索引存储都不太满足我们的需求。我们想通过我们的index存储。那么这时候我们就得自定义处理逻辑了。Mybatis处理器都是继承BaseTypeHandler。因为BaseTypeHandler实现了TypeHandler.所以我们这里也就继承BaseTypeHandler。
public class SexTypeHandler extends BaseTypeHandler<SexEnum> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, SexEnum parameter, JdbcType jdbcType) throws SQLException {
ps.setInt(i,parameter.getIndex());
}
@Override
public SexEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
int i = rs.getInt(columnName);
return SexEnum.getSexEnum(i);
}
@Override
public SexEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
int i = rs.getInt(columnIndex);
return SexEnum.getSexEnum(i);
}
@Override
public SexEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
int i = cs.getInt(columnIndex);
return SexEnum.getSexEnum(i);
}
}
typeHandler注意点
- 在编写自定义处理器的时候我们得之处Javatype、jdbctype。两者不是必填。但至少得有一个。正常我们默认javatype是必填的。
- 填写的方式有三种
- 通过MappedTypes、MappedJdbcTypes分别指定javatype、jdbctype
- 通过在mybatis-config.xml中配置typeHandlers进行注解。里面也有这两个属性的配置。
- 通过在mapper.xml的resultmap中再次指定某个字段的typehandler.
- TypeHandler为我们提供了Java到jdbc数据的转换桥梁。极大的方便了我们平时的开发。让我们开发期间忽略数据的转换这么糟心的事情。
# 加入战队
微信公众号
mybatis精讲(三)--标签及TypeHandler使用的更多相关文章
- mybatis精讲(五)--映射器组件
目录 前言 标签 select insert|update|delete 参数 resultMap cache 自定义缓存 # 加入战队 微信公众号 前言 映射器之前我们已经提到了,是mybatis特 ...
- Mybatis精讲(一)---环境配置及架构梳理
目录 简介 ORM模型 Hibernate Ibatis 环境搭建 jar 配置 xml方式配置 代码方式配置 两种方式对比 Mybatis结构 源码解读xml环境加载 映射器解读 Ibatis # ...
- Mybatis精讲(二)---生命周期
目录 回顾 SqlSessionFactoryBuilder SqlSessionFactory openSessionFromDataSource Executor SqlSession Mappe ...
- mybatis精讲(四)--ObjectFactory
目录 前言 mybatis的ObjectFactory 源码 setProperties create instantiateClass 使用场景 # 加入战队 微信公众号 前言 ObjectFact ...
- mybatis精讲(六)--二级缓存
目录 简介 配置 源码 CachingExecutor 自定义二级缓存 # 加入战队 微信公众号 简介 上一章节我们简单了解了二级缓存的配置.今天我们详细分析下二级缓存以及为什么不建议使用二级缓存. ...
- mybatis精讲(七)--动态sql
目录 常用标签 if元素 choose元素 trim元素 forearch bind元素 在我们传统的开发中我们会通过拼接sql达到数据库的操作.java中的拼接不仅效率低下而且代码很长不易维护.而M ...
- 第三百七十节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索结果分页
第三百七十节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索结果分页 逻辑处理函数 计算搜索耗时 在开始搜索前:start_time ...
- 第三百六十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索功能
第三百六十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索功能 Django实现搜索功能 1.在Django配置搜索结果页的路由映 ...
- 第三百六十七节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)scrapy写入数据到elasticsearch中
第三百六十七节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)scrapy写入数据到elasticsearch中 前面我们讲到的elasticsearch( ...
随机推荐
- 玩转 RTC时钟库 DS3231
1.前言 接着博主的上一篇 玩转 RTC时钟库 + DS1302,这一篇我们重点讲解DS3231时钟模块.没有看过上一篇的同学,麻烦先去阅读一下,因为很多理论基础已经在上一篇做了详细讲解,这里 ...
- 面试题-javascript-面向对象编程
笔者在某次笔试中遇到这个题:印象很深. function ClassA() { var value=4; this.getValue= function() { return value; } thi ...
- 谷歌黑客语法(google hacking)让你的搜索更精准有效
Google Hacking的含义原指利用Google Google搜索引擎搜索信息来进行入侵的技术和行为: 现指利用各种搜索引擎搜索信息来进行入侵的技术和行为,但我们也可以利用这个在互联网上更加便捷 ...
- Java 干货之深入理解String
可以证明,字符串操作是计算机程序设计中最常见的行为,尤其是在Java大展拳脚的Web系统中更是如此. ---<Thinking in Java> 提到Java中的String,总是有说不完 ...
- Lab_1:练习3——分析bootloader进入保护模式的过程
文章链接:https://www.cnblogs.com/cyx-b/p/11809742.html 作者:chuyaoxin 一.实验内容 BIOS将通过读取硬盘主引导扇区到内存,并转跳到对应内存中 ...
- NOIP模拟34
考试的时候被T2卡了一年....考虑了一下正解的式子,然后没去给左边分解因数,去给后面乘倍数...理论复杂度O(n^2),实际好像卡不掉的样子.但是由于我智障的打了一棵主席树,他M了.... 预计得分 ...
- 腾讯新闻构建高性能的 react 同构直出方案
在腾讯新闻抢金达人活动 node 同构直出渲染方案的总结文章中我们整体了解了下同构直出渲染方案在我们项目中的使用.正如我在上篇文章结尾所说的: 应用型技术的难点不是在克服技术问题,而是在于能够不断的结 ...
- js内容溢出用省略号(...)表示
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 考试T1护花
传送门 这题的提议似乎有什么问题,只要约翰选好了要抓那头牛,他就不会吃草了,站在原地傻等? 这题就是贪心,但在用cmp中比较单位时间吃草数量时,要用double型,不然可能会有点一样... 还有就是主 ...
- Python基本数据结构之集合
一道python面试的一个小问题,说怎么使用一行代码将一个列表里的重复元素,其实这里只要将列表转换成集合就可以了. 定义 集合跟我们学的列表有点像,也是可以存一堆数据,不过它有几个独特的特点,令其在整 ...