千家信息网

mybatis中的类型转换方式

发表于:2024-09-25 作者:千家信息网编辑
千家信息网最后更新 2024年09月25日,本篇内容介绍了"mybatis中的类型转换方式"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.场景
千家信息网最后更新 2024年09月25日mybatis中的类型转换方式

本篇内容介绍了"mybatis中的类型转换方式"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

1.场景

日常java开发中经常有这种需求,用0或者1这些代码(不局限于数字)来表示某种状态。比如用0表示女性,用1来表示男性。而且写入数据库可能是一个标识,从数据库读取又还原为具体的说明。而且一般情况下为了更好理解或者消除魔法值,通常的处理方案是定义一个枚举:

有些枚举是这样定义的

 public enum GenderType{      FEMALE,MALE,UNKNOWN }

那么通常很多人会这么入库(java伪代码)

  if(GenderType.MALE){   // 写入 1  }else if(GenderType.FEMALE){   // 写入 0  }else{  //也可能是泰国回来的 那就 2  }

读取的时候要么同样按照上面的再反向处理一次或者使用数据库sql语法case when 来直接写入DTO

 CASE gender WHEN 1 THEN '男' WHEN 0 THEN '女' ELSE '未知' END

这种处理方式看起来不是很优雅。而且多了很多的判断和处理逻辑,和我们的业务并不是非常相关。所以我们可以选择更好的处理方式。

2.Mybatis中的TypeHandler

如果你ORM框架用的是Mybatis。那么将很容易通过TypeHandler接口解决这个问题。

2.1 TypeHandler 分析

public interface TypeHandler {    void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;   T getResult(ResultSet rs, String columnName) throws SQLException;  T getResult(ResultSet rs, int columnIndex) throws SQLException;  T getResult(CallableStatement cs, int columnIndex) throws SQLException;}

源码分析:

  • setParameter 方法 通过 传入的T类型写你自己的逻辑,选择调用 PreparedStatement 对象的某个set方法将数据写入数据库。此方法用来写库。

  • getResult(ResultSet rs, String columnName) 通过字段名来读库并转换为T类型。

  • getResult(ResultSet rs, int columnIndex) 通过字段索引来读库并转换为T类型。

  • getResult(CallableStatement cs, int columnIndex) 调用存储过程来获取结果并转换为T类型。

2.2 EnumOrdinalTypeHandler

我们发现TypeHandler有一个实现类EnumOrdinalTypeHandler。字面意思是可以通过枚举的序号来处理类型。

@Override  public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {    ps.setInt(i, parameter.ordinal());  }

我们先不考虑setNull的情况。通过此方法我们发现确实存入的是枚举的顺序值(顺序从0开始),拿上面的例子来说 如果是GenderType.FEMALE是0,如果是GenderType.MALE是1,但是当GenderType.UNKNOWN时存入的是2。取的时候也是自然反向处理为具体的GenderType枚举。

2.3 EnumTypeHandler

我们还发现有另外一个枚举类型处理器。它的set方法是这样的:

  @Override  public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {    if (jdbcType == null) {      ps.setString(i, parameter.name());    } else {      ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE); // see r3589    }  }

我们不考虑jdbcType问题发现都是将Enum.name()的值写入数据库。拿上面的例子来说 如果是GenderType.FEMALE是FEMALE,如果是GenderType.MALE是MALE,但是当GenderType.UNKNOWN时存入的是UNKNOWN。读库是通过Enum.valueOf(Class enumType,String name)来进行反转操作。

2.4 自定义TypeHandler

如果说我们的枚举类型或者说我们使用其他方式来处理类别转换怎么办?当然Mybatis不会帮你干这么具体的事情。需要你自己来实现了。我们还拿枚举作为例子,然后模仿上面的两种TypeHandler。 还是拿开始的例子来说通常我个人比较喜欢这么定义枚举:

public enum GenderTypeEnum {    /**     * female.     */    FEMALE(0, "女"),     /**     * male.     */    MALE(1,"男"),    /**     * unknown.     */    UNKNOWN(2, "未知");    private int value;    private String description;    GenderType(int value, String description) {        this.value = value;        this.description = description;    }         public int value() {        return this.value;    }         public String description() {        return this.description;    }}

通过继承BaseTypeHandler实现该抽象类的3个钩子方法就行了:

@MappedTypes({GenderTypeEnum.class})@MappedJdbcTypes({JdbcType.INTEGER})public class GenderTypeEnumTypeHandler extends BaseTypeHandler {    @Override    public void setNonNullParameter(PreparedStatement ps, int i, GenderTypeEnum parameter, JdbcType jdbcType) throws SQLException {        if (jdbcType == null) {            ps.setInt(i, parameter.value());        } else {            // see r3589            ps.setObject(i, parameter.value(), jdbcType.TYPE_CODE);        }    }    @Override    public GenderTypeEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {        return getGenderType(rs.getInt(columnName));    }    @Override    public GenderTypeEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {        return getGenderType(rs.getInt(columnIndex));    }    @Override    public GenderTypeEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {        return getGenderType(cs.getInt(columnIndex));    }    private GenderTypeEnum getGenderType(int value) {        Class genderTypeClass = GenderTypeEnum.class;        return Arrays.stream(genderTypeClass.getEnumConstants())                .filter(genderType -> genderType.value() == value)                .findFirst().orElse(GenderTypeEnum.UNKNOWN);    }}

TypeHandler 实现写好了,那么如何让其发挥作用呢?我们接着往下走。

2.5 TypeHandler的核心要点

TypeHandler作用是javaType和jdbcType相互转换。所以在声明一个TypeHandler的时候一定要明确该TypeHandler处理的这两种类型。这是必须要明确的原则。MyBatis不会通过窥探数据库元信息来决定使用哪种JDBC类型,所以你必须在参数和结果映射中指明何种类型的字段,使其能够绑定到正确的类型处理器上。MyBatis直到语句被执行时才清楚数据类型。 通过上述例子中的@MappedJdbcTypes和@MappedTypes来进行绑定类型转换关系,也可以通过xml的typeHandler元素中的jdbcType或者javaType来指定。如果同时指定,xml的优先级要高。 注意有可能你会覆盖内置的TypeHandler。所以自定义时一定要去了解Mybatis提供的一些默认处理器。避免对其他业务的影响。所以使用自定义TypeHandler很重要的一个原则就是一定要声明JavaType和JdbcType.上面这些虽然比较生涩但是对于使用好TypeHandler非常重要。接下来我们来讲讲具体的配置。

2.6 免注册TypeHandler

我们这里只讲xml中的配置:

  • 一种在rultMap元素中声明一般用来查询。一定要注意2.5中的一些原则。

                                   
  • 然后是在插入、更新语句中使用。它们都是相同的,这里只举一个插入例子。

            insert into student (student_name, gender, age)        values (#{studentName},                #{genderType,javaType=cn.felord.mybatis.enums.GenderTypeEnum,jdbcType=INTEGER,typeHandler=cn.felord.mybatis.type.GenderTypeEnumTypeHandler},                #{age})    

如果注册了别名都可以使用别名。上面的好处就是不用在TypeHandlerRegistry中进行注册。

2.7 注册TypeHandler

在配置中声明注册TypeHandler,然后Mybatis根据两种类型会自动匹配。所以这里还是要强调2.5中的核心要点。

  • 如果你是xml配置需要在Configuration配置文件中的标签中进行声明式注册

  • javaConfig 方式 ,第一你可以通过SqlSessionFactory对象取到Configuration对象将typeHandler注册进去。如果你使用mybatis-spring组件,可以在SqlSessionFactoryBean 的setTypeHandlersPackage方法中配置typeHandler的集中包路径,那么框架将会自动扫描并注册他们。springboot中对应的配置属性是mybatis.typeHandlersPackage。

如果你注册了TypeHandler。在Mapper.xml中只需要声明jdbcType和javaType,无需再声明具体的typeHandler。Mybatis会自动通过jdbcType、javaType来映射到具体注册的TypeHandler上去 。就像下面的例子

            insert into student (student_name, gender, age)        values (#{studentName}, #{genderType,javaType=cn.felord.mybatis.enums.GenderTypeEnum,jdbcType=INTEGER}, #{age})    

3.总结

今天我们学习了mybatis开发中如何通过使用类型处理器进行类型的转换处理,如何处理枚举,如何自定义处理器并使用它。相信对你在java开发过程中会有很大的帮助。相关的代码在我的码云仓库中:https://gitee.com/felord/mybatis-test.git

"mybatis中的类型转换方式"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

类型 处理 数据 例子 配置 方式 数据库 面的 处理器 方法 代码 原则 可以通过 字段 对象 情况 时候 过程 开发 重要 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 英雄联盟各个地区服务器英雄选择 北京大数据网络技术咨询口碑推荐 怎么查询数据库最大值 数据库管理关键技术是什么 我的世界服务器都可以做什么 软件开发fo是什么职位 王者不同服务器可以送礼物吗 手机如何进行网络安全测试 手机软件开发打代码吗 湖北专业网络技术创新服务 微软的系统管理服务器 互联网公司金融科技 excel 数组追加数据库 漳州拓展互联网科技有限公司 雾霾对计算机网络技术的启示 表白墙需要数据库吗 莱芜智慧社区软件开发电话 王者的碎星之锤是哪个服务器 网络安全具备哪些基本特征 悠悠导航软件开发 数据库管理的课堂设计 斑马网络技术有限公司任晓慧 西安曲翘工贸招聘软件开发吗 航空行业标准数据库系统 南京白鸥网络技术 农信数据库管理 table 清空数据库 助讯通服务器地址怎么查询 软件开发笔试做得不好会有问题吗 公司局域网服务器放在柜子可以吗
0