Mybatis中封装数据如何自定义一个数据类型处理器
说明:干过Java都知道,数据库的数据类型与Java中属性的类型是不完全一致的,Java中的int类型,MySQL有与之对应的int类型,但MySQL的json类型,Java就没有与之对应的类型,还有例如MySQL的地理坐标类型,Java中也是没有与之对应的类型。
当然,json类型我们可以用第三方库(如fastjson中)的 JSONObject 类型来对应,但直接使用查询数据库是封装不了的。
本文介绍如何自定义一个数据类型处理器,来处理这种情况,实现数据库类型到Java类型的转换。
场景
如下,实体类User的extraInfo字段,类型是 JSONObject,表示用户的扩展信息;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
/**
* 用户
*/
@Data
public class User {
private Long userId;
private String username;
private String password;
private JSONObject extraInfo;
}
数据库中的类型是 json
查询
import com.hezy.pojo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserMapper {
List<User> selectAllUser();
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hezy.mapper.UserMapper">
<select id="selectAllUser" resultType="com.hezy.pojo.entity.User" >
select * from tb_user
</select>
</mapper>
测试
@Test
public void selectTest4() {
List<User> users = userMapper.selectAllUser();
System.out.println("users = " + users);
}
封装不进来
数据类型处理器
创建一个类型处理器,如下:
import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import java.sql.*;
@MappedTypes(JSONObject.class)
@MappedJdbcTypes(JdbcType.OTHER)
public class JSONObjectTypeHandler extends BaseTypeHandler<JSONObject> {
/**
* 设置参数
*/
@Override
public void setNonNullParameter(PreparedStatement ps, int i, JSONObject parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter.toJSONString());
}
/**
* 获取数据库中的值
*/
@Override
public JSONObject getNullableResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
return json != null ? JSONObject.parseObject(json) : null;
}
/**
* 获取数据库中的值
*/
@Override
public JSONObject getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String json = rs.getString(columnIndex);
return json != null ? JSONObject.parseObject(json) : null;
}
/**
* 获取数据库中的值
*/
@Override
public JSONObject getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String json = cs.getString(columnIndex);
return json != null ? JSONObject.parseObject(json) : null;
}
}
其中,类上的注解,
-
@MappedTypes(JSONObject.class):表示JavaBean中的数据类型,是JSONObject;
-
@MappedJdbcTypes(JdbcType.OTHER):表示的是数据库中的类型,这里没有JSON,可以选择OTHER;
其中,四个成员方法,
第一个:表示数据存入到数据库中的操作,数据库中json类型能接收的是json格式的字符串,所以需要toString();
后面三个:表示读取数据库后,数据转为Java中的操作,这里就可以将数据库类型再转为Java中的JSONObject类型;
两种使用方式
第一种很简单,再当前类型处理器上打上 @Component
注解,只要类型符合,都会执行该类的方法,相当于加了一层拦截器,如下:
import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.springframework.stereotype.Component;
import java.sql.*;
@Component
@MappedTypes(JSONObject.class)
@MappedJdbcTypes(JdbcType.OTHER)
public class JSONObjectTypeHandler extends BaseTypeHandler<JSONObject> {
/**
* 设置参数
*/
@Override
public void setNonNullParameter(PreparedStatement ps, int i, JSONObject parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter.toJSONString());
}
/**
* 获取数据库中的值
*/
@Override
public JSONObject getNullableResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
return json != null ? JSONObject.parseObject(json) : null;
}
/**
* 获取数据库中的值
*/
@Override
public JSONObject getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String json = rs.getString(columnIndex);
return json != null ? JSONObject.parseObject(json) : null;
}
/**
* 获取数据库中的值
*/
@Override
public JSONObject getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String json = cs.getString(columnIndex);
return json != null ? JSONObject.parseObject(json) : null;
}
}
查询,可以看到数据能封装到JavaBean中
方式二,在查询的 resultMap 中,封装数据的同时,指定数据类型处理器,如下:
<resultMap id="getAllUser" type="com.hezy.pojo.entity.User">
<result column="user_id" property="userId" />
<result column="username" property="username" />
<result column="password" property="password" />
<result column="extra_info" property="extraInfo" typeHandler="com.hezy.config.JSONObjectTypeHandler" />
</resultMap>
<select id="selectAllUser" resultMap="getAllUser" >
select * from tb_user
</select>
查询,也可以封装进来
但需要注意,因为这种方式,只对这个查询方法生效,如果你的项目中有其他 insert() 方法,对应字段也需要指定数据类型处理器
<insert id="insert" parameterType="com.hezy.pojo.entity.User">
insert into tb_user(user_id, username, password, extra_info)
values(#{userId},#{username},#{password},#{extraInfo, typeHandler=com.hezy.config.JSONObjectTypeHandler})
</insert>
不然就会报下面这个错误
另外
通过上面的介绍,我们可以思考这两点,
-
通过数据类型处理器,数据库和编程语言之间的数据可以自由、灵活地互相转换,数据库存的是int,也能给你转为字符串;
-
能看出数据库和编程语言,对于数据定义是不一致的,数据库专注存储,所以划分更细致具体,编程语言重逻辑,所以定义更自由;
总结
本文介绍了如何在Mybatis中自定义一个数据类型处理器