首页 > 编程语言 > 详细

MyBatis(八):Mybatis Java API枚举类型转化的用法

时间:2019-11-18 21:47:22      阅读:89      评论:0      收藏:0      [点我收藏+]

最近工作中用到了mybatis的Java API方式进行开发,顺便也整理下该功能的用法,接下来会针对基本部分进行学习:

1)Java API处理一对多、多对一的用法

2)增、删、改、查的用法;

3)涉及到类型转化的用法;

4)批量修改、批量查询、批量新增的用法。

Mybatis官网给了具体的文档,但是并没有对以上用法具体介绍,因此在这里整理下,以便以后工作用到时,可以参考。

本章主要使用Mybatis中使用typeHandlers进行对Enum进行转化的用法(本章将结合Spring自动注入《Spring(二十三):Spring自动注入的实现方式》),下边文章分为以下几个步骤:

本章将不再对maven项目的引入包,以及配置文件:jdbc.properties、mybatis-config.xml、spring-config.xml重复进行介绍,详情请参考上篇文件构建项目过程:《MyBatis(七):mybatis Java API编程实现增、删、改、查的用法》。

简介:

在开发过程中,我们往往会使用到枚举类型,因为使用枚举更可以穷举、开发起来方便、把所有可选值都定义在一起(比起使用数字代表更能避免出现BUG:数字标记规定一旦数字记错或者数字代表意义变化都会导致n多问题:带来bug、不易维护)。
因此枚举类型的出现给开发带来了不少好处:

  • 1)将一系列的枚举项统一定义到一个enum文件中,统一管理(比起使用数字,导出都是数字和备注);
  • 2)而且增加一个枚举时只要已定义值不变动,不会影响到其他已有枚举项;
  • 3)另外,如果调整枚举值是,只需要修改enum文件中定义枚举项值(使用数字,需要使用到地方一个一个的修改,很容易出错),以及设计到持久化的数据调整。

什么时候使用枚举?

  • 定义用户的性别:可以定义为male,female,other,nolimit;
  • 标记记录的状态:0-living,1-published,2-deleted。

在实际开发中,入库时我们可以选择enum的code(int/smallint.tinyint)入库,也可以选择enum的name(varchar)入库。实际上往往code存入库的话,按照int来存储;name入库的话,按照varchar存储。读取的时候再进行转化按照库中的int值转化为enum,或者按照库中的varchar值转化为enum.

Enum的属性中包含两个字段:

  • 1)name(String类型,存储enum元素的字符串)
  • 2)ordinal(int类型,存储enum元素的顺序,从0开始)

弄清这点对后边分析一些现象会有帮助。

Mybatis中默认提供了两种Enum类型的handler:EnumTypeHandler和EnumOrdinalTypeHandler。

  • EnumTypeHandler:将enum按照String存入库,存储为varchar类型;
  • EnumOrdinalTypeHandler:将enum按照Integer处理,存储为int(smallint、tinyint也可以)。

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的用法:

typeHandlers之EnumTypeHandler(默认)的用法:

1)db使用varchar存储enum(enum的类型为:String、Integer)的用法

在不修改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属性。

2)db使用int存储enum(enum的类型为:String、Integer)的用法

测试存储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) 。。。

 

 

typeHandlers之EnumOrdinalTypeHandler的用法:

 

 

 

MyBatis(八):Mybatis Java API枚举类型转化的用法

原文:https://www.cnblogs.com/yy3b2007com/p/11884898.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!