Hibernate 和 PostgreSQL 中具有 UserType 的数组 --> MappingException
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14219498/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Array with UserType in Hibernate and PostgreSQL --> MappingException
提问by Alex
I am trying to write a class implementing UserType to deal with arrays in Hibernate/JPA. I used the following posts mapping a postgres array with hibernateand Hibernate/JPA/HSQL : How to create a Dialect mapping for User Type ARRAYto build a solution but I cannot get it to work. I created a new Spring Roo project just to test it. Here are the different files (all java classes are located in the package test):
我正在尝试编写一个实现 UserType 的类来处理 Hibernate/JPA 中的数组。我使用以下帖子 映射 postgres 数组与 hibernate和Hibernate/JPA/HSQL:How to create a Dialect mapping for User Type ARRAYto build a solution but I can't get it to work. 我创建了一个新的 Spring Roo 项目只是为了测试它。以下是不同的文件(所有 java 类都位于包 test 中):
persistence.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <!-- <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/> --> <property name="hibernate.dialect" value="test.PostgreSQLDialectArray"/> <!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database --> <property name="hibernate.hbm2ddl.auto" value="create"/> <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/> <property name="hibernate.connection.charSet" value="UTF-8"/> <!-- Uncomment the following two properties for JBoss only --> <!-- property name="hibernate.validator.apply_to_ddl" value="false" /--> <!-- property name="hibernate.validator.autoregister_listeners" value="false" /--> </properties> </persistence-unit> </persistence>
TestArray.java
package test; import java.math.BigInteger; import java.security.SecureRandom; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.roo.addon.javabean.RooJavaBean; import org.springframework.roo.addon.serializable.RooSerializable; import org.springframework.roo.addon.tostring.RooToString; @RooJavaBean @RooToString @RooSerializable public class TestArray { private static final long serialVersionUID = 1L; private SecureRandom random = new SecureRandom(); public String nextSessionId() { return new BigInteger(130, random).toString(32); } public static void main(String[] args) { ApplicationContext context; context = new ClassPathXmlApplicationContext("classpath:META-INF/spring/applicationContext.xml"); int[] array = new int[1428]; TestArray test = new TestArray(); Blabla blabla = new Blabla(); int nb = 1428; for(int i = 0 ; i < nb ; i++) array[i] = test.random.nextInt(); // blabla.setTest(array); // blabla.persist(); // System.out.println(Arrays.toString(blabla.getTest())); System.out.println(java.sql.Types.ARRAY); System.out.println("Done"); } }
Blabla.java
package test; import org.hibernate.annotations.Type; import org.springframework.roo.addon.entity.RooEntity; import org.springframework.roo.addon.javabean.RooJavaBean; import org.springframework.roo.addon.tostring.RooToString; @RooJavaBean @RooToString @RooEntity public class Blabla { @Type(type = "test.IntArrayUserType") private int[] array; }
PostgreSQLDialectArray
package test; import java.sql.Types; public class PostgreSQLDialectArray extends org.hibernate.dialect.PostgreSQLDialect{ public PostgreSQLDialectArray() { super(); registerHibernateType(Types.ARRAY, "array"); } }
IntArrayUserType.java (basically the same than in mapping a postgres array with hibernate)
package test; import java.io.Serializable; import java.sql.Array; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.hibernate.HibernateException; import org.hibernate.usertype.UserType; public class IntArrayUserType implements UserType { protected static final int SQLTYPE = java.sql.Types.ARRAY; private int[] toPrimitive(Integer[] array){ int[] a = new int[array.length]; for(int i = 0 ; i < array.length ; i++) a[i] = array[i]; return a; } private Integer[] toObject(int[] array){ Integer[] a = new Integer[array.length]; for(int i = 0 ; i < array.length ; i++) a[i] = array[i]; return a; } @Override public Object nullSafeGet(final ResultSet rs, final String[] names, final Object owner) throws HibernateException, SQLException { Array array = rs.getArray(names[0]); Integer[] javaArray = (Integer[]) array.getArray(); return toPrimitive(javaArray); } @Override public void nullSafeSet(final PreparedStatement statement, final Object object, final int i) throws HibernateException, SQLException { System.out.println("test null safe set..."); Connection connection = statement.getConnection(); int[] castObject = (int[]) object; Integer[] integers = toObject(castObject); Array array = connection.createArrayOf("integer", integers); statement.setArray(i, array); System.out.println("test null safe set..."); } @Override public Object assemble(final Serializable cached, final Object owner) throws HibernateException { return cached; } @Override public Object deepCopy(final Object o) throws HibernateException { return o == null ? null : ((int[]) o).clone(); } @Override public Serializable disassemble(final Object o) throws HibernateException { return (Serializable) o; } @Override public boolean equals(final Object x, final Object y) throws HibernateException { return x == null ? y == null : x.equals(y); } @Override public int hashCode(final Object o) throws HibernateException { return o == null ? 0 : o.hashCode(); } @Override public boolean isMutable() { return false; } @Override public Object replace(final Object original, final Object target, final Object owner) throws HibernateException { return original; } @Override public Class<int[]> returnedClass() { return int[].class; } @Override public int[] sqlTypes() { return new int[] { SQLTYPE }; } }
持久化文件
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <!-- <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/> --> <property name="hibernate.dialect" value="test.PostgreSQLDialectArray"/> <!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database --> <property name="hibernate.hbm2ddl.auto" value="create"/> <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/> <property name="hibernate.connection.charSet" value="UTF-8"/> <!-- Uncomment the following two properties for JBoss only --> <!-- property name="hibernate.validator.apply_to_ddl" value="false" /--> <!-- property name="hibernate.validator.autoregister_listeners" value="false" /--> </properties> </persistence-unit> </persistence>
测试数组
package test; import java.math.BigInteger; import java.security.SecureRandom; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.roo.addon.javabean.RooJavaBean; import org.springframework.roo.addon.serializable.RooSerializable; import org.springframework.roo.addon.tostring.RooToString; @RooJavaBean @RooToString @RooSerializable public class TestArray { private static final long serialVersionUID = 1L; private SecureRandom random = new SecureRandom(); public String nextSessionId() { return new BigInteger(130, random).toString(32); } public static void main(String[] args) { ApplicationContext context; context = new ClassPathXmlApplicationContext("classpath:META-INF/spring/applicationContext.xml"); int[] array = new int[1428]; TestArray test = new TestArray(); Blabla blabla = new Blabla(); int nb = 1428; for(int i = 0 ; i < nb ; i++) array[i] = test.random.nextInt(); // blabla.setTest(array); // blabla.persist(); // System.out.println(Arrays.toString(blabla.getTest())); System.out.println(java.sql.Types.ARRAY); System.out.println("Done"); } }
布拉布拉.java
package test; import org.hibernate.annotations.Type; import org.springframework.roo.addon.entity.RooEntity; import org.springframework.roo.addon.javabean.RooJavaBean; import org.springframework.roo.addon.tostring.RooToString; @RooJavaBean @RooToString @RooEntity public class Blabla { @Type(type = "test.IntArrayUserType") private int[] array; }
PostgreSQL方言数组
package test; import java.sql.Types; public class PostgreSQLDialectArray extends org.hibernate.dialect.PostgreSQLDialect{ public PostgreSQLDialectArray() { super(); registerHibernateType(Types.ARRAY, "array"); } }
IntArrayUserType.java(与使用 hibernate 映射 postgres 数组基本相同)
package test; import java.io.Serializable; import java.sql.Array; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.hibernate.HibernateException; import org.hibernate.usertype.UserType; public class IntArrayUserType implements UserType { protected static final int SQLTYPE = java.sql.Types.ARRAY; private int[] toPrimitive(Integer[] array){ int[] a = new int[array.length]; for(int i = 0 ; i < array.length ; i++) a[i] = array[i]; return a; } private Integer[] toObject(int[] array){ Integer[] a = new Integer[array.length]; for(int i = 0 ; i < array.length ; i++) a[i] = array[i]; return a; } @Override public Object nullSafeGet(final ResultSet rs, final String[] names, final Object owner) throws HibernateException, SQLException { Array array = rs.getArray(names[0]); Integer[] javaArray = (Integer[]) array.getArray(); return toPrimitive(javaArray); } @Override public void nullSafeSet(final PreparedStatement statement, final Object object, final int i) throws HibernateException, SQLException { System.out.println("test null safe set..."); Connection connection = statement.getConnection(); int[] castObject = (int[]) object; Integer[] integers = toObject(castObject); Array array = connection.createArrayOf("integer", integers); statement.setArray(i, array); System.out.println("test null safe set..."); } @Override public Object assemble(final Serializable cached, final Object owner) throws HibernateException { return cached; } @Override public Object deepCopy(final Object o) throws HibernateException { return o == null ? null : ((int[]) o).clone(); } @Override public Serializable disassemble(final Object o) throws HibernateException { return (Serializable) o; } @Override public boolean equals(final Object x, final Object y) throws HibernateException { return x == null ? y == null : x.equals(y); } @Override public int hashCode(final Object o) throws HibernateException { return o == null ? 0 : o.hashCode(); } @Override public boolean isMutable() { return false; } @Override public Object replace(final Object original, final Object target, final Object owner) throws HibernateException { return original; } @Override public Class<int[]> returnedClass() { return int[].class; } @Override public int[] sqlTypes() { return new int[] { SQLTYPE }; } }
And now the stacktrace:
现在是堆栈跟踪:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class path resource [META-INF/spring/applicationContext.xml]: Cannot resolve reference to bean 'entityManagerFactory' while setting bean property 'entityManagerFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [META-INF/spring/applicationContext.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: persistenceUnit] Unable to build EntityManagerFactory
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1325)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1086)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at test.TestArray.main(TestArray.java:29)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [META-INF/spring/applicationContext.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: persistenceUnit] Unable to build EntityManagerFactory
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:322)
... 15 more
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: persistenceUnit] Unable to build EntityManagerFactory
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:915)
at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:74)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:225)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:308)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
... 22 more
Caused by: org.hibernate.MappingException: No Dialect mapping for JDBC type: 2003
at org.hibernate.dialect.TypeNames.get(TypeNames.java:77)
at org.hibernate.dialect.TypeNames.get(TypeNames.java:100)
at org.hibernate.dialect.Dialect.getTypeName(Dialect.java:296)
at org.hibernate.mapping.Column.getSqlType(Column.java:208)
at org.hibernate.mapping.Table.sqlCreateString(Table.java:418)
at org.hibernate.cfg.Configuration.generateSchemaCreationScript(Configuration.java:1099)
at org.hibernate.tool.hbm2ddl.SchemaExport.<init>(SchemaExport.java:106)
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:372)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1872)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:906)
... 27 more
So I guess that the dialect that I created is not used at all or is wrong but I don't know why. I think that the @Type annotation should do the mapping but I have seen some tags but I do not know if they are needed in this example and if they are, where do I had them? It's been two days that I am stuck with this problem and I am getting desperate. Could you help me debug this program? Please. Thank you very much in advance.
所以我猜我创建的方言根本没有使用或者是错误的,但我不知道为什么。我认为 @Type 注释应该进行映射,但我已经看到了一些标签,但我不知道在这个例子中是否需要它们,如果它们是,我在哪里有它们?我被这个问题困住了两天,我越来越绝望了。你能帮我调试这个程序吗?请。非常感谢您提前。
Edit 0:
编辑0:
The persistence.xml file seem to find the correct dialect but the function getTypeName(2003) throws the errors above after doing registerHibernateType(Types.ARRAY, "array"). BTW, I am using Hibernate 3.6.4.Final and postgresql 8.4-702.jdbc3.
persistence.xml 文件似乎找到了正确的方言,但函数 getTypeName(2003) 在执行 registerHibernateType(Types.ARRAY, "array") 后抛出上述错误。顺便说一句,我正在使用 Hibernate 3.6.4.Final 和 postgresql 8.4-702.jdbc3。
Edit 1:
编辑1:
I added the following line to PostgreSQLDialectArray constructor:
我将以下行添加到 PostgreSQLDialectArray 构造函数:
registerColumnType(Types.ARRAY, "integer[$l]" );
which seems to partially solve the problem. However, now I get another error:
这似乎部分解决了问题。但是,现在我收到另一个错误:
2013-01-09 11:14:30,281 [main] ERROR org.hibernate.tool.hbm2ddl.SchemaExport - Unsuccessful: create table blabla (id int8 not null, array int[255], name varchar(255), test int4 not null, version int4, primary key (id))
2013-01-09 11:14:30,282 [main] ERROR org.hibernate.tool.hbm2ddl.SchemaExport - ERREUR: erreur de syntaxe sur ou près de ? array ?
Position: 40
Apparently, hibernate still does not know how to create a table with an array in it...
显然,hibernate 仍然不知道如何创建一个包含数组的表......
Edit 2:
编辑2:
It seems that postgresql didn't like the fact that my column was called "array". I change that and it worked. The table is created by hibernate with an array of integer.
似乎 postgresql 不喜欢我的专栏被称为“数组”这一事实。我改变了它,它奏效了。该表是由 hibernate 使用整数数组创建的。
BUT I cannot save any array in it with hibernate because of a problem in the UserType implementation. Apparently, the creation of the array fails with createArrayOf. I am reading some threads on this matter telling to access the underlying connection instead of the wrapper. I think I am going to open a new thread linking to this one because this problem is quite different.
但是由于 UserType 实现中的问题,我无法使用 hibernate 在其中保存任何数组。显然,数组的创建因 createArrayOf 而失败。我正在阅读关于这个问题的一些线程,告诉访问底层连接而不是包装器。我想我要打开一个链接到这个的新线程,因为这个问题完全不同。
The stacktrace:
堆栈跟踪:
Exception in thread "main" java.lang.AbstractMethodError: org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.createArrayOf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/sql/Array;
at test.IntArrayUserType.nullSafeSet(IntArrayUserType.java:59)
at org.hibernate.type.CustomType.nullSafeSet(CustomType.java:140)
at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2184)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2430)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2874)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:76)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:467)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$afterReturning$org_springframework_transaction_aspectj_AbstractTransactionAspecta73e96c(AbstractTransactionAspect.aj:78)
at test.Blabla_Roo_Entity.ajc$interMethod$test_Blabla_Roo_Entity$test_Blabla$persist(Blabla_Roo_Entity.aj:56)
at test.Blabla.persist(Blabla.java:1)
at test.Blabla_Roo_Entity.ajc$interMethodDispatch1$test_Blabla_Roo_Entity$test_Blabla$persist(Blabla_Roo_Entity.aj)
at test.TestArray.main(TestArray.java:39)
Edit 3:
编辑3:
Finally, after the following modifications, the UserType for integer arrays works:
最后,经过以下修改后,整数数组的 UserType 起作用了:
Add this line in applicationContext.xml in:
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
....
<property name="accessToUnderlyingConnectionAllowed" value="true" />
</bean>
Modify the nullSafeSet from IntArrayUserType
@Override public void nullSafeSet(final PreparedStatement statement, final Object object, final int i) throws HibernateException, SQLException { Connection connection = statement.getConnection(); int[] castObject = (int[]) object; Integer[] integers = toObject(castObject); Connection conn = ((DelegatingConnection) connection).getInnermostDelegate(); Array array = conn.createArrayOf("integer", integers); statement.setArray(i, array); }
在 applicationContext.xml 中添加这一行:
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
....
<property name="accessToUnderlyingConnectionAllowed" value="true" />
</bean>
从 IntArrayUserType 修改 nullSafeSet
@Override public void nullSafeSet(final PreparedStatement statement, final Object object, final int i) throws HibernateException, SQLException { Connection connection = statement.getConnection(); int[] castObject = (int[]) object; Integer[] integers = toObject(castObject); Connection conn = ((DelegatingConnection) connection).getInnermostDelegate(); Array array = conn.createArrayOf("integer", integers); statement.setArray(i, array); }
BUT there is still a problem when getting all the entries from the table blabla: The function findAllBlablas does not work properly and only returns the first entry...
但是从表 blabla 中获取所有条目时仍然存在问题:函数 findAllBlablas 无法正常工作,仅返回第一个条目...
Edit 4:
编辑4:
In fact, it worked great but the eclipse console was not able to print all data. That's all!
事实上,它工作得很好,但 eclipse 控制台无法打印所有数据。就这样!
回答by borchvm
__________ HibernateSessionFactory.xml ___________________________
<property name="hibernateProperties">
<props>
<!-- <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop> -->
<prop key="hibernate.dialect">com.test.model.PostgreSQLDialectArray</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.generate_statistics">false</prop>
<prop key="hibernate.connection.pool_size">10</prop>
<prop key="hibernate.archive.autodetection">class</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
</props>
</property>
______________ PostgreSQLDialectArray.java _______________________
package com.test.model;
import java.sql.Types;
public class PostgreSQLDialectArray extends org.hibernate.dialect.PostgreSQL82Dialect{
public PostgreSQLDialectArray() {
super();
System.out.println("Register Hibernate Type ... ");
registerHibernateType(Types.ARRAY, "array");
System.out.println("Register Column Type ... ");
registerColumnType(Types.ARRAY, "integer[]");
}
}
_____________ CustomArrayType.java ______________________________
package com.test.model;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.sql.Array;
import org.hibernate.*;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;
public class CustomArrayType implements UserType
{
protected static final int SQLTYPE = java.sql.Types.ARRAY;
private int[] toPrimitive(Integer[] array){
int[] a = new int[array.length];
for(int i = 0 ; i < array.length ; i++)
a[i] = array[i];
return a;
}
private Integer[] toObject(int[] array){
Integer[] a = new Integer[array.length];
for(int i = 0 ; i < array.length ; i++)
a[i] = array[i];
return a;
}
@Override
public Object nullSafeGet(final ResultSet rs, final String[] names, SessionImplementor session, final Object owner) throws HibernateException, SQLException {
Array array = rs.getArray(names[0]);
Integer[] javaArray = (Integer[]) array.getArray();
return toPrimitive(javaArray);
}
@Override
public void nullSafeSet(final PreparedStatement statement, final Object object, final int i, SessionImplementor session) throws HibernateException, SQLException {
System.out.println("test null safe set...");
Connection connection = statement.getConnection();
int[] castObject = (int[]) object;
Integer[] integers = toObject(castObject);
Array array = connection.createArrayOf("integer", integers);
statement.setArray(i, array);
System.out.println("test null safe set...");
}
@Override
public Object assemble(final Serializable cached, final Object owner) throws HibernateException {
return cached;
}
@Override
public Object deepCopy(final Object o) throws HibernateException {
return o == null ? null : ((int[]) o).clone();
}
@Override
public Serializable disassemble(final Object o) throws HibernateException {
return (Serializable) o;
}
@Override
public boolean equals(final Object x, final Object y) throws HibernateException {
return x == null ? y == null : x.equals(y);
}
@Override
public int hashCode(final Object o) throws HibernateException {
return o == null ? 0 : o.hashCode();
}
@Override
public boolean isMutable() {
return false;
}
@Override
public Object replace(final Object original, final Object target, final Object owner) throws HibernateException {
return original;
}
@Override
public Class<int[]> returnedClass() {
return int[].class;
}
@Override
public int[] sqlTypes() {
return new int[] { SQLTYPE };
}
}
____________ MyClass.java ___________________________
package com.test.model;
import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializable;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Date;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Type;
@Entity
@Table(name = "MyClass")
public class MyClass implements Serializable {
private static final long serialVersionUID = -2520209406925143850L;
@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;
@Type(type = "com.test.model.CustomArrayType")
@Column(name = "arrayDay", nullable = true)
private int[] arrayDay;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public int[] getArrayDay() {
return arrayDay;
}
public void setArrayDay(int[] arrayDay) {
this.arrayDay = arrayDay;
}
}
______________ ArrayTypeTests.java ___________________________
package com.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.test.model.MyClass;
import com.test.service.MyClassService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:application-context.xml" })
public class ArrayTypeTests implements ApplicationContextAware {
@Autowired
private MyClassService myClassService;
public static ApplicationContext ctx;
@Test
public void test_() {
System.out.println("Test junit");
}
@Test
public void test_arrayDays() {
System.out.println("\n - Start test_array - ");
MyClass myClass = myClassService.getMyClassById(1L);
if (myClass != null) {
int[] array = myClass.getArrayDay();
System.out.println("\n valor1:" + array[0]);
System.out.println("\n valor2:" + array[1]);
System.out.println("\n\n test_array OK ");
} else {
System.out.println("\n ERROR");
}
System.out.println("\n - End test_array - ");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ctx = applicationContext;
}
}
回答by Rollozuh
Beside your solution in Edit 3, it works perfect when you don't use connection-pooling like dbcp or c3p0. - You are working with dbcp.
除了您在 Edit 3 中的解决方案之外,当您不使用像 dbcp 或 c3p0 这样的连接池时,它也能完美运行。- 您正在使用 dbcp。
A possible solution, when using c3p0 would be to use proxool. With this, there shouldn't be any problems, because proxool can handle createArrayOf()
.
使用 c3p0 时可能的解决方案是使用proxool。有了这个,应该不会有任何问题,因为 proxool 可以处理createArrayOf()
.
Another would be this:
另一个是这样的:
C3P0ProxyConnection connection = (C3P0ProxyConnection) _statement.getConnection();
Method method = Connection.class.getMethod("createArrayOf", new Class[] { String.class, Object[].class });
Array array = (Array) connection.rawConnectionOperation(
method, C3P0ProxyConnection.RAW_CONNECTION, new Object[] {"integer", intArray});
_statement.setArray(_i, array);
You need to get the underlying function from the jdbc-class. Therefor get it with getMethod
and use it with reflection.
您需要从 jdbc-class 中获取底层函数。因此getMethod
,通过反射获取并使用它。