最近工作中用到了mybatis的Java API方式进行开发,顺便也整理下该功能的用法,接下来会针对基本部分进行学习:
4)批量修改、批量查询、批量新增的用法。
Mybatis官网给了具体的文档,但是并没有对以上用法具体介绍,因此在这里整理下,以便以后工作用到时,可以参考。
本章主要使用Mybatis中使用typeHandlers进行对Enum进行转化的用法(本章将结合Spring自动注入《Spring(二十三):Spring自动注入的实现方式》),下边文章分为以下几个步骤:
本章将不再对maven项目的引入包,以及配置文件:jdbc.properties、mybatis-config.xml、spring-config.xml重复进行介绍,详情请参考上篇文件构建项目过程:《MyBatis(七):mybatis Java API编程实现增、删、改、查的用法》。
在开发过程中,我们往往会使用到枚举类型,因为使用枚举更可以穷举、开发起来方便、把所有可选值都定义在一起(比起使用数字代表更能避免出现BUG:数字标记规定一旦数字记错或者数字代表意义变化都会导致n多问题:带来bug、不易维护)。
因此枚举类型的出现给开发带来了不少好处:
什么时候使用枚举?
在实际开发中,入库时我们可以选择enum的code(int/smallint.tinyint)入库,也可以选择enum的name(varchar)入库。实际上往往code存入库的话,按照int来存储;name入库的话,按照varchar存储。读取的时候再进行转化按照库中的int值转化为enum,或者按照库中的varchar值转化为enum.
Enum的属性中包含两个字段:
弄清这点对后边分析一些现象会有帮助。
Mybatis中默认提供了两种Enum类型的handler:EnumTypeHandler和EnumOrdinalTypeHandler。
maven项目公用类如下:
maven项目中mapper类LogMapper.java
package com.dx.test.mapper; import org.apache.ibatis.annotations.InsertProvider; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Options; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import com.dx.test.mapper.sqlprovider.LogSqlProvider; import com.dx.test.model.Log; import com.dx.test.model.enums.ModuleType; import com.dx.test.model.enums.OperateType; @Mapper public interface LogMapper { /** * 入库日志 * * @param log 待入库实体 * @return 影响条数 */ @Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE, useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") @InsertProvider(type = LogSqlProvider.class, method = "insert") public int insert(Log log); /** * 根据文章id,查询日志详情 * * @param id 日志id * @return 返回查询到的日志详情 */ @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000) @Results(id = "logResult", value = { @Result(property = "id", column = "id", id = true), @Result(property = "title", column = "title"), @Result(property = "content", column = "content"), @Result(property = "moduleType", column = "module_type", javaType = ModuleType.class), @Result(property = "operateType", column = "operate_type", javaType = OperateType.class), @Result(property = "dataId", column = "data_id"), @Result(property = "createUser", column = "create_user"), @Result(property = "createUserId", column = "create_user_id"), @Result(property = "createTime", column = "create_time") }) @Select({ "select * from `log` where `id`=#{id}" }) Log getById(@Param("id") Long id); }
LogMapper生成sql的代理类LogSqlProvider.java
package com.dx.test.mapper.sqlprovider; import org.apache.ibatis.jdbc.SQL; import com.dx.test.model.Log; public class LogSqlProvider { /** * 生成插入日志SQL * @param log 日志实体 * @return 插入日志SQL * */ public String insert(Log log) { return new SQL() { { INSERT_INTO("log"); INTO_COLUMNS("title", "module_type", "operate_type","data_id", "content", "create_time","create_user","create_user_id"); INTO_VALUES("#{title}", "#{moduleType}", "#{operateType}","#{dataId}", "#{content}", "now()","#{createUser}","#{createUserId}"); } }.toString(); } }
Log实体类Log.java
package com.dx.test.model; import java.util.Date; import com.dx.test.model.enums.ModuleType; import com.dx.test.model.enums.OperateType; public class Log { private Long id; // 自增id private String title;// 日志msg private ModuleType moduleType;// 日志归属模块 private OperateType operateType; // 日志操作类型 private String dataId; // 操作数据id private String content; // 日志内容简介 private Date createTime; // 新增时间 private String createUser; // 新增人 private String createUserId; // 新增人id 。。。// getter setter @Override public String toString() { return "Log [id=" + id + ", title=" + title + ", moduleType=" + moduleType + ", operateType=" + operateType + ", dataId=" + dataId + ", content=" + content + ", createTime=" + createTime + ", createUser=" + createUser + ", createUserId=" + createUserId + "]"; } }
下面展开对Mybatis Java API中使用Enun的用法:
在不修改mybatis-config.xml和spring-config.xml配置文件(基于上一篇文章而言)的情况下,mybatis内部typeHandlers采用默认配置是:EnumTypeHandler,因此enum对应存储字段需要存储为varchar类型。
定义enum类型:ModuleType.java/OperateType.java
操作模块枚举MoudleType.java
package com.dx.test.model.enums; public enum ModuleType { Unkown("0:Unkown"), /** * 文章模块 */ Article_Module("1:Article_Module"), /** * 文章分类模块 **/ Article_Category_Module("2:Article_Category_Module"), /** * 配置模块 */ Settings_Module("3:Settings_Module"); private String value; ModuleType(String value) { this.value = value; } public String getValue() { return this.value; } }
操作类型枚举类OperateType.java
package com.dx.test.model.enums; public enum OperateType { /** * 如果0未占位,可能会出现错误。 * */ Unkown(0), /** * 新增 */ Create(1), /** * 修改 */ Modify(2), /** * 删除 */ Delete(3), /** * 查看 */ View(4), /** * 作废 */ UnUsed(5); private int value; OperateType(int value) { this.value = value; } public int getValue() { return this.value; } }
mydb中新建log表:
CREATE TABLE `log` ( `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT ‘自增id‘, `title` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ‘日志标题‘, `content` text CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT ‘日志内容‘, `module_type` varchar(32) NOT NULL COMMENT ‘记录模块类型‘, `operate_type` varchar(32) NOT NULL COMMENT ‘操作类型‘, `data_id` varchar(64) NOT NULL COMMENT ‘操作数据记录id‘, `create_time` datetime NOT NULL COMMENT ‘日志记录时间‘, `create_user` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ‘操作人‘, `create_user_id` varchar(64) NOT NULL COMMENT ‘操作人id‘, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
测试类com.dx.test.LogTest.java:
package com.dx.test; import java.util.Date; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.dx.test.mapper.LogMapper; import com.dx.test.model.Log; import com.dx.test.model.enums.ModuleType; import com.dx.test.model.enums.OperateType; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({ "classpath:spring-config.xml" }) public class LogTest { @Autowired private LogMapper logMapper; @Test public void testInsert() { Log log=new Log(); log.setTitle("test log title"); log.setContent("test log content"); log.setModuleType(ModuleType.Article_Module); log.setOperateType(OperateType.Modify); log.setDataId(String.valueOf(1L)); log.setCreateTime(new Date()); log.setCreateUser("create user"); log.setCreateUserId("user-0001000"); int result=this.logMapper.insert(log); Assert.assertEquals(result, 1); } @Test public void testGetById() { Long logId=1L; Log log=this.logMapper.getById(logId); System.out.println(log); Long dbLogId=(log!=null?log.getId():0L); Assert.assertEquals(dbLogId, logId); } }
执行testInsert()测试函数的执行结果如下:
Logging initialized using ‘class org.apache.ibatis.logging.stdout.StdOutImpl‘ adapter. Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1e4d3ce5] was not registered for synchronization because synchronization is not active JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1b8a29df] will not be managed by Spring ==> Preparing: INSERT INTO log (title, module_type, operate_type, data_id, content, create_time, create_user, create_user_id) VALUES (?, ?, ?, ?, ?, now(), ?, ?) ==> Parameters: test log title(String), Article_Module(String), Modify(String), 1(String), test log content(String), create user(String), user-0001000(String) <== Updates: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1e4d3ce5]
执行testSelectById()测试函数的执行结果如下:
Logging initialized using ‘class org.apache.ibatis.logging.stdout.StdOutImpl‘ adapter. Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@404bbcbd] was not registered for synchronization because synchronization is not active JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@275bf9b3] will not be managed by Spring ==> Preparing: select * from `log` where `id`=? ==> Parameters: 1(Long) <== Columns: id, title, content, module_type, operate_type, data_id, create_time, create_user, create_user_id <== Row: 1, test log title, <<BLOB>>, Article_Module, Modify, 1, 2019-11-18 21:00:08, create user, user-0001000 <== Total: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@404bbcbd] Log [id=1, title=test log title, moduleType=Article_Module, operateType=Modify, dataId=1, content=test log content, createTime=Mon Nov 18 21:00:08 CST 2019, createUser=create user, createUserId=user-0001000]
此时查询数据库中数据如下:
上边的执行结果可以总结出:在typeHandlers为EnumTypeHandler时,enum中存储到数据的是Enum.name属性,而不是enum定义的value值,也不是Enum.ordinal属性。
测试存储enum字段为int(4):
修改测试log表的module_type、operate_type为int(4):
truncate table `log`;
alter table `log` modify column `module_type` int(4) not null comment ‘模块类型‘; alter table `log` modify column `operate_type` int(4) not null comment ‘操作类型‘;
此时执行测试类com.dx.test.LogTest.java
执行testInsert(),抛出以下异常:
org.springframework.jdbc.UncategorizedSQLException: ### Error updating database. Cause: java.sql.SQLException: Incorrect integer value: ‘Article_Module‘ for column ‘module_type‘ at row 1 ### The error may involve com.dx.test.mapper.LogMapper.insert-Inline ### The error occurred while setting parameters ### SQL: INSERT INTO log (title, module_type, operate_type, data_id, content, create_time, create_user, create_user_id) VALUES (?, ?, ?, ?, ?, now(), ?, ?) ### Cause: java.sql.SQLException: Incorrect integer value: ‘Article_Module‘ for column ‘module_type‘ at row 1 ; uncategorized SQLException; SQL state [HY000]; error code [1366]; Incorrect integer value: ‘Article_Module‘ for column ‘module_type‘ at row 1;
nested exception is java.sql.SQLException: Incorrect integer value: ‘Article_Module‘ for column ‘module_type‘ at row 1 at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:89) at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:88) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:440) at com.sun.proxy.$Proxy24.insert(Unknown Source) at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:271) at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:58) at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59) at com.sun.proxy.$Proxy36.insert(Unknown Source) at com.dx.test.LogTest.testInsert(LogTest.java:37) 。。。
执行testGetById()测试函数,需要先插入一条,否则空数据测试无意义:
insert into log
(title,content,module_type,operate_type,data_id,create_time,create_user,create_user_id)
values(‘test title‘,‘test content‘,2,2,‘1‘,now(),‘test create user‘,‘test create user id‘);
此时执行抛出以下异常:
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.result.ResultMapException:
Error attempting to get column ‘module_type‘ from result set.
Cause: java.lang.IllegalArgumentException: No enum constant com.dx.test.model.enums.ModuleType.2 at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:92) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:440) at com.sun.proxy.$Proxy24.selectOne(Unknown Source) at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:159) at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:83) at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59) at com.sun.proxy.$Proxy36.getById(Unknown Source) at com.dx.test.LogTest.testGetById(LogTest.java:44) 。。。
MyBatis(八):Mybatis Java API枚举类型转化的用法
原文:https://www.cnblogs.com/yy3b2007com/p/11884898.html