mybatis更新时间字段_你以为把Mybatis型处理器了解了,就不会“暴雷”了!

1. 明确需求

在设计之初,sys_role表的enabled字段有2个可选值,其中0 代表禁用,1代表启用,而且实体类中我们使用的是Interger类型:

/*** 有效标志*/
private Integer enabled;public Integer getEnabled() {return enabled;
}public void setEnabled(Integer enabled) {this.enabled = enabled;
}

如果要新增或者更新角色信息,我们肯定要校验enabled字段的值必须是0或者1,所以最初的部分代码可能是这样的:

if (sysRole.getEnabled() == 0 || sysRole.getEnabled() == 1) {sysRoleMapper.updateById(sysRole);sysRole = sysRoleMapper.selectById(2L);Assert.assertEquals(0, sysRole.getEnabled());
} else {throw new Exception("无效的enabled值");
}

这种硬编码的方式不仅看起来不友好,而且不利于后期维护,如果维护的程序员脾气不好,还会骂你,哈哈。

所以我们的需求就是,拒绝硬编码,使用友好的编码方式来校验enabled字段的值是否有效。

2. 使用MyBatis提供的枚举类型处理器

我们通常会使用枚举来解决这种场景。

首先新建com.zwwhnly.mybatisaction.type包,然后在该包下新建枚举Enabled:

package com.zwwhnly.mybatisaction.type;public enum Enabled {/*** 禁用*/disabled,/*** 启用*/enabled;
}

其中,disabled对应的索引为0,enabled对应的索引为1。

然后将SysRole类中原来为Integer类型的enabled字段修改为:

/*** 有效标志*/
private Enabled enabled;public Enabled getEnabled() {return enabled;
}public void setEnabled(Enabled enabled) {this.enabled = enabled;
}

此时原本硬编码的代码就可以修改为:

if (sysRole.getEnabled() == Enabled.disabled || sysRole.getEnabled() == Enabled.enabled) {sysRoleMapper.updateById(sysRole);sysRole = sysRoleMapper.selectById(2L);Assert.assertEquals(Enabled.disabled, sysRole.getEnabled());
} else {throw new Exception("无效的enabled值");
}

虽然上面的代码很完美的解决了硬编码的问题,但此时又引出一个新的问题:

数据库并不能识别Enabled枚举类型,在新增,更新或者作为查询条件时,需要将枚举值转换为数据库中的int类型,在查询数据时,需要将数据库的int类型的值转换为Enabled枚举类型。

带着这个问题,我们在SysRoleMapperTest测试类中添加如下测试方法:

