转载自:http://www.wangwenhui.com.cn/archives/82
项目现在换成hibernate5后,在原先使用Spring的ClobStringType类型进行String与Clob对应时,无法使用,直接是报空指针异常,经过对Spring源码分析后,发现,ClobStringType是Spring基于hibernate3给出的解决方案,无法支持到hibernate5了,针对这一问题,我参考Spring 的ClobStringType类,自己封装了一个自己的ClobStringType类。下面给出封装的过程,希望对大家能有帮助。
1、先写一个类,继承Hibernate的UserType接口,实现相关的方法,具体如下:
package
com.platform.base.usertype;
import
java.io.Serializable;
import
java.sql.Clob;
import
java.sql.PreparedStatement;
import
java.sql.ResultSet;
import
java.sql.SQLException;
import
java.sql.Types;
import
org.hibernate.HibernateException;
import
org.hibernate.engine.spi.SessionImplementor;
import
org.hibernate.internal.util.compare.EqualsHelper;
import
org.hibernate.usertype.UserType;
import
org.springframework.jdbc.support.lob.LobHandler;
import
com.platform.common.SpringContextHolder;
/**
* www.wangwenhui.com.cn
* @ClassName:PtClobTypeString
* @Description:TODO(实现hibernate中,java String 类对数据库Clob的直接支持类)
* @Author:王文辉
* @Date:2016年4月11日
*/
public
class
PtClobTypeString
implements
UserType, Serializable {
@Override
public
int
[] sqlTypes() {
return
new
int
[] { Types.CLOB };
}
@Override
public
Class returnedClass() {
return
String.
class
;
}
@Override
public
boolean
equals(Object x, Object y)
throws
HibernateException {
return
EqualsHelper.equals(x, y);
}
@Override
public
int
hashCode(Object x)
throws
HibernateException {
// TODO Auto-generated method stub
return
x.hashCode();
}
@Override
public
Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
throws
HibernateException, SQLException {
if
(
null
!= names && names.length >
0
) {
LobHandler lobHandler = getCurrentLobHandler(session);
return
lobHandler.getClobAsString(rs, names[
0
]);
}
return
""
;
}
@Override
public
void
nullSafeSet(PreparedStatement st, Object value,
int
index, SessionImplementor session)
throws
HibernateException, SQLException {
LobHandler lobHandler = getCurrentLobHandler(session);
lobHandler.getLobCreator().setClobAsString(st, index, (String) value);
}
@Override
public
Object deepCopy(Object value)
throws
HibernateException {
return
value;
}
@Override
public
boolean
isMutable() {
// TODO Auto-generated method stub
return
false
;
}
@Override
public
Serializable disassemble(Object value)
throws
HibernateException {
return
(Serializable) value;
}
@Override
public
Object assemble(Serializable cached, Object owner)
throws
HibernateException {
return
cached;
}
@Override
public
Object replace(Object original, Object target, Object owner)
throws
HibernateException {
return
original;
}
private
LobHandler getCurrentLobHandler(SessionImplementor session) {
String dialect = session.getFactory().getDialect().getClass().getName();
if
(
null
!= dialect && dialect.toLowerCase().contains(
"oracle"
)) {
return
SpringContextHolder.getBean(
"oracleLobHandler"
);
}
return
SpringContextHolder.getBean(
"defaultLobHandler"
);
}
}
主要需要实现的方法有两个,一个是,nullSafeGet,用于把clob转换为String类型的实现;另一个是:nullSafeSet,用于把String转换为Clob类型。具体可以根据不同数据库的方法,实现自己的转换函数。我这里使用的还是Spring 的LobHandler这个借口进行转换。
2、配置LobHandler接口,通过spring bean的配置,把LobHandler的两个实现分别注入到Spring 容器中,然后再在上面列出的,根据不同的数据库获取不同的实现进行转换即可。代码如下:
<
bean
id
=
"nativeJdbcExtractor"
lazy-init
=
"true"
class
=
"org.springframework.jdbc.support.nativejdbc.C3P0NativeJdbcExtractor"
/>
<
bean
id
=
"oracleLobHandler"
class
=
"org.springframework.jdbc.support.lob.OracleLobHandler"
lazy-init
=
"true"
>
<
property
name
=
"nativeJdbcExtractor"
>
<
ref
bean
=
"nativeJdbcExtractor"
/>
property
>
bean
>
<
bean
id
=
"defaultLobHandler"
class
=
"org.springframework.jdbc.support.lob.DefaultLobHandler"
lazy-init
=
"true"
>
3、把我们定义的PtClobTypeString注册成全局定义,如下代码所示:
@TypeDefs
({
@TypeDef
(name =
"ptclobstring"
, typeClass = PtClobTypeString.
class
) })
4、hibernate 实体bean的配置使用方式如下:
/**
* www.wangwenhui.com.cn
*/
@Lob
@Type
(type=
"ptclobstring"
)
@Column
(name =
"plugin_options"
)
private
String pluginOptions;
附Spring管理bean:
package com.supermap.sgis.util; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出ApplicaitonContext. * */ public class SpringContextHolder implements ApplicationContextAware { private static ApplicationContext applicationContext; /** * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量. */ public void setApplicationContext(ApplicationContext applicationContext) { SpringContextHolder.applicationContext = applicationContext; // NOSONAR } /** * 取得存储在静态变量中的ApplicationContext. */ public static ApplicationContext getApplicationContext() { checkApplicationContext(); return applicationContext; } /** * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型. */ @SuppressWarnings("unchecked") public static <T> T getBean(String name) { checkApplicationContext(); return (T) applicationContext.getBean(name); } /** * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型. */ @SuppressWarnings("unchecked") public static <T> T getBean(Class<T> clazz) { checkApplicationContext(); return (T) applicationContext.getBeansOfType(clazz); } /** * 清除applicationContext静态变量. */ public static void cleanApplicationContext() { applicationContext = null; } private static void checkApplicationContext() { if (applicationContext == null) { throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder"); } } }