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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 00:42:15  来源:igfitidea点击:

Array with UserType in Hibernate and PostgreSQL --> MappingException

javaarraysspringhibernatepostgresql

提问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 数组与 hibernateHibernate/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 getMethodand use it with reflection.

您需要从 jdbc-class 中获取底层函数。因此getMethod,通过反射获取并使用它。