@Test
public void testUpdateById() {SqlSession sqlSession = getSqlSession();try {SysRoleMapper sysRoleMapper = sqlSession.getMapper(SysRoleMapper.class);// 先查询出id=2的角色,然后修改角色的enabled值为disabledSysRole sysRole = sysRoleMapper.selectById(2L);Assert.assertEquals(Enabled.enabled, sysRole.getEnabled());// 修改角色的enabled为disabledsysRole.setEnabled(Enabled.disabled);if (sysRole.getEnabled() == Enabled.disabled || sysRole.getEnabled() == Enabled.enabled) {sysRoleMapper.updateById(sysRole);sysRole = sysRoleMapper.selectById(2L);Assert.assertEquals(Enabled.disabled, sysRole.getEnabled());} else {throw new Exception("无效的enabled值");}} catch (Exception e) {e.printStackTrace();} finally {sqlSession.close();}
}

运行测试代码,发现抛出如下异常:

d69eb32c4fe060369c1fbbeed24093ff.png
Error querying database. Cause: org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'enabled' from result set. Cause: java.lang.IllegalArgumentException: No enum constant com.zwwhnly.mybatisaction.type.Enabled.1

这是因为MyBatis在处理Java类型和数据库类型时,使用TypeHandler(类型处理器)对这两者进行转换。

MyBatis为Java类型和数据库JDBC中的常用类型类型提供了TypeHandler接口的实现。

MyBatis在启动时会加载所有的JDBC对应的类型处理器,在处理枚举类型时默认使用org.apache.ibatis.type.EnumTypeHandler处理器,这个处理器会将枚举类型转换为字符串类型的字面值使用,对于Enabled枚举来说,就是“disabled"和”enabled"字符串。

而数据库中enabled字段的类型是int,所以在查询到角色信息将int类型的值1转换为Enabled类型报错。

那么如何解决这个问题呢?

MyBatis还提供了另一个枚举处理器:org.apache.ibatis.type.EnumOrdinalTypeHandler,这个处理器使用枚举的索引进行处理,可以解决此处转换报错的问题。

使用这个处理器,需要在之前的resources/mybatis-config.xml中添加如下配置:

<typeHandlers><typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"javaType="com.zwwhnly.mybatisaction.type.Enabled"/>
</typeHandlers>

再次运行测试代码,测试通过,输出日志如下:

DEBUG [main] - ==> Preparing: SELECT id,role_name,enabled,create_by,create_time FROM sys_role WHERE id = ?DEBUG [main] - ==> Parameters: 2(Long)TRACE [main] - <== Columns: id, role_name, enabled, create_by, create_timeTRACE [main] - <== Row: 2, 普通用户, 1, 1, 2019-06-27 18:21:12.0DEBUG [main] - <== Total: 1DEBUG [main] - ==> Preparing: UPDATE sys_role SET role_name = ?,enabled = ?,create_by=?, create_time=? WHERE id=?DEBUG [main] - ==> Parameters: 普通用户(String), 0(Integer), 1(Long), 2019-06-27 18:21:12.0(Timestamp), 2(Long)DEBUG [main] - <== Updates: 1

从日志中可以看出,在查询角色信息时,MyBatis将1转换为了Enabled.enabled,在更新角色信息时,MyBatis将Enabled.disabled转换为了0。

3. 使用自定义的类型处理器

假设enabled字段的值既不是枚举的字面值,也不是枚举的索引值,此时org.apache.ibatis.type.EnumTypeHandlerorg.apache.ibatis.type.EnumOrdinalTypeHandler都不能满足我们的需求,这种情况下我们就需要自己来实现类型处理器了。

首先修改下枚举类Enabled代码:

package com.zwwhnly.mybatisaction.type;public enum Enabled {/*** 启用*/enabled(1),/*** 禁用*/disabled(0);private final int value;private Enabled(int value) {this.value = value;}public int getValue() {return value;}
}

然后在com.zwwhnly.mybatisaction.type包下新建类型处理器EnabledTypeHandler:

package com.zwwhnly.mybatisaction.type;import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;/*** Enabled类型处理器*/
public class EnabledTypeHandler implements TypeHandler<Enabled> {private final Map<Integer, Enabled> enabledMap = new HashMap<Integer, Enabled>();public EnabledTypeHandler() {for (Enabled enabled : Enabled.values()) {enabledMap.put(enabled.getValue(), enabled);}}@Overridepublic void setParameter(PreparedStatement preparedStatement, int i, Enabled enabled, JdbcType jdbcType) throws SQLException {preparedStatement.setInt(i, enabled.getValue());}@Overridepublic Enabled getResult(ResultSet resultSet, String s) throws SQLException {Integer value = resultSet.getInt(s);return enabledMap.get(value);}@Overridepublic Enabled getResult(ResultSet resultSet, int i) throws SQLException {Integer value = resultSet.getInt(i);return enabledMap.get(value);}@Overridepublic Enabled getResult(CallableStatement callableStatement, int i) throws SQLException {Integer value = callableStatement.getInt(i);return enabledMap.get(value);}
}

自定义类型处理器实现了TypeHandler接口,重写了接口中的4个方法,并且在无参构造函数中遍历了枚举类型Enabled并对字段enabledMap进行了赋值。

想要使用自定义的类型处理器,也需要在resources/mybatis-config.xml中添加如下配置:

<typeHandlers><!--其他配置--><typeHandler handler="com.zwwhnly.mybatisaction.type.EnabledTypeHandler"javaType="com.zwwhnly.mybatisaction.type.Enabled"/>
</typeHandlers>

运行测试代码,输出日志和上面的输出日志一样,这里不再重复贴出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558384.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

filter函数使用出现的问题

需求&#xff1a; 需要在筛选框中&#xff0c;输入筛选条件&#xff0c;筛选出当前列表中符合的数据。 indexList&#xff1a;[] 是数组存储的数据e是获取输入框中的值 query(e){this.indexListthis.indexList.filter(function (item) {return item.goodsname.indexOf(e) ! -…

python根据模板生成pdf文件_程序生成word与PDF文档的方法(python)

程序导出word文档的方法 将web/html内容导出为world文档&#xff0c;再java中有很多解决方案&#xff0c;比如使用Jacob、Apache POI、Java2Word、iText等各种方式&#xff0c;以及使用freemarker这样的模板引擎这样的方式。php中也有一些相应的方法&#xff0c;但在python中将…

js将object转化为json数据,json数据转js对象

json数据转js对象: JSON.parse(); js对象转json数据: JSON.stringify();

本地更新github项目_GitHub开源项目2019-03-29更新精选

1.etcd&#xff1a;一个高可用的分布式键值数据库&#xff0c;k8s 全家桶标配的注册与发现服务etcd&#xff1a;一个高可用的分布式键值数据库&#xff0c;k8s 全家桶标配的注册与发现服务。它采用 raft 一致性算法&#xff0c;基于 Go 语言实现。可以通过该项目了解、学习 raf…

js中for循环调用回调函数,一直循环最后一个

js的for循环中使用回调函数&#xff0c;获取到的值总是最后一个值&#xff1f;_MLAY-CSDN博客_js 循环回调函数

maven default aliyun_大家看看大佬对Maven仓库的讲解,有何高明之处?

概念Maven在某个统一的位置存储所有项目的共享的构件&#xff0c;这个统一的位置&#xff0c;我们就称之为仓库。(仓库就是存放依赖和插件的地方)。分类maven的仓库只有两大类&#xff1a;1.本地仓库 2.远程仓库&#xff0c;在远程仓库中又分成了3种&#xff1a;中央仓库、 私服…

形参和实参的区别

形参就是函数声明时的变量&#xff0c;实参是我们调用该函数时传入的具体参数。 function function(a,b){ console.log(a,b) }function(1,2) 这里1&#xff0c;2就是实参 a,b是形参

JAVA八种基本类型

基本类型(primitive types), 共有8种&#xff0c;即int, short, long, byte, float, double, boolean, char(注意&#xff0c;并没有string的基本类型)

计算差分方程的收敛点_数值计算(五十九)热传导方程组的差分数值求解

1 问题描述Chenglin Li&#xff1a;数值计算&#xff08;三&#xff09;matlab求解一般的偏微分方程组​zhuanlan.zhihu.com因为给出的边界条件包含导数&#xff0c;因此需要同时考虑前向差分和后向差分&#xff1b;遍历循环&#xff0c;先计算每个坐标的时间节点&#xff0c;或…

python树莓派编程_python树莓派编程

广告关闭 腾讯云11.11云上盛惠 &#xff0c;精选热门产品助力上云&#xff0c;云服务器首年88元起&#xff0c;买的越多返的越多&#xff0c;最高返5000元&#xff01;例如&#xff0c;你可以用树莓派搭建你自己的家用云存储服务器。? 树莓派用python来进行编程。 树莓派项目的…

Java 引用类型变量的声明和使用

引用类型变量的声明和使用 (1)把类名当作是一种类型来声明变量&#xff0c;这种变量叫引用类型变量。如&#xff1a;People people; (2)引用类型变量保存对象的“引用”&#xff0c;即对象的地址。 (3)对象的创建  new 类名()  如&#xff1a;new People(); (4)new创建对象后…

se是什么职位_女皇大学PSE&SE 独家解析!

坐落于圣劳伦斯河畔的女皇大学成立于1841年&#xff0c;至今已经有178年的历史了。作为加拿大传统的四大名校“Old Four”之一&#xff0c;女王大学一直以来在学术成就&#xff08;常年位列麦考林排名医博类前5&#xff09;&#xff0c;学生满意度&#xff08;麦考林排名医博类…

js中new操作符

1.什么是new? 在JS中&#xff0c;new的作用是通过构造函数来创建一个实例对象&#xff08;和普通函数不一样&#xff0c;当函数用作构造函数时&#xff0c;首字母一般要大写&#xff09; function Foo(name) {this.name name; } console.log("new Foo(mm)的类型&#…

charles 安装 ssl_「从零开始Python爬虫」1.7.1 Charles的安装与配置

Charles的安装Charles是一个网络抓包工具&#xff0c;相比Fiddler&#xff0c;其功能更为强大&#xff0c;而且跨平台支持得更好&#xff0c;所以这里选用它来作为主要的移动端抓包工具。相关链接官方网站&#xff1a;https://www.charlesproxy.com下载链接&#xff1a;https:/…

Git创建本地分支并提交到远程仓库

1.建立本地仓库 查看当前项目根目录中有没有 .git文件&#xff08;隐藏文件&#xff09;&#xff0c;如果没有&#xff0c;右键->Git bash here &#xff0c;然后输入命令git init建立本地仓库 git init 2.将代码提交到本地仓库 git add git commit -m "new branch…

python删除一个文件_Python 实现一个小功能: 删除某路径下文件及文件夹的脚本...

下面是编程之家 jb51.cc 通过网络收集整理的代码片段。 编程之家小编现在分享给大家&#xff0c;也给大家做个参考。 #!/usr/bin/env python import os import shutil delList [] delDir "/home/test" delList os.listdir(delDir ) for f in delList: filePath o…

uniapp防抖操作

1.新建common文件并创建common.js文件 // 防止处理多次点击function noMultipleClicks(methods, info) {// methods是需要点击后需要执行的函数&#xff0c; info是点击需要传的参数let that this;if (that.noClick) {// 第一次点击that.noClick false;if(info && inf…

JS去除字符串去除最后的逗号

let str"1,2,3,"str str.substring(0, str.lastIndexOf(,));

一个div 上下两行_web前端工程师如何理解 CSS 布局和块级格式化上下文

CSS是web前端中的重要内容&#xff0c;很多初学者在学习CSS时都会遇到各种各样的问题&#xff0c;今天就给大家分享web前端开发如何理解CSS不惧和块级格式化上下文。也许你从未听说过这个术语&#xff0c;但是如果你曾经用 CSS 做过布局&#xff0c;那么你也许知道它是什么。理…

什么函数是回调函数?

1.什么函数是回调函数&#xff1f; 1.你定义得 2.你没有调用 3.它最终执行了 2.常见的回调函数 1.dom事件操作函数 2.ajax请求回调函数 3.定时器回调函数 ......