最近在开发中,涉及到了讲数据库查询的类型,直接转为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 从使用角度介绍的更多相关文章

  1. MyBatis 3.5.2 新特性介绍

    1.MyBatis 最新版本 3.5.2 发布 MyBatis最新版本是:3.5.2,发布时间是:2019年7月15日 2.MyBatis 3.5.2 新特征介绍 我们知道,MyBatis 是支持定制 ...

  2. MyBatis常用对象SqlSessionFactory和SqlSession介绍和运用

    学习框架一个比较好的路径阅读源码.本文介绍的SqlSessionFactory和SqlSession.可以通过了解SqlSessionFactory接口和SqlSession接口以及两个的实现类入手, ...

  3. MyBatis执行流程的各阶段介绍

    目录 一.mybatis极简示例 1.1 创建mybatis配置文件 1.2 创建数据库表 1.3 创建javabean 1.4 创建mapper映射文件 1.5 运行测试 二.mybatis的几大“ ...

  4. Android Bundle、Handler和Message类介绍

    Bundle是一个载体,可以存放基本数据类型.对象等内容,相当于一辆汽车,可以装载很多东西,然后运到需要的地方,例如: Bundle mBundle=new Bundle(); mBundle.put ...

  5. Handler的简单使用介绍

    Handler在android程序开发中使用的非常频繁.我们知道android是不允许在子线程中更新UI的,这就需要借助Handler来实现,那么你是否想过为什么一定要这个这样子做呢?而且Handle ...

  6. mybatis学习(十)——缓存介绍

    与Hibernate一样,MyBatis 也提供了一级缓存和二级缓存的支持. 1.一级缓存:(本地缓存)SqlSession级别的缓存,默认一直开启的 , 与数据库同一次会话期间的数据会放到本地缓存中 ...

  7. Mybatis逆向工程文件标签的详细介绍:

    ?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUB ...

  8. Mybatis核心配置文件中的标签介绍

    0. 标签顺序 Mybatis核心配置文件中有很多标签,它们谁谁写在前写在后其实是有顺序要求的: 从前到后: properties?,settings?,typeAliases?,typeHandle ...

  9. Mybatis(二):Mybatis的映射文件sqlmapper详解

    MyBatis 真正的力量是在映射语句中.这里是奇迹发生的地方.对于所有的力量,SQL 映射的 XML 文件是相当的简单.当然如果你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大约 ...

随机推荐

  1. Django框架详细介绍---Form表单

    一.概述 在HTML页面中,利用form表单向后端提交数据时,需要编写input等输入标签并用form标签包裹起来,与此同时,在很多应用场景之下需要对用户输入的数据校验,例如注册登录页面中,校验用户注 ...

  2. selenium webdriver报错 ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。

    昨天跑的好好的代码,今天突然报错: ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接. 调查一下,原来是Chrome自动升级,而chrom ...

  3. tab切换的效果——仿照今日头条APP的切换效果

    说点废话;不知道是哪一版本起头条的tab切换效果就变了,一直琢磨着这个事,去度娘那里也没有什么结果:正好这两天有空就尝试做了一下:用前端的技术来实现: 先看效果吧:上面的tab随着slide滑动,上面 ...

  4. jenkins构建任务后发送邮件

    1.jenkins登录后-系统管理-系统设置打开后定位到下面的位置:系统管理员邮件地址一定要填写 2.下滑页面定位到extend E-mail Notification:这个是jenkins的一个插件 ...

  5. Jupyter Notebooks 是数据科学/机器学习社区内一款非常流行的工具

    Jupyter Notebooks 是数据科学/机器学习社区内一款非常流行的工具.Jupyter Notebooks 允许数据科学家创建和共享他们的文档,从代码到全面的报告都可以.李笑来 相当于拿他来 ...

  6. window.location.replace和window.location.href的区别

    简单说说:有3个jsp页面(1.jsp,  2.jsp,  3.jsp). 进系统默认的是1.jsp ,当我进入2.jsp的时候, 2.jsp里面用window.location.replace(&q ...

  7. 微信小程序数组对象

    xml:<block wx:for="{{post_key}}" wx:for-item="{{item}}"></block> dat ...

  8. 堆排序 P1090 合并果子

    P1090 合并果子 本题要用到堆 一个小根堆 每次取出两堆,合并成一堆,为了让多多花费体力最少,我们要尽量少的重复大堆的合并,因此每次合并完以后,要把新的一坨放到堆里排一排,维护一个堆 有必要强调一 ...

  9. JS,JQuery小知识

    http://blog.163.com/wumingli456@126/blog/static/28896414201112252456459/?suggestedreading&wumii

  10. 关于IIS的4月26日笔记

    常用命令: 31. regedit.exe----注册表 48. msconfig.exe---系统配置实用程序  80. services.msc---本地服务设置 93. regedit.exe- ...