当前位置: 首页 > 后端技术 > Java

详细讲解MyBatis类型处理器,让你的代码更优雅!

时间:2023-04-01 17:59:17 Java

来源:https://www.cnblogs.com/zwwhn...本文主要讲解MyBatis中类型处理器的使用方法。1.明确需求在设计之初,sys_role表的enabled字段有2个可选值,其中0表示禁用,1表示启用,我们在实体类中使用Integer类型:/***effectiveflag*/privateIntegerenabled;publicIntegergetEnabled(){returnenabled;}publicvoidsetEnabled(Integerenabled){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{thrownewException("Invalidenabledvalue");}这种硬编码的方法不仅看起来不友好,而且也不利于后期维护,如果维护了程序员脾气不好会骂你的,哈哈。所以我们的要求是拒绝硬编码,使用友好的编码方式来检查enabled字段的值是否有效。2.使用MyBatis提供的枚举类型处理器我们通常使用枚举来解决这种场景。首先新建一个com.zwwhnly.mybatisaction.type包,然后在包下新建一个枚举Enabled:packagecom.zwwhnly.mybatisaction.type;publicenumEnabled{/***disable*/disabled,/***enable*/enabled;}其中disabled对应的index为0,enabled对应的index为1,然后修改原来的enabled字段SysRole类中的整数类型为:/***有效标志*/privateEnabledenabled;publicEnabledgetEnabled(){returnenabled;}publicvoidsetEnabled(Enabledenabled){this.enabled=enabled;}此时,原始硬编码代码可以修改为:if(sysRole.getEnabled()==Enabled.disabled||sysRole.getEnabled()==Enabled.enabled)sysRole=sysRoleMapper.selectById(2L);Assert.assertEquals(Enabled.disabled,sysRole.getEnabled());}else{thrownewException("Invalidenabledvalue");}上面的代码虽然完美解决了硬编码的问题,但是这次又引出了新的问题:数据库无法识别Enabled枚举类型。添加、更新或作为查询条件时,需要将枚举值转换为数据库中的int类型。查询数据时,需要将数据库的int类型值转换为Enabled枚举类型。考虑到这个问题,我们在SysRoleMapperTest测试类中添加如下测试方法:@TestpublicvoidtestUpdateById(){SqlSessionsqlSession=getSqlSession();尝试{SysRoleMappersysRoleMapper=sqlSession.getMapper(SysRoleMapper.class);//先查询id=2,然后修改role的enabled值为disabledSysRolesysRole=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{thrownewException("无效的启用值");}}catch(Exceptione){e.printStackTrace();}最后{sqlSession.close();}}运行测试代码,发现抛出如下异常:Errorqueryingdatabase。原因:org.apache.ibatis.executor.result.ResultMapException:尝试从结果集中获取“已启用”列时出错。Cause:java.lang.IllegalArgumentException:Noenumconstantcom.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中添加如下配置:type.enabled"/>再次运行测试代码,测试通过,输出日志如下:DEBUG[main]-==>Preparing:SELECTid,role_name,enabled,create_by,create_timeFROMsys_roleWHEREid=?DEBUG[main]-==>Parameters:2(Long)TRACE[main]-<==Columns:id,role_name,enabled,create_by,create_timeTRACE[main]-<==Row:2,普通用户,1,1,2019-06-2718:21:12.0DEBUG[main]-<==Total:1DEBUG[main]-==>准备:UPDATEsys_roleSETrole_name=?,enabled=?,create_by=?,创建_时间=?WHEREid=?DEBUG[main]-==>Parameters:Normaluser(String),0(Integer),1(Long),2019-06-2718: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。类型。EnumOrdinalTypeHandler都不能满足我们的需求。在这种情况下,我们需要自己实现类型处理程序。首先修改枚举类Enabled代码:packagecom.zwwhnly.mybatisaction.type;publicenumEnabled{/***enable*/enabled(1),/***disable*/disabled(0);私有最终int值;privateEnabled(intvalue){this.value=value;}publicintgetValue(){返回值;然后在com.zwwhnly.mybatisaction.type包下新建一个类型处理器EnabledTypeHandler:packagecom.zwwhnly.mybatisaction。类型;导入org.apache.ibatis.type.JdbcType;导入org.apache.ibatis.type.TypeHandler;导入java.sql.CallableStatement;导入java.sql.PreparedStatement;导入java.sql.ResultSet;导入java.sql。SQLException;importjava.util.HashMap;importjava.util.Map;/***启用类型处理器*/publicclassEnabledTypeHandlerimplementsTypeHandler{privatefinalMapenabledMap=newHashMap();publicEnabledTypeHandler(){for(Enabledenabled:Enabled.values()){enabledMap.put(enabled.getValue(),已启用);}}@OverridepublicvoidsetParameter(PreparedStatementpreparedStatement,inti,Enabledenabled,JdbcTypejdbcType)throwsSQLException{preparedStatement.setInt(i,enabled.getValue());}@OverridepublicEnabledgetResult(ResultSetresultSet,Strings)throwsSQLException{整数值=resultSet.getInt(s);返回enabledMap.get(value);}@OverridepublicEnabledgetResult(ResultSetresultSet,inti)throwsSQLException{Integervalue=resultSet.getInt(i);返回enabledMap.get(value);}@OverridepublicEnabledgetResult(CallableStatementcallableStatement,inti)throwsSQLException{Integervalue=callableStatement.getInt(i);返回enabledMap.get(value);}}自定义类型处理器实现TypeHandler接口,重写接口中的4个方法,在无参构造函数中遍历枚举类型Enabled,并为字段enabledMap赋值如果要使用自定义类型处理器,还需要在resources/mybatis-config.xml中添加如下配置:运行测试代码,输出日志和上面的输出日志一样,这里不再赘述。近期热点文章推荐:1.1000+Java面试题及答案(2022最新版)2.厉害了!Java协程来了。..3.SpringBoot2.x教程,太全面了!4.不要用爆破爆满画面,试试装饰者模式,这才是优雅的方式!!5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!