简体   繁体   English

使用 Hibernate 验证实体存在的最佳实践

[英]Best Practice For Verifying an Entity Exists Using Hibernate

In one of my applications I have a validator that is responsible for checking if an entity with a given class and id exists in the database.在我的一个应用程序中,我有一个验证器,负责检查数据库中是否存在具有给定 class 和 id 的实体。 In the past I used entityManager.find() and simply checked if the result was null.过去我使用 entityManager.find() 并简单地检查结果是否为 null。 While this works, it is expensive for entities with complex associations since find() will try to pull back the whole entity graph.虽然这很有效,但对于具有复杂关联的实体来说代价高昂,因为 find() 会尝试拉回整个实体图。 It is also prone to lazy load exceptions if it ever gets used outside the scope of a transaction.如果它曾经在事务的 scope 之外使用,它也容易出现延迟加载异常。

I've been looking for an alternative solution and I have found a few suggestions but I don't know how to evaluate them in terms of performance vs potential down sides.我一直在寻找替代解决方案,并找到了一些建议,但我不知道如何从性能与潜在不利方面评估它们。 From the research I have done so far, here are the potential options I see:从我目前所做的研究来看,以下是我看到的潜在选择:

  1. Manually create and execute a 'count' query.手动创建并执行“计数”查询。
  2. Use Criteria Builder to create and execute a count query.使用 Criteria Builder 创建和执行计数查询。
  3. Use entityManager.getReference()使用 entityManager.getReference()

3 would be my preferred solution if it actually worked, but it doesn't seem to be viable in Hibernate.如果它确实有效,3 将是我的首选解决方案,但它在 Hibernate 中似乎不可行。 Hibernate doesn't throw an exception when getReference() is called on an entity that does not exist in the DB and I don't see any way to differentiate between the proxy returned when the lookup fails and the proxy returned when the lookup actually finds something.当对数据库中不存在的实体调用 getReference() 时,Hibernate 不会引发异常,我看不出有任何方法可以区分查找失败时返回的代理和查找实际找到时返回的代理某物。

If anyone is familiar with Hibernate, is there another way of doing this that I'm missing?如果有人熟悉 Hibernate,是否还有另一种我想念的方法? If not, is the performance overhead from using a Criteria Query high enough to make a native query a better option?如果不是,使用 Criteria Query 的性能开销是否足够高以使本机查询成为更好的选择?

It depends.这取决于。

EntityManager.find(id) is entirely adequate if the entity has no eager associations, and a reasonable size (ie contains no huge blobs or lengthy strings).如果实体没有急切的关联和合理的大小(即不包含巨大的斑点或冗长的字符串), EntityManager.find(id)就完全足够了。 Since a primary key index is usually clustered, loading the state of the entity does not cause additional I/O for the database, and incurs a negligible CPU and bandwidth overhead.由于主键索引通常是集群的,因此加载实体的 state 不会对数据库造成额外的 I/O,并且产生的 CPU 和带宽开销可以忽略不计。 On the positive side, EntityManager.find(id) is easy to use, easy to understand, and, by virtue of loading the entity into the session, can speed up future accesses to that entity.从积极的方面来说, EntityManager.find(id)易于使用、易于理解,并且通过将实体加载到 session 中,可以加快未来对该实体的访问。

If your entity is very big, or has eager associations, a count query is more efficient.如果您的实体非常大,或者有急切的关联,则计数查询更有效。 Whether you write this in SQL or through the Criteria API has negligible performance impact, since the bottleneck will usually be database I/O, not CPU time on your application server.无论您是在 SQL 还是通过 Criteria API 编写此代码,对性能的影响都可以忽略不计,因为瓶颈通常是数据库 I/O,而不是应用程序服务器上的 CPU 时间。

Sometimes, it is also possible to omit the check for existence, and trust the database to alert you if a constraint is violated.有时,也可以省略存在性检查,并相信数据库会在违反约束时提醒您。 This is more efficient for the database, and more robust in the face of high concurrency.这对数据库来说效率更高,面对高并发时更健壮。 And that's what entityManager.getReference(id) is for:这就是entityManager.getReference(id)的用途:

person.getFriends().add(entityManager.getReference(newFriendId)); 
// assume the friend id is valid - if it isn't, the database will tell us anyway

appendix: existence checks and phantom reads附录:存在检查和幻读

In the read committed isolation level, another transaction may delete an entity after its existence has been checked by a query, but before the transaction commits:在读提交隔离级别中,另一个事务可能会在查询检查到实体存在之后,但在事务提交之前删除一个实体:

Thread 1                                                Thread 2

select count(*)
from BigFatEntity
where id = 42;

1 row found

                                                        delete from BigFatEntity
                                                        where id = 42;
                                                        commit;

insert into Relationship(id, big_fat_entity_id)
values (123, 42);

constraint violation: 42 no longer exists

That is, checking for existence before using an entity as a foreign key can not prevent a foreign key violation in all cases.也就是说,在使用实体作为外键之前检查是否存在并不能在所有情况下都防止外键违规。

Even under serializable transaction isolation, checking first will not prevent a transaction rollback in this case.即使在可序列化事务隔离下,在这种情况下,先检查也不会阻止事务回滚。

That is, checking for existence will not catch all cases, but makes the transaction longer, increasing the probability of transaction rollback and reducing the overall throughput of the system.即检查是否存在不会捕获所有情况,反而会使事务变长,增加事务回滚的概率,降低系统的整体吞吐量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM