typeAliases(类型别名)

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

<!-- 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注解

<typeAliases>
  <package name="com.freecloud.plug.mybatis.entity"/>
</typeAliases>
@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方法。

MyBatis typeAliases & typeHandlers(3)-LMLPHP

如果我们想自定义一些类型转换规则,或者对一些特殊类型做处理,比如要支持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
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文件中注册
<!-- 自定义类型转换器 -->
<typeHandlers>
    <typeHandler handler="com.freecloud.plug.mybatis.type.JsonTypeHandler"></typeHandler>
</typeHandlers>
  1. 在我们需要使用的字段上指定
<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>

准备数据

## 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" : "无"}');

实例对象

@Data
@ToString
public class MyBatisJson implements Serializable {
    /** 主键ID */
    private Long id;
    /** 姓名 */
    private String name;
    /** json */
    private JSON json;
}

单元测试:

/**
 * 测试获取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();
    }
}

MyBatis typeAliases & typeHandlers(3)-LMLPHP

//新增
@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();
    }
}

MyBatis typeAliases & typeHandlers(3)-LMLPHP

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

04-13 08:35