您似乎觉得对JPA上下文中加载的实体的更改会自动提交,除非该实体已分离。这是而不是,实际上它显然是如何工作的。但是,即使您修改附加实体并刷新,或者合并了分离的实体,也可以确保其他事务永远不会看到更改。
它是无害的 - 而且往往一致性是一个好主意 - 执行只读操作,当这么久有交易开放只要你不把它开得太久 。如果你想保证没有数据被写入,并且你正在使用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
和Don” t setRollbackOnly()
。你不能改变任何东西,所以没有什么会被提交。如果尚未打开,它将打开一个新事务,否则将加入现有事务,以便您可以一致地读取LOB。唯一的缺点是一些数据库错误会中止整个JTA事务。
如果您使用用户管理的事务与非JTA环境中,仅仅获得一个新的EntityManager,得到一个EntityTransaction,使用em.find(...)
加载包含实体LOB的新副本等
。好的,所以在大多数数据库中都有一些不需要事务处理的对象类型,比如PostgreSQL SEQUENCE
和相关的SERIAL
伪类型,咨询锁等等,即使回滚的事务也会受到这种类型的影响。事务也可以“锁定”数据库,从而锁定可能阻止其他操作的资源。对于实际的数据,这是安全的。
。如果可以的话,避免让tx保持打开状态的时间超过几秒钟,因为长时间运行的事务会导致某些数据库出现性能问题,并且会阻塞连接池。避免在“用户的思考时间”内保持交易 - 当你等待用户做某件事时 - 他们可能会做白日梦,午餐,度假或月球......让你的穷人数据库和连接池等待他们的回报。
这是一个非常类似于我们想过的解决方案(添加一个读取Lob内容的事务方法,以便我们可以使用它)。 我认为如果没有奇迹发生,我们会为之努力,因为它是我们能找到的最好的。 – 2012-07-25 08:05:33
@XavierPortebois可惜的是PgJDBC无法让你获得整个LOB的更透明,从而关注幕后的事务管理。也许你应该看看PgJDBC的来源?毕竟它是开源的,你可能会加强它以适应你的需求。 – 2012-07-25 13:53:43
哇。在写这篇文章的时候,我发现JTA bean管理的事务没有相同的'REQUIRES_NEW'。他们不能暂停和恢复交易。如果您希望您使用*的功能来使用容器管理的事务。 – 2012-07-26 00:00:27