标题无法反映我的问题,但我不知道如何表达。我有一个JPA实体(VatOperatorBalance
,其中有一个字段saleBalance
),假设我是第一次检索实体,并获得一个实体(VatOperatorBalance@3d6396f5
),其{{1}是saleBalance
。现在还有其他操作已将100.0
修改为saleBalance
,现在我从数据库查询并获取新实体(200
),确保此实体的VatOperatorBalance@10f8ed
为saleBalance
。然而,让我感到困惑的是旧实体的200.0
(saleBalance
)也是VatOperatorBalance@3d6396f5
。
所有这些查询和操作都在一个事务中,查询不是200.0
,它将从缓存中返回实体。
以下是我的代码
EntityManager.find(java.lang.Class<T> entityClass, java.lang.Object primaryKey)
这个测试用例会失败,我不明白为什么会这样。 JPA实体经理会更新同一实体类型的所有实体吗? @Rollback(true)
@Test
public void testSale_SingleBet_OK() throws Exception {
// prepare request ...
// query the VatOperatorBalance first
VatOperatorBalance oldBalance = this.getVatOperatorBalanceDao().findByOperator("OPERATOR-111");
//this.entityManager.detach(oldBalance);
logger.debug("------ oldBalance(" + oldBalance + ").");
// the operation which will modify the oldBalance
Context saleReqCtx = this.getDefaultContext(TransactionType.SELL_TICKET.getRequestType(),
clientTicket);
saleReqCtx.setGameTypeId(GameType.VAT.getType() + "");
Context saleRespCtx = doPost(this.mockRequest(saleReqCtx));
RaffleTicket respTicket = (RaffleTicket) saleRespCtx.getModel();
this.entityManager.flush();
this.entityManager.clear();
// assert vat sale balance
VatOperatorBalance newBalance = this.getVatOperatorBalanceDao().findByOperator("OPERATOR-111");
logger.debug("------ newBalance(" + newBalance + ").");
assertEquals(oldBalance.getSaleBalance().add(respTicket.getTotalAmount()).doubleValue(), newBalance
.getSaleBalance().doubleValue(), 0);
}
实体和oldBalance
实体具有相同的newBlance
,但是它们是不同的Java实例,JPA实体管理器中发生了什么?如果我从entityId
分离oldBalance
实体,则testcase将通过。
注意:我的测试使用的是Spring4.0.5和JPA2.1
@ piet.t因为entityManager会通过其主键识别它是同一个实体(随意尝试)。因此,通过同一个entityManager对该实体所做的所有更改都将影响同一个java实例
因此在实体管理器中,具有给定主键的给定实体类型,应该只有一个java实例或管理实体(如果来自实体管理器的查询,无论查询条件是什么,不管是不是id,都是相同的java实例(管理实体)将被退回)。
然而,在我的测试案例中,实体“oldBalance&#39;将更新&#34; 将修改oldBalance &#34;的操作,然后调用entityManager.clear()将分离由此实体管理器管理的所有实体,即& #39; oldBalance&#39;也是分离的。
&#39; newBalance&#39;然后是托管实体,这就是为什么他们有不同的java实例标识符。如果&old;旧平衡&#39;例如,通过调用entityManager.merge()进行管理,它将是&#39; newBalance&#39;的相同实例。
答案 0 :(得分:0)
我认为您的大部分混淆都来自flush()
- 您的代码中的调用。
flush
将始终将更改后的值存储到数据库中 - 这就是调用flush
的对象。使用事务时,由于数据库事务机制,更改的值可能仍然不会通过其他连接可见,但您的entityManager只会看到更改的值。clear
- 调用您的查询 - 即使它没有使用find
- 仍会返回先前创建的相同实例(VatOperatorBalance @ 3d6396f5),因为entityManager会识别它是通过其主键实现相同的实体(随意尝试)。因此,通过同一个entityManager对此实体所做的所有更改都将影响同一个java实例,而通过另一个实体管理器进行的修改很可能会导致异常,因为该实体是从另一个事务更新的。flush
,因为缓存的更改可能会影响查询结果,因此在执行查询以获取正确的结果集之前,必须将所有更改写入数据库。我希望这确实有所帮助。