PSQLException:大对象可能无法在自动提交模式下使用

时间:2016-07-28 22:22:12

标签: postgresql hibernate jpa wildfly

我正在使用WildFly 10,Java EE,JPA和Hibernate。最近我将我的应用程序从MySQL迁移到了PostgreSQL。使用MySQL时,我会使用以下方法将图像存储在我的实体中:

@Lob
@Basic(fetch = FetchType.LAZY)
private byte[] image;

这很好用,MySQL使用LONGBLOB来存储数据。

切换到PostgreSQL后,列类型为OID,并且在保留图像时收到此错误:

Caused by: org.postgresql.util.PSQLException: Large Objects may not be used in auto-commit mode.
at org.postgresql.largeobject.LargeObjectManager.createLO(LargeObjectManager.java:308)
at org.postgresql.largeobject.LargeObjectManager.createLO(LargeObjectManager.java:296)
at org.postgresql.jdbc.PgPreparedStatement.createBlob(PgPreparedStatement.java:1202)
at org.postgresql.jdbc.PgPreparedStatement.setBlob(PgPreparedStatement.java:1243)
at org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.setBlob(WrappedPreparedStatement.java:1157)
at org.hibernate.type.descriptor.sql.BlobTypeDescriptor$4$1.doBind(BlobTypeDescriptor.java:112)
at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:73)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:257)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:252)
at org.hibernate.type.AbstractSingleColumnStandardBasicType.nullSafeSet(AbstractSingleColumnStandardBasicType.java:39)
at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2598)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2883)
... 131 more

我以这种方式插入:

@PersistenceContext
EntityManager entityManager;

...

//Simple insert method...
this.entityManager.persist(entity);

这是我的persistence.xml

<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="MyApp" transaction-type="JTA">
        <jta-data-source>java:jboss/datasources/PostgreSQLDS</jta-data-source>
        <shared-cache-mode>DISABLE_SELECTIVE</shared-cache-mode>
        <properties>
            <property name="hibernate.enable_lazy_load_no_trans" value="true"/>
            <property name="hibernate.cache.use_second_level_cache"
                      value="true"/>
            <property name="hibernate.cache.use_query_cache" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

我已经查看了有关此异常的其他多个问题,但是我无法解决问题。

One suggestion创建一个实体,仅用于存储数据并与其使用@OneToOne关系,以便可以急切地获取存储数据的实体,但这并没有以任何方式改变结果

另一个建议是使用

禁用Hibernate的自动提交
<property name="hibernate.connection.autocommit" value="false"/>

......也没有做任何事。

我完全迷失了为什么这不起作用。看起来这似乎不是一个非常常见的例外,我觉得我正在接近以完全错误的方式存储图像数据的任务。我该怎么做才能解决这个问题,或者我该如何存储数据?

2 个答案:

答案 0 :(得分:2)

我不能告诉你这是如何在Hibernate中完成的,但是打开和读/写一个大对象必须在同一个数据库事务中发生。

禁用自动提交模式应该可以解决问题,也许你做错了。

但我可以建议您根本不使用大型物体吗? 通常使用bytea PostgreSQL数据类型要容易得多,后者可以包含最大1GB大小的数据。除非您以块的形式存储和检索数据,否则大型对象不会提供任何优势,我怀疑您无论如何都可以使用ORM充分利用大对象功能。

答案 1 :(得分:0)

我遇到了同样的问题,并通过更改JBOSS配置文件(standalone.xml或domain.xml)解决了该问题。

首先分析问题,我发现通过日志记录自动提交仍然是正确的

entityManager.unwrap(SessionImpl.class).connection().getAutoCommit()

我尝试将其设置为false

entityManager.unwrap(SessionImpl.class).connection().setAutoCommit(false)

但这会导致异常“您无法在托管事务中设置自动提交”。

研究发现this article的异常消息,该消息解释了为什么自动提交始终为真。

我们使用的数据源配置如下:

<datasource jta="true"  . . . >

问题在于,在JTA数据源中,自动提交设置始终为true,并且无法更改。 我将其更改为xa数据源,此问题不再发生。

<xa-datasource . . . .>

em.unwrap(SessionImpl.class).connection()。getAutoCommit()最终返回false。

要使其正常工作,我还必须在Postgres数据库的postgres.conf中将参数max_prepared_transaction设置为500,以允许多个数据库连接/连接池:

max_prepared_transactions = 500     # zero disables the feature