postgresql - 如何从 EJB3 扩展持久性上下文访问 @Lob 字段

标签 postgresql jakarta-ee ejb-3.0 jpa-2.0 blob

我们正在 JaveEE6 中开发一个项目,使用 EJB3 bean 和 JPA2 注释。

我们有一些有状态的 EJB3 bean,它们使用扩展的持久性上下文,以便将数据库实体显示在前面(通过一些接口(interface),消除对 DTO 的需要)。

典型的用法是这样的:

  • 所有方法都没有事务,因为我们不想立即提交用户修改
  • 通过非事务性方法,我们正在加载附加到扩展上下文的实体
  • 只有一个保存方法是事务性的:在检查用户数据后,实体将被提交并保存在数据库中。

使用 MySQL 数据库,一切正常。

唉,在 Postgres 上,在非事务方法中加载的 @Lob 字段出现问题。 JDBC 似乎禁止 Lob 访问外部事务,抛出: org.hibernate.exception.GenericJDBCException:大对象不能用于自动提交模式


作为 stackoverflower pointed ,一个Lob可以在多个记录中,所以需要一个事务来保持一致性。

persistence.xml 中将 autocommit 设置为 true 根本不起作用,而且 should not be done .

我不能使该方法具有事务性,因为我们不想在调用结束时提交任何内容。那么,有人知道我怎样才能简单地访问 Lob 吗?

我们设想的黑客解决方案是将 Lob 移动到另一个实体中,然后添加一个读取 Lob 内容的事务方法,以便我们可以使用它。我觉得很脏...

最佳答案

您的印象似乎是,对 JPA 上下文中加载的实体所做的更改会自动提交,除非实体已分离。 事实并非如此 显然它是如何工作的。但是,即使您修改附加实体并刷新,或者合并分离的实体,rollback 也会确保更改1 对其他事务永远不可见。

在执行只读操作时打开事务是无害的 - 而且通常是保持一致性的好主意,只要你不让它打开太久 2。如果你想保证没有数据被写入并且你正在使用 JTA,只需在 SessionContext 上使用 setRollbackOnly() 来确保这一点。对于手动 JPA 事务管理,只需确保在完成后调用 EntityTransaction 上的 rollback(),而不是提交。

我个人建议在您的“getLob”方法中使用一个新事务,并在该方法结束时将其回滚。如果您的数据库不支持嵌套事务(很少支持),这通常会导致从池中获取新连接以执行此工作。

如果您正在使用 JTA 和容器管理的事务,请尝试:

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class LobTest {

    @PersistenceContext
    private EntityManager em;

    @Resource 
    private SessionContext sctx;

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public byte[] getLob() {
        // Get your LOB content by fetching a new copy of the entity from the DB
        // by ID, avoiding the need to split the LOB out. Note that you lose
        // tx consistency guarantees between the LOB and the rest of the entity by
        // doing this.
        // then after loading the LOB:
        sctx.setRollbackOnly();
    }

}

或者,如果您不介意读取 LOB 中止任何周围事务的错误,请使用 TransactionAttributeType.REQUIRES 而不是 REQUIRES_NEW 并且不要 setRollbackOnly ()。您无法更改任何内容,因此不会提交任何内容。如果一个事务尚未打开,它将打开一个新事务,否则将加入现有事务,因此您可以获得对 LOB 的一致读取。唯一的缺点是一些数据库错误会中止整个 JTA 事务。

如果您在非 JTA 环境中使用用户管理的事务,只需获取一个新的 EntityManager,获取一个 EntityTransaction,使用 em.find(...) 加载新的 EntityManager 副本LOB包含实体等


1。好的,所以在大多数数据库中都有一些事务豁免对象类型,例如 PostgreSQL SEQUENCE 和相关的 SERIAL 伪类型、咨询锁等甚至会受到影响通过回滚的事务。事务还可以在持有资源锁的意义上“写入”数据库,这也可能会阻止其他操作。对于实际的数据,它是安全的。

2。如果可以的话,请避免让 tx 打开超过几秒钟,因为长时间运行的事务会导致某些数据库出现性能问题,并且它们会占用连接池。避免在“用户思考时间”(您等待用户做某事的时间)内保持交易开放,他们可能会去做白日梦、去吃午饭、去度假或去月球……离开你的穷人等待返回的数据库和连接池。

关于postgresql - 如何从 EJB3 扩展持久性上下文访问 @Lob 字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11582149/

相关文章:

java - 使用 ORMLite 时出现死锁

java - javax.ejb.SessionSynchronization 和 javax.transaction.Synchronization 之间的区别

java - 计算 Java EE 网络应用程序中用户数量的最佳方法

java - 我们可以在JDK 1.4中使用EJB(3.0)吗

java - 调用 entityManager.getTransaction() 时出现 EJBException

python - 如何将 Select * Postgres/Redshift 查询结果放入字典(列/值)

用于将列值分组到列中的 PostgreSQL 查询

postgresql - 串行(自动递增)主键的标签

来自 .net 客户端的 java web 服务

spring - 使用命令行(maven、Tomcat、spring、hibernate)从头开始创建 JEE 项目