MyBatis typeAliases & typeHandlers(3)

2021-04-14 14:33:07 浏览数 (1)

typeAliases(类型别名)

顾名思义,它就是java类型的一个缩写名字,方便在Mapper等其他地方使用。

代码语言:javascript复制
<!-- mybatis-config.xml -->
<typeAliases>
        <typeAlias alias="user" type="com.freecloud.plug.mybatis.entity.User" />
        <typeAlias alias="myBatisJson" type="com.freecloud.plug.mybatis.entity.MyBatisJson" />
        <typeAlias alias="department" type="com.freecloud.plug.mybatis.entity.Department" />
        <typeAlias alias="userAndDepartment" type="com.freecloud.plug.mybatis.entity.UserAndDepartment" ></typeAlias>
</typeAliases>

<!-- UserMapper.xml -->
<resultMap id="BaseResultMap" type="user">
        <id column="id" property="id" jdbcType="INTEGER"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <result column="age" property="age" jdbcType="INTEGER"/>
</resultMap>

可以看到,在resultMap标签type属性直接使用别名user就可以匹配到类型”com.freecloud.plug.mybatis.entity.User“,极大的减少了全限定类名的书写。

也可以使用包搜索方式,减少配置,但需要在实体类上增加@Alias注解

代码语言:javascript复制
<typeAliases>
  <package name="com.freecloud.plug.mybatis.entity"/>
</typeAliases>
代码语言:javascript复制
@Data
@NoArgsConstructor
@AllArgsConstructor
@Alias("user")
public class User implements Serializable {
    /** 主键ID */
    private Long id;
    /** 姓名 */
    private String name;
    /** 年龄 */
    private Integer age;
}

上边是我们自定义的一些类型,对于一些基本数据类型MyBatis已经为我们内置了一些基本数据类型的别名。

它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。如下:

别名

映射的类型

_byte

byte

_long

long

_short

short

_int

int

_integer

int

_double

double

_float

float

_boolean

boolean

string

String

byte

Byte

long

Long

short

Short

int

Integer

integer

Integer

double

Double

float

Float

boolean

Boolean

date

Date

decimal

BigDecimal

bigdecimal

BigDecimal

object

Object

map

Map

hashmap

HashMap

list

List

arraylist

ArrayList

collection

Collection

iterator

Iterator

typeHandlers(类型处理器)

由于java类型与数据库的JDBC类型不是一一对应的(比如String与varchar、char、text),所以我们把java对象转换为数据库值时,和把数据库的值转换成java对象,需要经过一定的转换,这两个方向的转换就要用到TypeHandler。

在我们常规使用时我们没做任何配置,为什么对象里的String属性,可以转换成数据库里的varchar字段?

这是因为MyBatis已经内置了很多TypeHandler(在org.apache.ibatis.type包下),他们全部注册在TypeHandlerRegistry中,他们都继承了抽象类BaseTypeHandler<T>,泛型就是要处理的java数据类型。

这也是大部分类型都不需要我们处理的原因。当我们查询数据和操作数据时,做数据类型转换的时候,就会自动调用对应的TypeHandler方法。

如果我们想自定义一些类型转换规则,或者对一些特殊类型做处理,比如要支持mysql 5.7 之后的json类型、使用一个字段存储多个外键ID用“,”分隔、或者支持字段枚举类型,自动转换等等。

下边我们自定义一个TypeHandler来实现一个简单支持mysql 5.7之后的json类型字段。

首先跟系统自定义的TypeHandlerg一样,继承抽象类BaseTypeHandler<T>。有4个抽象方法必须实现,我们把它分成两类:

set方法是从java类型转换成JDBC类型的,get方法是从JDBC类型转换成java类型的。

这里将数据库中的Json类型数据,转换为hutool中的JSON对象。

  1. 编写自定义typeHander
代码语言:javascript复制
package com.freecloud.plug.mybatis.type;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.freecloud.common.LoggerUtil;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
 *
 * 注意:需要使用mysql-connector 5.1.40以上才可解决mysql json格式乱码问题
 * @Author: maomao
 * @Date: 2021-04-09 11:16
 */
public class JsonTypeHandler extends BaseTypeHandler<JSON> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, JSON parameter, JdbcType jdbcType) throws SQLException {
        LoggerUtil.printThread("java -> jdbc类型");
        ps.setString(i,parameter.toString());
    }

    @Override
    public JSON getNullableResult(ResultSet rs, String columnName) throws SQLException {
        LoggerUtil.printThread("jdbc -> java类型 根据列名获取");
        return JSONUtil.parse(rs.getString(columnName));
    }

    @Override
    public JSON getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        LoggerUtil.printThread("jdbc -> java类型 根据序号获取");
        return JSONUtil.parse(rs.getString(columnIndex));
    }

    @Override
    public JSON getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        LoggerUtil.printThread("jdbc -> java类型 存储过程使用");
        return JSONUtil.parse(cs.getString(columnIndex));
    }
}
  1. 在mybatis-config.xml文件中注册
代码语言:javascript复制
<!-- 自定义类型转换器 -->
<typeHandlers>
    <typeHandler handler="com.freecloud.plug.mybatis.type.JsonTypeHandler"></typeHandler>
</typeHandlers>
  1. 在我们需要使用的字段上指定
代码语言:javascript复制
<resultMap id="BaseResultMap" type="myBatisJson">
    <id column="id" property="id" jdbcType="INTEGER"/>
    <result column="name" property="name" jdbcType="VARCHAR"/>
    <result column="json" property="json" jdbcType="VARCHAR" typeHandler="com.freecloud.plug.mybatis.type.JsonTypeHandler" />
</resultMap>

准备数据

代码语言:javascript复制
## mybatis测试typeHander增加json转换
CREATE TABLE `mybatis_json` (
  `id` int(5) NOT NULL,
  `name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
  `json` json DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

insert into mybatis_json values (1,'名称1','{"remark" : "无"}');

实例对象

代码语言:javascript复制
@Data
@ToString
public class MyBatisJson implements Serializable {
    /** 主键ID */
    private Long id;
    /** 姓名 */
    private String name;
    /** json */
    private JSON json;
}

单元测试:

代码语言:javascript复制
/**
 * 测试获取json类型的数据,做转换
 */
@Test
public void testJsonTypeHander(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    try {
        MyBatisJsonMapper mapper = sqlSession.getMapper(MyBatisJsonMapper.class);
        MyBatisJson myBatisJson = mapper.byId(1L);
        LoggerUtil.printThread(myBatisJson.toString());
    }finally {
        sqlSession.close();
    }
}
代码语言:javascript复制
//新增
@Test
public void testSaveJsonTypeHander(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    try {
        MyBatisJsonMapper mapper = sqlSession.getMapper(MyBatisJsonMapper.class);
        MyBatisJson myBatisJson = new MyBatisJson();
        myBatisJson.setId(1001L);
        myBatisJson.setName("名称:"   DateUtil.now());
        myBatisJson.setJson(JSONUtil.parse("{"remark" : ""   DateUtil.now()   ""}"));
        mapper.save(myBatisJson);
        sqlSession.commit();
        LoggerUtil.printThread(myBatisJson.toString());
    }finally {
        sqlSession.close();
    }
}

以上实现了一个简单的mysql json数据类型转换

0 人点赞