MyBatis中TypeHandler的使用
最终遇到一个问题,就是在使用MyBatis保存数据的时候里面的javabean得字段不是单纯的字段,而是包含了对象(也是javaBean)。这种方式并不奇怪,但是以为我这次遇到的是四次嵌套。所以我就使用了TypeHandler来处理试试,测试的时候还是以双层嵌套为例子。
基本环境的准备
实体类代码:
public class Person { private int id; private Student student; public int getId() { return id; } public void setId(int id) { this.id = id; } public Student getStudent() { return student; } public void setStudent(Student student) { this.student = student; } @Override public String toString() { return "Person{" + "id=" + id + ", student=" + student + '}'; } }
public class Student { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Mapper接口
public interface PersonMapper { /** * 新增一条记录 * * @param p * @return */ Integer insertOne(Person p); /** * 查询一条记录 * * @param p * @return */ Person query(); }
Mapper.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.example.mybatistypehandler.mapper.PersonMapper"> <resultMap id="BaseResultMap" type="com.example.mybatistypehandler.domain.Person"> <id column="id" jdbcType="INTEGER" property="id"></id> <result column="student" jdbcType="VARCHAR" property="student" typeHandler="com.example.mybatistypehandler.util.JsonTypeHandler"/> </resultMap> <insert id="insertOne"> INSERT INTO person(student) VALUES(#{student,typeHandler=com.example.mybatistypehandler.util.JsonTypeHandler}) </insert> <select id="query" resultMap="BaseResultMap"> select id,student from person limit 1 </select> </mapper>
service以及实现类
public interface PersonService { /** * 新增一条记录 * * @param p * @return */ Integer insert(Person p); /** * 查询一条记录 * * @param p * @return */ Person query(); }
@Service public class PersonServiceImpl implements PersonService { @Autowired(required = false) PersonMapper personMapper; @Override public Integer insert(Person p) { return personMapper.insertOne(p); } @Override public Person query() { return personMapper.query(); } }
Controller
@RestController @RequestMapping("t") public class MyTypeHandlerController { @Autowired PersonService personService; @RequestMapping("save") public String save(@RequestBody Person person) { personService.insert(person); return "SUCCESS"; } @RequestMapping("query") public String query() { Person query = personService.query(); System.out.println(query); System.out.println(query.getStudent()); return "SUCCESS"; } }
yml配置文件
server: port: 8899 spring: application: TypeHandlerTest datasource: druid: #指定数据库类型 db-type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.20.152:3306/TypeHandlerTest?useUnicode=true&characterEncoding=utf8&useSSL=false username: root password: 111111 mybatis: mapper-locations: classpath:mapper/**.xml
工具类
public class JsonTypeHandler<T extends Object> extends BaseTypeHandler<T> { private Class<T> clazz; public JsonTypeHandler(Class<T> clazz) { if (clazz == null) { throw new IllegalArgumentException("Type argument cannot be null"); } this.clazz = clazz; } @Override public void setNonNullParameter(PreparedStatement preparedStatement, int i, T t, JdbcType jdbcType) throws SQLException { preparedStatement.setString(i, this.toJson(t)); } @Override public T getNullableResult(ResultSet resultSet, String columnName) throws SQLException { return this.toObject(resultSet.getString(columnName), clazz); } @Override public T getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException { return this.toObject(resultSet.getString(columnIndex), clazz); } @Override public T getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException { return this.toObject(callableStatement.getString(columnIndex), clazz); } private String toJson(T object) { try { return JSON.toJSONString(object); } catch (Exception e) { throw new RuntimeException(e); } } private T toObject(String content, Class<?> clazz) { if (content != null && !content.isEmpty()) { try { return (T) JSON.parseObject(content, clazz); } catch (Exception e) { throw new RuntimeException(e); } } else { return null; } } }
启动类
@SpringBootApplication @MapperScan(basePackages = "com.example.mybatistypehandler.mapper") public class MybatisTypehandlerApplication { public static void main(String[] args) { SpringApplication.run(MybatisTypehandlerApplication.class, args); } }
测试
http://localhost:8899/t/save
{
"student":{
"name":"小明"
}
}
对象数据被成功转成json保存到数据库了
那么查询的时候能否将json转成对象保存起来呢?
http://localhost:8899/t/query
json被成功的封装到对象中了。
原理
在保存的时候,实际上走了这个方法:setNonNullParameter
断点调试下看看是什么东西
最后一个是数据库中的字段类型。
查询的调试
这就是为什么数据库中是json,但是查出来却能直接转成对象的原因。
另外注意JsonTypeHandler是需要继承BaseTypeHandler(或者是)实现TypeHandler接口。只要这样MyBatis在处理类型的时候才会去执行相应的方法。
MyBatis中自带的类型处理
不畏艰险,践踏实地!