我们正在 JaveEE6 中开发一个项目,使用 EJB3 bean 和 JPA2 注释。
我们有一些有状态的 EJB3 bean,它们使用 扩展持久性上下文 以便将数据库实体显示在前面(通过一些接口(interface),消除对 DTO 的需要)。
典型的用途是这样的:
使用 MySQL 数据库,一切正常。
唉,在 Postgres 上,在非事务方法中加载的
@Lob
字段会出现问题。 JDBC 似乎禁止 Lob 访问外部事务,抛出:org.hibernate.exception.GenericJDBCException: Large Objects may not be used in auto-commit mode
作为 stackoverflower pointed ,一个 Lob 可以在多条记录中,所以需要一个事务来保持一致性。
在
autocommit
中将 persistence.xml
设置为 true 根本不起作用,还有 should not be done 。我不能使方法具有事务性,因为我们不想在调用结束时提交任何内容。那么,有谁知道我怎样才能简单地访问 Lob?
我们想象的一个 hack 解决方案是将 Lob 移动到另一个实体中,然后添加一个读取 Lob 内容的事务方法,以便我们可以使用它。我觉得挺脏的...
最佳答案
您似乎认为对在 JPA 上下文中加载的实体所做的更改会自动提交,除非实体被分离。事实并非如此,它显然是如何工作的。但是,即使您修改附加实体并刷新,或者合并分离的实体,rollback
也可确保其他事务永远不会看到更改。
在执行只读操作时打开事务是无害的——而且通常是保持一致性的好主意,只要你不要让它保持打开太长时间2。如果你想保证没有数据被写入并且你正在使用 JTA,只需在 setRollbackOnly()
上使用 SessionContext
来确保它。对于手动 JPA 事务管理,只需确保在完成后在 rollback()
上调用 EntityTransaction
,而不是提交。
我个人建议在“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(...)
加载包含实体的 LOB 的新副本等。1. 好的,所以在大多数数据库中都有一些事务豁免对象类型,例如 PostgreSQL
SEQUENCE
s 和相关的 SERIAL
伪类型、咨询锁等,甚至会受到回滚事务的影响。事务也可以“写入”数据库,因为它持有资源锁,这也可能阻止其他操作。对于实际数据,它是安全的。2. 如果可以的话,尽量避免让 tx 保持打开状态超过几秒钟,因为长时间运行的事务会导致某些数据库出现性能问题,并且会占用连接池。避免在“用户思考时间”(您等待用户做某事的时间)保持交易开放,他们可能会去做白日梦,或者去吃午饭,或者去度假,或者去月球……留下你的穷人数据库和连接池等待它们的返回。
关于postgresql - 如何从 EJB3 扩展持久性上下文访问 @Lob 字段,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11582149/