我目前正在使用Hibernate 3和Spring 3.0。我想迁移到Hibernate 4和Spring 3.2。我正在使用AbstractLobType
的子类来实现从InputStream
映射到数据库(MySQL LONGBLOB)的UserType:
import java.io.InputStream;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.HibernateException;
import org.springframework.jdbc.support.lob.LobCreator;
import org.springframework.jdbc.support.lob.LobHandler;
import org.springframework.orm.hibernate3.support.AbstractLobType;
public class BlobUserType extends AbstractLobType {
public int[] sqlTypes() {
return new int[] { Types.BLOB };
}
public Class returnedClass() {
return InputStream.class;
}
@Override
protected Object nullSafeGetInternal(ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
throws SQLException, HibernateException {
return lobHandler.getBlobAsBinaryStream(rs, names[0]);
}
@Override
protected void nullSafeSetInternal(PreparedStatement ps, int index, Object value, LobCreator lobCreator)
throws SQLException, HibernateException {
if (value != null) {
lobCreator.setBlobAsBinaryStream(ps, index, (InputStream) value, -1);
} else {
lobCreator.setBlobAsBytes(ps, index, null);
}
}
}
由于AbstractLobType
位于hibernate3
,我不应再使用它了,但替代方案是什么?
我在春季项目上看过this JIRA issue,但它根本没有帮助我。
这是hibernate映射:
<class name="SoundNotification" table="SoundNotification" entity-name="SoundNotificationWithData">
<id name="m_id" type="int" column="id" unsaved-value="-1">
<generator class="native"/>
</id>
<property name="m_name" column="name" unique="true" not-null="true"/>
<property name="m_data" column="data"
type="com.mycompany.server.common.service.persistence.impl.hibernate.usertype.BlobUserType"
not-null="true"/>
<property name="m_size" formula="OCTET_LENGTH(data)"/>
<property name="m_inUse"
formula="(select count(1) from EventTypeConfiguration etc where etc.soundNotification=id)"/>
</class>
Java类:
public class SoundNotification extends IntegerEntity
{
private String m_name;
private transient InputStream m_data;
private boolean m_inUse;
private long m_size;
// getters and setters ...
}
使用MaterializedBlobType更新:
我的TrafficMap.hbm.xml:
<class name="TrafficMapImage" table="TrafficMapImage" entity-name="TrafficMapImageWithData">
<id name="m_id" column="id" type="int" unsaved-value="-1">
<generator class="native"/>
</id>
<property name="m_created" column="created" type="org.jadira.usertype.dateandtime.joda.PersistentDateTime"
not-null="true"/>
<property name="m_image" column="image"
type="org.hibernate.type.MaterializedBlobType"
not-null="true"/>
<property name="m_type" column="type" not-null="true">
<type name="com.traficon.tmsng.server.common.service.persistence.impl.hibernate.usertype.EnumUserType">
<param name="enumClass">com.traficon.domain.map.TrafficMapImageType</param>
</type>
</property>
</class>
我的Spring上下文中的sessionFactory bean:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.hbm2ddl.auto=${hibernate.hbm2ddl.auto}
hibernate.show_sql=${hibernate.show_sql}
hibernate.jdbc.batch_size=50
hibernate.jdbc.use_streams_for_binary=true
hibernate.current_session_context_class=com.traficon.tmsng.server.common.spring.TransactionAwareSessionContext
</value>
</property>
<property name="mappingResources">
<list>
<value>hibernate/authentication.hbm.xml</value>
<value>hibernate/SystemPrefs.hbm.xml</value>
<value>hibernate/Detector.hbm.xml</value>
<value>hibernate/filters.hbm.xml</value>
<value>hibernate/EventTypeConfiguration.hbm.xml</value>
<value>hibernate/Scenario.hbm.xml</value>
<value>hibernate/RunningScenario.hbm.xml</value>
<value>hibernate/StorePoint.hbm.xml</value>
<value>hibernate/OfflineNetwork.hbm.xml</value>
<value>hibernate/Characteristics.hbm.xml</value>
<value>hibernate/EventType.hbm.xml</value>
<value>hibernate/EventStore.hbm.xml</value>
<value>hibernate/IntervalDataMessage.hbm.xml</value>
<value>hibernate/IntegrationPeriodConstraints.hbm.xml</value>
<value>hibernate/Media.hbm.xml</value>
<value>hibernate/TrafficMap.hbm.xml</value>
<value>hibernate/CommentLibrary.hbm.xml</value>
<value>hibernate/CommentHistory.hbm.xml</value>
<value>hibernate/Dashboard.hbm.xml</value>
</list>
</property>
<property name="entityInterceptor">
<bean class="com.traficon.tmsng.server.common.service.persistence.impl.hibernate.RollbackReintializerInterceptor"
scope="prototype"/>
</property>
</bean>
日志记录输出:
[WARNING] [talledLocalContainer] INFO: Initializing Spring root WebApplicationContext
[INFO] [talledLocalContainer] 13 Dec 2013 13:54:10,525 [main] INFO hibernate.annotations.common.Version - HCANN000001: Hibernate Commons Annotations {4.0.2.Final}
[INFO] [talledLocalContainer] 13 Dec 2013 13:54:10,537 [main] INFO org.hibernate.Version - HHH000412: Hibernate Core {4.2.7.Final}
[INFO] [talledLocalContainer] 13 Dec 2013 13:54:10,544 [main] INFO org.hibernate.cfg.Environment - HHH000205: Loaded properties from resource hibernate.properties: {hibernate.jdbc.use_streams_for_binary=true, hibernate.bytecode.use_reflection_optimizer=false}
[INFO] [talledLocalContainer] 13 Dec 2013 13:54:10,545 [main] INFO org.hibernate.cfg.Environment - HHH000407: Using java.io streams to persist binary types
[INFO] [talledLocalContainer] 13 Dec 2013 13:54:10,546 [main] INFO org.hibernate.cfg.Environment - HHH000021: Bytecode provider name : javassist
[INFO] [talledLocalContainer] 13 Dec 2013 13:54:12,302 [main] INFO org.hibernate.dialect.Dialect - HHH000400: Using dialect: org.hibernate.dialect.MySQL5InnoDBDialect
...
[INFO] [talledLocalContainer] 13 Dec 2013 14:06:12,136 [http-8080-4] INFO hibernate.event.internal.DefaultLoadEventListener - HHH000327: Error performing load command : org.hibernate.PropertyAccessException: could not set a field value by reflection setter of com.traficon.domain.map.TrafficMapImage.m_image
[WARNING] [talledLocalContainer] Dec 13, 2013 2:06:12 PM org.apache.catalina.core.StandardWrapperValve invoke
[WARNING] [talledLocalContainer] SEVERE: Servlet.service() for servlet mediaServlet threw exception
[WARNING] [talledLocalContainer] java.lang.IllegalArgumentException: Can not set java.io.InputStream field com.traficon.domain.map.TrafficMapImage.m_image to [B
[WARNING] [talledLocalContainer] at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
[WARNING] [talledLocalContainer] at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
[WARNING] [talledLocalContainer] at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
[WARNING] [talledLocalContainer] at java.lang.reflect.Field.set(Field.java:741)
[WARNING] [talledLocalContainer] at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:139)
[WARNING] [talledLocalContainer] at org.hibernate.tuple.entity.AbstractEntityTuplizer.setPropertyValues(AbstractEntityTuplizer.java:710)
[WARNING] [talledLocalContainer] at org.hibernate.tuple.entity.PojoEntityTuplizer.setPropertyValues(PojoEntityTuplizer.java:379)
[WARNING] [talledLocalContainer] at org.hibernate.persister.entity.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:4523)
[WARNING] [talledLocalContainer] at org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:186)
[WARNING] [talledLocalContainer] at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:137)
[WARNING] [talledLocalContainer] at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:1108)
[WARNING] [talledLocalContainer] at org.hibernate.loader.Loader.processResultSet(Loader.java:964)
[WARNING] [talledLocalContainer] at org.hibernate.loader.Loader.doQuery(Loader.java:911)
[WARNING] [talledLocalContainer] at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:342)
[WARNING] [talledLocalContainer] at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:312)
[WARNING] [talledLocalContainer] at org.hibernate.loader.Loader.loadEntity(Loader.java:2121)
[WARNING] [talledLocalContainer] at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:82)
[WARNING] [talledLocalContainer] at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:72)
[WARNING] [talledLocalContainer] at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3941)
[WARNING] [talledLocalContainer] at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:460)
[WARNING] [talledLocalContainer] at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:429)
[WARNING] [talledLocalContainer] at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:206)
[WARNING] [talledLocalContainer] at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:246)
[WARNING] [talledLocalContainer] at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:150)
[WARNING] [talledLocalContainer] at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1098)
[WARNING] [talledLocalContainer] at org.hibernate.internal.SessionImpl.access$2000(SessionImpl.java:175)
[WARNING] [talledLocalContainer] at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2482)
[WARNING] [talledLocalContainer] at org.hibernate.internal.SessionImpl.get(SessionImpl.java:998)
[WARNING] [talledLocalContainer] at com.traficon.tmsng.server.common.service.persistence.impl.hibernate.HibernateTrafficMapRepository.getTrafficMapImageWithData_aroundBody6(HibernateTrafficMapRepository.java:176)
[WARNING] [talledLocalContainer] at com.traficon.tmsng.server.common.service.persistence.impl.hibernate.HibernateTrafficMapRepository$AjcClosure7.run(HibernateTrafficMapRepository.java:1)
[WARNING] [talledLocalContainer] at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96cproceed(AbstractTransactionAspect.aj:59)
[WARNING] [talledLocalContainer] at org.springframework.transaction.aspectj.AbstractTransactionAspect$AbstractTransactionAspect$1.proceedWithInvocation(AbstractTransactionAspect.aj:65)
[WARNING] [talledLocalContainer] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
[WARNING] [talledLocalContainer] at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(AbstractTransactionAspect.aj:63)
[WARNING] [talledLocalContainer] at com.traficon.tmsng.server.common.service.persistence.impl.hibernate.HibernateTrafficMapRepository.getTrafficMapImageWithData(HibernateTrafficMapRepository.java:173)
[WARNING] [talledLocalContainer] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[WARNING] [talledLocalContainer] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
[WARNING] [talledLocalContainer] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[WARNING] [talledLocalContainer] at java.lang.reflect.Method.invoke(Method.java:606)
[WARNING] [talledLocalContainer] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
[WARNING] [talledLocalContainer] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
[WARNING] [talledLocalContainer] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
[WARNING] [talledLocalContainer] at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
[WARNING] [talledLocalContainer] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
[WARNING] [talledLocalContainer] at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91)
[WARNING] [talledLocalContainer] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
[WARNING] [talledLocalContainer] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
[WARNING] [talledLocalContainer] at com.sun.proxy.$Proxy39.getTrafficMapImageWithData(Unknown Source)
[WARNING] [talledLocalContainer] at com.traficon.tmsng.server.web.mvc.DownloadTrafficMapImageController.onSubmit(DownloadTrafficMapImageController.java:40)
[WARNING] [talledLocalContainer] at org.springframework.web.servlet.mvc.SimpleFormController.processFormSubmission(SimpleFormController.java:272)
[WARNING] [talledLocalContainer] at org.springframework.web.servlet.mvc.AbstractFormController.handleRequestInternal(AbstractFormController.java:268)
[WARNING] [talledLocalContainer] at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
[WARNING] [talledLocalContainer] at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
[WARNING] [talledLocalContainer] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
[WARNING] [talledLocalContainer] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
[WARNING] [talledLocalContainer] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
[WARNING] [talledLocalContainer] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
[WARNING] [talledLocalContainer] at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
[WARNING] [talledLocalContainer] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
[WARNING] [talledLocalContainer] at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
[WARNING] [talledLocalContainer] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
[WARNING] [talledLocalContainer] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
[WARNING] [talledLocalContainer] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
[WARNING] [talledLocalContainer] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
[WARNING] [talledLocalContainer] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
[WARNING] [talledLocalContainer] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
[WARNING] [talledLocalContainer] at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:568)
[WARNING] [talledLocalContainer] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
[WARNING] [talledLocalContainer] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
[WARNING] [talledLocalContainer] at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
[WARNING] [talledLocalContainer] at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
[WARNING] [talledLocalContainer] at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
[WARNING] [talledLocalContainer] at java.lang.Thread.run(Thread.java:744)
[WARNING] [talledLocalContainer]
答案 0 :(得分:0)
理论上,如果你想为你的Blob使用MaterializedBlobType
,你应该使用hibernate提供的InputStream
,然后将以下属性添加到你的hibernate配置
hibernate.jdbc.use_streams_for_binary=true
这将指示MaterializedBlobType
使用InputStream
代替byte[]
。
答案 1 :(得分:0)
我最终创建了自己的用户类型,可以在Blob和InputStream之间进行转换:
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;
import java.io.InputStream;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
public class BlobUserType implements UserType
{
// ------------------------ INTERFACE METHODS ------------------------
// --------------------- Interface UserType ---------------------
@Override
public int[] sqlTypes()
{
return new int[]{Types.BLOB};
}
@Override
public Class returnedClass()
{
return InputStream.class;
}
@Override
public boolean equals( Object x, Object y ) throws HibernateException
{
boolean result;
if (x == y)
{
result = true;
}
else if (x == null || y == null)
{
result = false;
}
else
{
result = x.equals( y );
}
return result;
}
@Override
public int hashCode( Object x ) throws HibernateException
{
return x.hashCode();
}
@Override
public Object nullSafeGet( ResultSet rs, String[] names, SessionImplementor session, Object owner ) throws HibernateException, SQLException
{
return rs.getBlob( names[0] ).getBinaryStream();
}
@Override
public void nullSafeSet( PreparedStatement st, Object value, int index, SessionImplementor session ) throws HibernateException, SQLException
{
if( value != null )
{
InputStream inputStream = (InputStream)value;
st.setBlob( index, inputStream );
}
else
{
st.setNull( index, Types.BLOB );
}
}
@Override
public Object deepCopy( Object value ) throws HibernateException
{
return value;
}
@Override
public boolean isMutable()
{
return false;
}
@Override
public Serializable disassemble( Object value ) throws HibernateException
{
return null;
}
@Override
public Object assemble( Serializable cached, Object owner ) throws HibernateException
{
return null;
}
@Override
public Object replace( Object original, Object target, Object owner ) throws HibernateException
{
return original;
}
}
似乎可以正常加载并将我的实体保存到数据库中。
答案 2 :(得分:0)
你不应该使用AbstractLobType,因为它正如你所说的那样在hibernate 3中。
您可以创建自己的UserType以在Blob和InputStream之间进行转换。但是,如果要将现有数据从Hibernate 3迁移到4,则代码将无法运行:
BlobSerializableType的格式还包含标题信息,如下所示:
¬ít{“userServices”:[{“accountStatus”:“PendingTermsAndConditions”,“serviceIdentifier”:“SNG”}] ...}]}
您的代码将工作(读取,写入)到没有标题的格式: { “userServices”:[{ “accountStatus”: “PendingTermsAndConditions”, “serviceIdentifier”: “SNG”}] ...}]}
我个人的解决方案是模拟Hibernate 3来编写和读取Blob数据,如下所示:
package com.newbay.acs.domain.hibernate;
import org.apache.commons.io.IOUtils;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
/**
* Created by qale0001 on 21/06/2016.
*/
public class CustomMaterializedBlobType implements UserType
{
private static final int OUTPUT_BYTE_ARRAY_INITIAL_SIZE = 1024;
@Override
public int[] sqlTypes()
{
return new int[]{Types.BLOB};
}
@Override
public Class returnedClass()
{
return String.class;
}
@Override
public boolean equals(Object x, Object y) throws HibernateException {
boolean result;
if (x == y)
{
result = true;
}
else if (x == null || y == null)
{
result = false;
}
else
{
result = x.equals( y );
}
return result;
}
@Override
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
java.sql.Blob blob = rs.getBlob( names[0] );
InputStream is = blob.getBinaryStream();
if (is != null) {
try {
ObjectInputStream ois = new ObjectInputStream(is);
try {
return ois.readObject();
} catch (ClassNotFoundException ex) {
throw new HibernateException("Could not deserialize BLOB contents", ex);
} finally {
ois.close();
}
} catch (IOException ex) {
throw new HibernateException("Could not deserialize BLOB contents", ex);
}
}
else {
return null;
}
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
if( value != null )
{
ByteArrayOutputStream baos = new ByteArrayOutputStream(OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
try {
ObjectOutputStream oos = new ObjectOutputStream(baos);
try {
oos.writeObject(value);
oos.flush();
InputStream is = new ByteArrayInputStream(baos.toByteArray());
st.setBlob(index, is);
}
finally {
oos.close();
}
} catch (IOException ex) {
throw new HibernateException("Could not serialize BLOB contents", ex);
}
}
else
{
st.setNull( index, Types.BLOB );
}
}
@Override
public Object deepCopy(Object value) throws HibernateException {
return value;
}
@Override
public boolean isMutable() {
return false;
}
@Override
public Serializable disassemble(Object value) throws HibernateException {
return null;
}
@Override
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return null;
}
@Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
}