MyBatis系列(十四):在MyBatis中使用类型处理器()

  本篇文章为你整理了MyBatis系列(十四):在MyBatis中使用类型处理器()的详细内容,包含有 MyBatis系列(十四):在MyBatis中使用类型处理器,希望能帮助你了解 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值为disabled

   SysRole sysRole = sysRoleMapper.selectById(2L);

   Assert.assertEquals(Enabled.enabled, sysRole.getEnabled());

   // 修改角色的enabled为disabled

   sysRole.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();

  

 

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

  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_time

  TRACE [main] - == Row: 2, 普通用户, 1, 1, 2019-06-27 18:21:12.0

  DEBUG [main] - == Total: 1

  DEBUG [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.EnumTypeHandler和org.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);

   @Override

   public void setParameter(PreparedStatement preparedStatement, int i, Enabled enabled, JdbcType jdbcType) throws SQLException {

   preparedStatement.setInt(i, enabled.getValue());

   @Override

   public Enabled getResult(ResultSet resultSet, String s) throws SQLException {

   Integer value = resultSet.getInt(s);

   return enabledMap.get(value);

   @Override

   public Enabled getResult(ResultSet resultSet, int i) throws SQLException {

   Integer value = resultSet.getInt(i);

   return enabledMap.get(value);

   @Override

   public 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

  

 

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

  4. 源码及参考

  源码地址:https://github.com/zwwhnly/mybatis-action.git,欢迎下载。

  刘增辉《MyBatis从入门到精通》

  原创不易,如果觉得文章能学到东西的话,欢迎点个赞、评个论、关个注,这是我坚持写作的最大动力。

  如果有兴趣,欢迎添加我的微信:zwwhnly,等你来聊技术、职场、工作等话题(PS:我是一名奋斗在上海的程序员)。

  以上就是MyBatis系列(十四):在MyBatis中使用类型处理器()的详细内容,想要了解更多 MyBatis系列(十四):在MyBatis中使用类型处理器的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: