mybatis handler一对多 怎么配置typehandler

阅读(1570)
上篇文章《》为大家介绍了mybatis中别名的使用,以及其源码。本篇将为大家介绍TypeHandler, 并简单分析其源码。
Mybatis中的TypeHandler是什么?
  无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时,都会用类型处理器将获取的值以合适的方式转换成 Java 类型。Mybatis默认为我们实现了许多TypeHandler, 当我们没有配置指定TypeHandler时,Mybatis会根据参数或者返回结果的不同,默认为我们选择合适的TypeHandler处理。
那么,Mybatis为我们实现了哪些TypeHandler呢? &我们怎么自定义实现一个TypeHandler ? &这些都会在接下来的mybatis的源码中看到。
在看源码之前,还是像之前一样,先看看怎么配置吧?
配置TypeHandler:
&configuration&
&typeHandlers&
当配置package的时候,mybatis会去配置的package扫描TypeHandler
&package name="com.dy.demo"/&
&!-- handler属性直接配置我们要指定的TypeHandler --&
&typeHandler handler=""/&
&!-- javaType 配置java类型,例如String, 如果配上javaType, 那么指定的typeHandler就只作用于指定的类型 --&
&typeHandler javaType="" handler=""/&
&!-- jdbcType 配置数据库基本数据类型,例如varchar, 如果配上jdbcType, 那么指定的typeHandler就只作用于指定的类型
&typeHandler jdbcType="" handler=""/&
&!-- 也可两者都配置 --&
&typeHandler javaType="" jdbcType="" handler=""/&
&/typeHandlers&
&/configuration&
上面简单介绍了一下TypeHandler, &下面就看看mybatis中TypeHandler的源码了。
=========================================================我是源码分割线==========================================================
老规矩,先从对xml的解析讲起:
* 解析typeHandlers节点
private void typeHandlerElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
//子节点为package时,获取其name属性的值,然后自动扫描package下的自定义typeHandler
if ("package".equals(child.getName())) {
String typeHandlerPackage = child.getStringAttribute("name");
typeHandlerRegistry.register(typeHandlerPackage);
//子节点为typeHandler时, 可以指定javaType属性, 也可以指定jdbcType, 也可两者都指定
//javaType 是指定java类型
//jdbcType 是指定jdbc类型(数据库类型: 如varchar)
String javaTypeName = child.getStringAttribute("javaType");
String jdbcTypeName = child.getStringAttribute("jdbcType");
//handler就是我们配置的typeHandler
String handlerTypeName = child.getStringAttribute("handler");
//resolveClass方法就是我们上篇文章所讲的TypeAliasRegistry里面处理别名的方法
Class&?& javaTypeClass = resolveClass(javaTypeName);
//JdbcType是一个枚举类型,resolveJdbcType方法是在获取枚举类型的值
JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
Class&?& typeHandlerClass = resolveClass(handlerTypeName);
//注册typeHandler, typeHandler通过TypeHandlerRegistry这个类管理
if (javaTypeClass != null) {
if (jdbcType == null) {
typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
typeHandlerRegistry.register(typeHandlerClass);
接下来看看TypeHandler的管理注册类:
TypeHandlerRegistry:
* typeHandler注册管理类
public final class TypeHandlerRegistry {
//源码一上来,二话不说,几个大大的HashMap就出现,这不又跟上次讲的typeAliases的注册类似么
//基本数据类型与其包装类
private static final Map&Class&?&, Class&?&& reversePrimitiveMap = new HashMap&Class&?&, Class&?&&() {
private static final long serialVersionUID = 1L;
put(Byte.class, byte.class);
put(Short.class, short.class);
put(Integer.class, int.class);
put(Long.class, long.class);
put(Float.class, float.class);
put(Double.class, double.class);
put(Boolean.class, boolean.class);
put(Character.class, char.class);
//这几个MAP不用说就知道存的是什么东西吧,命名的好处
private final Map&JdbcType, TypeHandler&?&& JDBC_TYPE_HANDLER_MAP = new EnumMap&JdbcType, TypeHandler&?&&(JdbcType.class);
private final Map&Type, Map&JdbcType, TypeHandler&?&&& TYPE_HANDLER_MAP = new HashMap&Type, Map&JdbcType, TypeHandler&?&&&();
private final TypeHandler&Object& UNKNOWN_TYPE_HANDLER = new UnknownTypeHandler(this);
private final Map&Class&?&, TypeHandler&?&& ALL_TYPE_HANDLERS_MAP = new HashMap&Class&?&, TypeHandler&?&&();
//就像上篇文章讲的typeAliases一样,mybatis也默认给我们注册了不少的typeHandler
//具体如下
public TypeHandlerRegistry() {
register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler());
register(Byte.class, new ByteTypeHandler());
register(byte.class, new ByteTypeHandler());
register(JdbcType.TINYINT, new ByteTypeHandler());
register(Short.class, new ShortTypeHandler());
register(short.class, new ShortTypeHandler());
register(JdbcType.SMALLINT, new ShortTypeHandler());
register(Integer.class, new IntegerTypeHandler());
register(int.class, new IntegerTypeHandler());
register(JdbcType.INTEGER, new IntegerTypeHandler());
register(Long.class, new LongTypeHandler());
register(long.class, new LongTypeHandler());
register(Float.class, new FloatTypeHandler());
register(float.class, new FloatTypeHandler());
register(JdbcType.FLOAT, new FloatTypeHandler());
register(Double.class, new DoubleTypeHandler());
register(double.class, new DoubleTypeHandler());
register(JdbcType.DOUBLE, new DoubleTypeHandler());
register(String.class, new StringTypeHandler());
register(String.class, JdbcType.CHAR, new StringTypeHandler());
register(String.class, JdbcType.CLOB, new ClobTypeHandler());
register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
register(JdbcType.CHAR, new StringTypeHandler());
register(JdbcType.VARCHAR, new StringTypeHandler());
register(JdbcType.CLOB, new ClobTypeHandler());
register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(JdbcType.NVARCHAR, new NStringTypeHandler());
register(JdbcType.NCHAR, new NStringTypeHandler());
register(JdbcType.NCLOB, new NClobTypeHandler());
register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
register(JdbcType.ARRAY, new ArrayTypeHandler());
register(BigInteger.class, new BigIntegerTypeHandler());
register(JdbcType.BIGINT, new LongTypeHandler());
register(BigDecimal.class, new BigDecimalTypeHandler());
register(JdbcType.REAL, new BigDecimalTypeHandler());
register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
register(Byte[].class, new ByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
register(byte[].class, new ByteArrayTypeHandler());
register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.BLOB, new BlobTypeHandler());
register(Object.class, UNKNOWN_TYPE_HANDLER);
register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(Date.class, new DateTypeHandler());
register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
register(JdbcType.TIMESTAMP, new DateTypeHandler());
register(JdbcType.DATE, new DateOnlyTypeHandler());
register(JdbcType.TIME, new TimeOnlyTypeHandler());
register(java.sql.Date.class, new SqlDateTypeHandler());
register(java.sql.Time.class, new SqlTimeTypeHandler());
register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());
// issue #273
register(Character.class, new CharacterTypeHandler());
register(char.class, new CharacterTypeHandler());
public boolean hasTypeHandler(Class&?& javaType) {
return hasTypeHandler(javaType, null);
public boolean hasTypeHandler(TypeReference&?& javaTypeReference) {
return hasTypeHandler(javaTypeReference, null);
public boolean hasTypeHandler(Class&?& javaType, JdbcType jdbcType) {
return javaType != null && getTypeHandler((Type) javaType, jdbcType) != null;
public boolean hasTypeHandler(TypeReference&?& javaTypeReference, JdbcType jdbcType) {
return javaTypeReference != null && getTypeHandler(javaTypeReference, jdbcType) != null;
public TypeHandler&?& getMappingTypeHandler(Class&? extends TypeHandler&?&& handlerType) {
return ALL_TYPE_HANDLERS_MAP.get(handlerType);
public &T& TypeHandler&T& getTypeHandler(Class&T& type) {
return getTypeHandler((Type) type, null);
public &T& TypeHandler&T& getTypeHandler(TypeReference&T& javaTypeReference) {
return getTypeHandler(javaTypeReference, null);
public TypeHandler&?& getTypeHandler(JdbcType jdbcType) {
return JDBC_TYPE_HANDLER_MAP.get(jdbcType);
public &T& TypeHandler&T& getTypeHandler(Class&T& type, JdbcType jdbcType) {
return getTypeHandler((Type) type, jdbcType);
public &T& TypeHandler&T& getTypeHandler(TypeReference&T& javaTypeReference, JdbcType jdbcType) {
return getTypeHandler(javaTypeReference.getRawType(), jdbcType);
private &T& TypeHandler&T& getTypeHandler(Type type, JdbcType jdbcType) {
Map&JdbcType, TypeHandler&?&& jdbcHandlerMap = TYPE_HANDLER_MAP.get(type);
TypeHandler&?& handler = null;
if (jdbcHandlerMap != null) {
handler = jdbcHandlerMap.get(jdbcType);
if (handler == null) {
handler = jdbcHandlerMap.get(null);
if (handler == null && type != null && type instanceof Class && Enum.class.isAssignableFrom((Class&?&) type)) {
handler = new EnumTypeHandler((Class&?&) type);
@SuppressWarnings("unchecked")
// type drives generics here
TypeHandler&T& returned = (TypeHandler&T&)
public TypeHandler&Object& getUnknownTypeHandler() {
return UNKNOWN_TYPE_HANDLER;
public void register(JdbcType jdbcType, TypeHandler&?& handler) {
JDBC_TYPE_HANDLER_MAP.put(jdbcType, handler);
// REGISTER INSTANCE
* 只配置了typeHandler, 没有配置jdbcType 或者javaType
@SuppressWarnings("unchecked")
public &T& void register(TypeHandler&T& typeHandler) {
boolean mappedTypeFound = false;
//在自定义typeHandler的时候,可以加上注解MappedTypes 去指定关联的javaType
//因此,此处需要扫描MappedTypes注解
MappedTypes mappedTypes = typeHandler.getClass().getAnnotation(MappedTypes.class);
if (mappedTypes != null) {
for (Class&?& handledType : mappedTypes.value()) {
register(handledType, typeHandler);
mappedTypeFound = true;
// @since 3.1.0 - try to auto-discover the mapped type
if (!mappedTypeFound && typeHandler instanceof TypeReference) {
TypeReference&T& typeReference = (TypeReference&T&) typeH
register(typeReference.getRawType(), typeHandler);
mappedTypeFound = true;
} catch (Throwable t) {
// maybe users define the TypeReference with a different type and are not assignable, so just ignore it
if (!mappedTypeFound) {
register((Class&T&) null, typeHandler);
* 配置了typeHandlerhe和javaType
public &T& void register(Class&T& javaType, TypeHandler&? extends T& typeHandler) {
register((Type) javaType, typeHandler);
private &T& void register(Type javaType, TypeHandler&? extends T& typeHandler) {
//扫描注解MappedJdbcTypes
MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class);
if (mappedJdbcTypes != null) {
for (JdbcType handledJdbcType : mappedJdbcTypes.value()) {
register(javaType, handledJdbcType, typeHandler);
if (mappedJdbcTypes.includeNullJdbcType()) {
register(javaType, null, typeHandler);
register(javaType, null, typeHandler);
public &T& void register(TypeReference&T& javaTypeReference, TypeHandler&? extends T& handler) {
register(javaTypeReference.getRawType(), handler);
* typeHandlerhe、javaType、jdbcType都配置了
public &T& void register(Class&T& type, JdbcType jdbcType, TypeHandler&? extends T& handler) {
register((Type) type, jdbcType, handler);
* 注册typeHandler的核心方法
* 就是向Map新增数据而已
private void register(Type javaType, JdbcType jdbcType, TypeHandler&?& handler) {
if (javaType != null) {
Map&JdbcType, TypeHandler&?&& map = TYPE_HANDLER_MAP.get(javaType);
if (map == null) {
map = new HashMap&JdbcType, TypeHandler&?&&();
TYPE_HANDLER_MAP.put(javaType, map);
map.put(jdbcType, handler);
if (reversePrimitiveMap.containsKey(javaType)) {
register(reversePrimitiveMap.get(javaType), jdbcType, handler);
ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
// REGISTER CLASS
// Only handler type
public void register(Class&?& typeHandlerClass) {
boolean mappedTypeFound = false;
MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
if (mappedTypes != null) {
for (Class&?& javaTypeClass : mappedTypes.value()) {
register(javaTypeClass, typeHandlerClass);
mappedTypeFound = true;
if (!mappedTypeFound) {
register(getInstance(null, typeHandlerClass));
// java type + handler type
public void register(Class&?& javaTypeClass, Class&?& typeHandlerClass) {
register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass));
// java type + jdbc type + handler type
public void register(Class&?& javaTypeClass, JdbcType jdbcType, Class&?& typeHandlerClass) {
register(javaTypeClass, jdbcType, getInstance(javaTypeClass, typeHandlerClass));
// Construct a handler (used also from Builders)
@SuppressWarnings("unchecked")
public &T& TypeHandler&T& getInstance(Class&?& javaTypeClass, Class&?& typeHandlerClass) {
if (javaTypeClass != null) {
Constructor&?& c = typeHandlerClass.getConstructor(Class.class);
return (TypeHandler&T&) c.newInstance(javaTypeClass);
} catch (NoSuchMethodException ignored) {
// ignored
} catch (Exception e) {
throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e);
Constructor&?& c = typeHandlerClass.getConstructor();
return (TypeHandler&T&) c.newInstance();
} catch (Exception e) {
throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e);
* 根据指定的pacakge去扫描自定义的typeHander,然后注册
public void register(String packageName) {
ResolverUtil&Class&?&& resolverUtil = new ResolverUtil&Class&?&&();
resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
Set&Class&? extends Class&?&&& handlerSet = resolverUtil.getClasses();
for (Class&?& type : handlerSet) {
//Ignore inner classes and interfaces (including package-info.java) and abstract classes
if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
register(type);
// get information
* 通过configuration对象可以获取已注册的所有typeHandler
public Collection&TypeHandler&?&& getTypeHandlers() {
return Collections.unmodifiableCollection(ALL_TYPE_HANDLERS_MAP.values());
由源码可以看到, mybatis为我们实现了那么多TypeHandler, &随便打开一个TypeHandler,看其源码,都可以看到,它继承自一个抽象类:BaseTypeHandler, 那么我们是不是也能通过继承BaseTypeHandler,从而实现自定义的TypeHandler ? 答案是肯定的, 那么现在下面就为大家演示一下自定义TypeHandler:
=====================================================自定义TypeHandler分割线============================================================
ExampleTypeHandler:
@MappedJdbcTypes(JdbcType.VARCHAR)
//此处如果不用注解指定jdbcType, 那么,就可以在配置文件中通过"jdbcType"属性指定, 同理, javaType 也可通过 @MappedTypes指定
public class ExampleTypeHandler extends BaseTypeHandler&String& {
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter);
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getString(columnName);
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getString(columnIndex);
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getString(columnIndex);
然后,就该配置我们的自定义TypeHandler了:
&configuration&
&typeHandlers&
&!-- 由于自定义的TypeHandler在定义时已经通过注解指定了jdbcType, 所以此处不用再配置jdbcType --&
&typeHandler handler="ExampleTypeHandler"/&
&/typeHandlers&
&/configuration&
也就是说,我们在自定义TypeHandler的时候,可以在TypeHandler通过@MappedJdbcTypes指定jdbcType, 通过 @MappedTypes&指定javaType, 如果没有使用注解指定,那么我们就需要在配置文件中配置。
好啦,本篇文章到此结束。原文链接:
阅读排行榜mybatis自定义typeHandler映射对象为JSON
我的图书馆
mybatis自定义typeHandler映射对象为JSON
mybatis自定义typeHandler映射对象为JSON&& 17:12:43|&&分类:&字号&一个domain对象不可避免的会出现List、Map类型的字段,或者将多个字段拼装到一个字段的情况。前者存在是业务及设计的需求,后者出现是当初设计数据库没有考虑那么多字段,业务快速发展时需要增加字段,数据库数据量大时,添加一个字段非常耗时,有可能中断服务。为保证服务的可用性,及减少数据订正麻烦,应对频繁的业务变更,会把几个字段拼接到一个字段中。&这些字段在domain对象中往往采用下面的方式进行处理:解析字段成需要的类型,拼接多个字段填充成一个字段。操作过程类似下面的代码:public class User implements Serializable{ private static final long serialVersionUID = -1648924L; private List&String& hobbys;
//存储hobbys private String hobbyExt; private String ext1; private String ext2; private String ext3;
//存储ext1 、 ext2、 ext3 的信息 private String extInfo; public String getExtInfo() {
return extInfo; } public void setExtInfo(String extInfo) {
this.extInfo = extInfo; } public String getExt1() {
return ext1; } public void setExt1(String ext1) {
this.ext1 = ext1; } public String getExt2() {
return ext2; } public void setExt2(String ext2) {
this.ext2 = ext2; } public String getExt3() {
return ext3; } public void setExt3(String ext3) {
this.ext3 = ext3; } public List&String&
getHobbys(){
this.parseInfo();
return hobbys; } public void parseInfo() {
解析字段hobbyExt 成hobbys, 将extInfo解析成ext1、ext2、ext3
} public void fillExtendInfo(){
//TODO 将List hobbys拼装成一个字符串,ext1、ext2、ext3拼接成一个字符串 } public String getHobbyExt() {
return hobbyExt; } public void setHobbyExt(String hobbyExt) {
this.hobbyExt = hobbyExt; } public void setHobbys(List&String& hobbys) {
this.hobbys = hobbys; }}这样处理操作繁琐,程序进行存取时要注意解析及填充操作,如果一旦忽略或误用了某个操作,会导致数据库中某个信息没被填充进去,或者产生一些脏数据,极易引入潜在的bug。& & & &领一种解决解决方法是将解析及填充操作放到DO对象的set及get方法中,类似下面的代码:public List&String&
getHobbys(){
this.parseInfo();
return hobbys; }& & & & 这种处理方式会导致每次存取该字段时都要进行解析操作,增加了不必要的性能开销。不同程序员对不同domain对象定义难以想用,这种解析操作无法共用。如果要增加附加字段,需修改原有的解析方法,又增加了引入bug的风险。这种拼接,解析操作也减低了程序的易读性,导致可维护性降低。如何避免这种拼接及解析的操作,创建一个干净的domain对象呢?下面是一个干净的domain对象及其对应的ibatis的的映射文件配置:UserDO 对象://UserDO
对象public class UserDO implements Serializable {
private static final long serialVersionUID = 361819L;
private int id;
private String name;
private UserExtDO extDO;
private List&String& hobbys ;
private Map&String,String& votes;
public Map&String, String& getVotes() {
return votes; } public void setVotes(Map&String, String& votes) {
this.votes = votes; } public void addHobby(String hobby){
if(hobbys == null){
hobbys = new ArrayList&String&();
hobbys.add(hobby);
public List&String& getHobbys() {
return hobbys; } public void setHobbys(List&String& hobbys) {
this.hobbys = hobbys; } 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; } public UserExtDO getExtDO() {
return extDO; } public void setExtDO(UserExtDO extDO) {
this.extDO = extDO; }}//其扩展字段的对象public class UserExtDO implements Serializable{ private static final long serialVersionUID = -4333314L; private String school; private List&String& loves; & public String getSchool() {
return school; } public void setSchool(String school) {
this.school = school; } public List&String& getLoves() {
return loves; } public void setLoves(List&String& loves) {
this.loves = loves; } public void addLove(String love){
if(loves == null){
loves = new ArrayList&String&();
loves.add(love); }}&UserDO 的ORM映射文件:&?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"&
namespace="UserDO"
type="UserDO" id="UserDO"
property="id" column="id"
property="name" column="name"
property="extDO" column="extDO"
type="UserDO" id="UserDO"
property="id"
property="name"
property="extDO"
id="selectAllUsers" resultType="UserDO"
select * from user
id="insertUser"
parameterType="UserDO"
insert into user(id, name, extDO, hobbys, votes)
values(#{id}, #{name}, #{extDO}, #{hobbys},
#{votes} );
id="mapTest" resultType="UserDO"
select * from user where votes like
#{keyword}
& & &查看UserDO映射文件,extDO字段是一个对象,程序中没有任何拼接代码,怎么能存到数据库中呢?数据库中该字段时什么类型呢?数据库中extDO的类型如下图:& & & &&& extDO字段是Text类型。 UserExtDO对象存储到一个text类型的字段上了,这是如何实现的呢? 这就要靠mybatis提供的自定义类型处理器功能了。&& & & &&&MyBatis 在预处理语句中设置一个参数,或从结果集中获取一个值时,会使用类型处理器typeHandler将获取的值以合适的方式转换成 Java 类型。数据库中的基本类型之所以能被mybatis转换成Java类型,是因为mybatis已经内置了这些类型的处理器,如下图是mybatis内置的部分处理器:&& & & & 除内置的类型处理器外,mybatis同时提供了类型处理器的扩展功能,允许程序自定类型处理器,或者替换内置的类型处理器。 自定义的类型处理器只需继承TypeHandler接口,然后在xml配置文件配置一下,或者用程序注册类型处理器,即可实现自定义处理器的功能。&& & & & UseExtDO及List、 Map字段只所以能直接存储到数据库中,就是采用自定义的类型处理器实现的。 在存储时,利用类型处理器将对象序列化成JSON字符串,存储到数据库的一个字段中,在取出时类型处理器将json数据进行解析,反序列化成对象。类型处理器代码如下:import java.sql.CallableStatement;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import org.apache.ibatis.type.JdbcType;import org.apache.ibatis.type.TypeHandler;import com.alibaba.fastjson.JSON;public class JSONHandler implements TypeHandler&Object& { /**
* json数据和类名的分隔符号
* */ private static final char SPLIT = '/';
public void setParameter(PreparedStatement ps, int i, Object parameter,
JdbcType jdbcType) throws SQLException {
if(parameter == null){
ps.setString(i, null);
String json = JSON.toJSONString(parameter);
= json + SPLIT + parameter.getClass().getName();
ps.setString(i, json); } public Object getResult(ResultSet rs, String columnName)
throws SQLException {
json = rs.getString(columnName);
jsonToObject(json); } public Object getResult(CallableStatement cs, int columnIndex)
throws SQLException {
json = cs.getString(columnIndex);
jsonToObject(json); } /**
* json 转换成对象
* */ private Object jsonToObject(String json){
if(json == null){
return null;
int index = json.lastIndexOf(SPLIT);
return null;
String key = json.substring(index + 1, json.length());
= json.substring(0, index);
Class&?& cls = null;
cls = Class.forName(key);
} catch (ClassNotFoundException e) {
throw new RuntimeException("序列化成json时找不到指定的类", e);
Object ob = JSON.parseObject(json, cls);
return ob; }}在ibatis.xml 文件增加如下配置:&
javaType="com.jianbai.learn.ibatis.domain.UserExtDO" jdbcType="TEXT"
handler="com.jianbai.learn.ibatis.handler.JSONHandler"
javaType="java.util.Map" jdbcType="TEXT"
handler="com.jianbai.learn.ibatis.handler.JSONHandler"
javaType="java.util.List" jdbcType="TEXT"
handler="com.jianbai.learn.ibatis.handler.JSONHandler"
或者通过程序注册类型处理器:&
Reader rd = Resources.getResourceAsReader("ibatis.xml");
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(rd);
Configuration cfg = sf.getConfiguration();
TypeHandlerRegistry tr = cfg.getTypeHandlerRegistry();
//程序注册,不然不起作用
tr.register(UserExtDO.class, new JSONHandler());
tr.register(List.class,
new JSONHandler());
tr.register(Map.class,
new JSONHandler());& & & & &这样既可把List、Map及对象当做基本类型进行存储。 &如果需要在UserExtDO 添加字段,则直接添加属性,设置普通的set和get方法既可,无需做拼接解析操作,并且mybatis配置及映射文件无需做任何变化,数据库也无需做任何变化。 减少字段也可以很方便的进行。业务开发人员无需在做任何字段的解析及拼接的操作,&极大增强了程序的扩展性,易读性,及维护性。& &实际数据库中存储形式如下:&& & & &当然你也可以将Java对象存储成其它形式,比如直接采用Java内置的序列化进行处理,存储成二进制的形式。  选用json主要出于通用性考虑,可视化的存储结果,便于对存储结果进行操作及扩展。相关资源:&&mybatis参考 & & & & & & & & & & & & & &: &&序列化JSON采用的库FastJSON &: &&&
TA的推荐TA的最新馆藏[转]&[转]&
喜欢该文的人也喜欢

我要回帖

更多关于 局部typehandler 配置 的文章

 

随机推荐