两个系统提供的枚举类型处理器
枚举类型的类型处理器比较特殊,MyBatis提供了两个处理Java枚举类型的类型处理器:
- org.apache.ibatis.type.EnumTypeHandler(使用枚举字符串名称作为参数传递)
- org.apache.ibatis.type.EnumOrdinalTypeHandler(使用枚举整数下标作为参数传递)
测试这两个枚举类型处理器
数据库中添加表
后两个字段都是指这本书的类型,一个想要用枚举整数下标,一个想要用枚举字符串名称,放在一起好测试。
enums.BookType(枚举类)
package enums;
//书类型的枚举,随便写几种类别
public enum BookType {
LOVE, ART, COMPUTER
}
model.Book(PO类)
package model;
import enums.BookType;
import org.apache.ibatis.type.Alias;
@Alias("book")
public class Book {
private int id;
private String name;
//这两属性都是枚举,一样的,这个Id和Name只是为了在这个实验里对照数据库中的列方便一些
private BookType typeId;
private BookType typeName;
//getter和setter...
}
mapper.BookMapper(映射器接口)
package mapper;
import model.Book;
public interface BookMapper {
Book getBook(int id);
int addBook(Book book);
}
mapper/BookMapper.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="mapper.BookMapper">
<!--ResultSet映射-->
<resultMap id="bookMap" type="book">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!--用整数下标-->
<result column="type_id" property="typeId" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
<!--用枚举字符串名称-->
<result column="type_name" property="typeName" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
</resultMap>
<!--按id查询书-->
<select id="getBook" parameterType="int" resultMap="bookMap">
SELECT
id,
name,
type_id,
type_name
FROM book
WHERE id = #{id}
</select>
<!--插入一本新书,typeId用整数下标的处理器,typeName用枚举字符串名称的处理器-->
<insert id="addBook" parameterType="book">
INSERT INTO book (name, type_id, type_name)
VALUES (#{name}, #{typeId,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler},
#{typeName,typeHandler=org.apache.ibatis.type.EnumTypeHandler})
</insert>
</mapper>
MyBatis配置文件
基本不用改,注册一下映射器:
<mappers>
<mapper resource="mapper/BookMapper.xml"/>
</mappers>
别名的扫描包保证好:
<typeAliases>
<package name="model"/>
</typeAliases>
Main
import enums.BookType;
import mapper.BookMapper;
import model.Book;
import org.apache.ibatis.session.SqlSession;
import util.SqlSessionFactoryUtil;
public class Main {
public static void main(String[] args) {
SqlSession sqlSession = null;
try {
//调用工具类的静态方法开启并获取一个SqlSession实例
sqlSession = SqlSessionFactoryUtil.openSqlSession();
//获取映射器代理类对象
BookMapper bookMapper=sqlSession.getMapper(BookMapper.class);
//建立一本书,注意后面两个类别属性其实是一样的,只是为了测试使用不同的枚举类型处理器他们在数据库中的不同表现
Book book1=new Book();
book1.setName("一本书");
book1.setTypeId(BookType.ART);
book1.setTypeName(BookType.ART);
//插入,这里顺便测试一下带返回值能不能正确显示受影响行数
int rows=bookMapper.addBook(book1);
System.out.println("成功插入,"+rows+"行受影响");
//查出来
Book book2=bookMapper.getBook(1);
System.out.println(book2.getTypeId()+"和"+book2.getTypeName()+"都能正常变回枚举类型");
//提交事务
sqlSession.commit();
} catch (Exception e) {
//发生异常时打印异常信息
System.err.println(e.getMessage());
//回退
if (null != sqlSession)
sqlSession.rollback();
} finally {
//在finally块中关闭SqlSession对象
if (null != sqlSession)
sqlSession.close();
}
}
}
运行结果
输出:
数据库中:
自定义枚举类型处理器的必要
根据书上的说法,更多的时候不使用它们,而是使用自定义的枚举类型处理器。
我个人对此的理解是,当数据库中已经存在某种不易修改的关系时,例如图书种类和图书种类号码,很难将一个多年运营的数据库某种具有枚举逻辑的信息(可能已经删了好多种类导致号码不连续,或者压根就不是整数号码)映射给连续的枚举数值。这时候所需要建立的枚举可能会包含这个种类号属性,这样就比较复杂,用这两个处理器显然是处理不了这种映射关系的。
具体的自定义方式和上篇的使用一样,只要在那四个要实现的方法里面做好和复杂枚举的属性的转换就可以了。