对mybatis的Handler 从使用角度介绍
最近在开发中,涉及到了讲数据库查询的类型,直接转为java需要的类型。 由于对handler 理解不到位 和 使用不当。躺了一些坑。
主要涉及的有2种。
1、varchar 转 List<T>
2、varchar 转Map<T>
如图是写的两个handler。
ListTypeHandler 为了保证 handler的通用性,采取了 将mybatis xml 配置中的type,传入 ListTypeHandler 中直接使用。 后来发现这是个大坑。
public class ListTypeHandler<E> extends BaseTypeHandler<List<E>> {
private Class<E> type;
public ListTypeHandler(Class<E> type) {
if (type == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
this.type = type;
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<E> parameter, JdbcType jdbcType) throws SQLException {
String x = JSON.toJSONString(parameter);
ps.setString(i, x);
}
@Override
public List<E> getNullableResult(ResultSet rs, String columnName) throws SQLException {
String s = rs.getString(columnName);
return StringUtils.isBlank(s) ? null : JSON.parseArray(s, type);
}
@Override
public List<E> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String s = rs.getString(columnIndex);
return StringUtils.isBlank(s) ? null : JSON.parseArray(s, type);
}
@Override
public List<E> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String s = cs.getString(columnIndex);
return StringUtils.isBlank(s) ? null : JSON.parseArray(s, type);
}
}
public class MapTypeHandler extends BaseTypeHandler<Map<String, Object>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Map<String, Object> parameter, JdbcType jdbcType) throws SQLException {
if(MapUtils.isNotEmpty(parameter)) {
String x = JSON.toJSONString(parameter);
ps.setString(i, x);
}else{
ps.setString(i, null);
}
}
@Override
public Map<String, Object> getNullableResult(ResultSet rs, String columnName) throws SQLException {
String s = rs.getString(columnName);
return StringUtils.isBlank(s) ? null : JSON.parseObject(s, new TypeReference<Map<String, Object>>(){}); // JSON.parseObject(s, getRawType());
}
@Override
public Map<String, Object> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String s = rs.getString(columnIndex);
return StringUtils.isBlank(s) ? null : JSON.parseObject(s, new TypeReference<Map<String, Object>>(){});
}
@Override
public Map<String, Object> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String s = cs.getString(columnIndex);
return StringUtils.isBlank(s) ? null : JSON.parseObject(s, new TypeReference<Map<String, Object>>(){});
}
}
首先没有在mybatis.xml 总注册,直接通过@result指定使用
@Select("<script>SELECT " + SELECT_FILEDS_AS + " FROM " + TABLE + " WHERE valid =1 and config_id = #{configId} " + SELECT_LIMIT + " </script>")
@Results(value={
@Result(column="operation_content", property="operationContent", javaType=String.class, jdbcType=JdbcType.VARCHAR,typeHandler=ListTypeHandler.class),
})
List<OperateRecord> selectList(@Param("configId") long configId,@Param("offset") int offset,@Param("limit") int limit);
由于希望 ListTypeHandler 可以通用一点,因此采用了传入的javaType 即String,使用, 这个时候查询也没问题。感觉还很完美。
接下来,开始写插入
@Insert({"INSERT INTO " + TABLE + " (config_id, operation_staff, operation_time, action, operation_content, ctime,valid) values "
+"( #{configId}, #{operationStaff}, #{operationTime}, #{action}, #{operationContent, javaType=String, jdbcType=VARCHAR,typeHandler=ListTypeHandler}, unix_timestamp(),1 )"})
int insert(OperateRecord record);
这个时候就开始各种报错,最后经过一顿百度,发现是没有注册,于是增加注册。
<typeHandlers>
<typeHandler handler="com.support.ListTypeHandler" javaType="List" jdbcType="VARCHAR" />
</typeHandlers>
这个时候,在插入,发现成功了。 这个时候,认为全部搞定了,开始部署线下,进行联调。结果最大的问题才刚刚开始。
后头测试查询的时候,发现查询又报错。。。 于是开始debug,发现 'name' 类型varchar,java类型 String。 也开始进入list转换。 一脸懵逼。
于是尝试性的去掉字段的别名,发现居然成功了。。。
然后开始进入另一个大坑。认为和别名有关。
进入下一步的尝试
@Result(column = "initiateName" ,property = "initiateName")
为字段指定result,发现问题完美解决。
这个时候,任务只要@Results(value={}),使用过handler的,其他字段就也要指定。
这个时候,终于认为大功告成,结果。。。。
测试另一个dao的时候,发现,这个dao完全没有使用handler, 查询结果中的字段,也会去转换。。
然后,又开始懵逼。。。 一顿百度,最终恍然大悟。 再mybatisxml配置之后,是全局匹配。
因为不能使用传入的java类型, 再listhandler写死。
结论:
1.查询时候,不需要注册,即可直接通过result使用。type指定也可以生效。
2.插入的时候必须注册。
3.注册后,通过java,jdbc类型,还有名字全局匹配
4.result中可以不写,自动匹配
对mybatis的Handler 从使用角度介绍的更多相关文章
- MyBatis 3.5.2 新特性介绍
1.MyBatis 最新版本 3.5.2 发布 MyBatis最新版本是:3.5.2,发布时间是:2019年7月15日 2.MyBatis 3.5.2 新特征介绍 我们知道,MyBatis 是支持定制 ...
- MyBatis常用对象SqlSessionFactory和SqlSession介绍和运用
学习框架一个比较好的路径阅读源码.本文介绍的SqlSessionFactory和SqlSession.可以通过了解SqlSessionFactory接口和SqlSession接口以及两个的实现类入手, ...
- MyBatis执行流程的各阶段介绍
目录 一.mybatis极简示例 1.1 创建mybatis配置文件 1.2 创建数据库表 1.3 创建javabean 1.4 创建mapper映射文件 1.5 运行测试 二.mybatis的几大“ ...
- Android Bundle、Handler和Message类介绍
Bundle是一个载体,可以存放基本数据类型.对象等内容,相当于一辆汽车,可以装载很多东西,然后运到需要的地方,例如: Bundle mBundle=new Bundle(); mBundle.put ...
- Handler的简单使用介绍
Handler在android程序开发中使用的非常频繁.我们知道android是不允许在子线程中更新UI的,这就需要借助Handler来实现,那么你是否想过为什么一定要这个这样子做呢?而且Handle ...
- mybatis学习(十)——缓存介绍
与Hibernate一样,MyBatis 也提供了一级缓存和二级缓存的支持. 1.一级缓存:(本地缓存)SqlSession级别的缓存,默认一直开启的 , 与数据库同一次会话期间的数据会放到本地缓存中 ...
- Mybatis逆向工程文件标签的详细介绍:
?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUB ...
- Mybatis核心配置文件中的标签介绍
0. 标签顺序 Mybatis核心配置文件中有很多标签,它们谁谁写在前写在后其实是有顺序要求的: 从前到后: properties?,settings?,typeAliases?,typeHandle ...
- Mybatis(二):Mybatis的映射文件sqlmapper详解
MyBatis 真正的力量是在映射语句中.这里是奇迹发生的地方.对于所有的力量,SQL 映射的 XML 文件是相当的简单.当然如果你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大约 ...
随机推荐
- 关于JDBC学习过程中的注意事项(分享自己犯过的错误,写给初学JDBC的小伙伴的八条建议)
关于JDBC学习过程中的注意事项(分享自己犯过的错误,写给初学JDBC的小伙伴的八条建议) 前言:最近在学习JDBC,总结了几个小问题,特地分享给大家,让大家不要犯这样的错误,也希望大家养成学会总结的 ...
- 关于 mysql2 -v '0.3.21'(CentOS7.3)
个人由于没有安装mysql而是装的MariaDB,所以网上说安装mysql,故没有采用,经查阅资料后,详细情况如下: Gem时报错: [root@localhost ~]# gem install m ...
- java中存储mysql数据库时间类型
Mysql 与 java 的时间类型 MySql的时间类型有 Java中与之对应的时间类型 date java.sql.Date Datetime ...
- Xshell连接Linux慢问题解决办法
由于各种原因,经常更换网络环境,然后发现,每次更换网络环境后,xshell连接虚拟机的rhel或者CentOS都几乎是龟速.... 今天专门查了一下解决方案: 原来是ssh的服务端在连接时会自动检测d ...
- Bootstrap3基础 栅格系统 标尺(col-lg/md/sm/xs-1)
内容 参数 OS Windows 10 x64 browser Firefox 65.0.2 framework Bootstrap 3.3.7 editor ...
- The application to execute does not exist: 'C:\Users\Administrator\.dotnet\tools\.store\dotnet-aspnet-codegenerator\2.2.0-rtm-35687\dotnet-aspnet-codegenerator\2.2.0-rtm-35687\tools\netcoreapp2.1\any\
vs code mvc搭建基架执行命令操作出现的问题解决方式重新复制拷贝一份2.2.0命名为2.2.0-rtm-35687, 修改
- react生命周期和组件生命周期
React的组件在第一次挂在的时候首先获取父组件传递的props,接着获取初始的state值,接着经历挂载阶段的三个生命周期函数,也就是ComponentWillMount,render,Compon ...
- Undefined、Null区别渗透
Undefined 类型表示未定义,它的类型只有一个值,就是 undefined.任何变量在赋值前是 Undefined 类型.值为 undefined,一般我们可以用全局变量 undefined(就 ...
- 比原链(Bytom)先知节点 Ubuntu接入文档
系统要求 我们建议选择知名的VPS服务商,运行比原链节点对算力没有要求,但是请配置尽可能大的磁盘空间. 节点服务器最小配置: 操作系统: Windows/Linux/Docker CPU: 2核 内存 ...
- 面试被问之-----sql优化中in与exists的区别
曾经一次去面试,被问及in与exists的区别,记得当时是这么回答的:''in后面接子查询或者(xx,xx,xx,,,),exists后面需要一个true或者false的结果",当然这么说也 ...