java 休眠/持久性有哪些常见问题?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11298594/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
what are some common problems with Hibernate/persistence?
提问by Poni
I have an application I'd like to test-proof against possible problems related to Hibernate and/or persistence.
我有一个应用程序,我想针对与 Hibernate 和/或持久性相关的可能问题进行测试。
What other problems? How do I reproduce them (literally)? And how do you recover from them?
还有哪些问题?我如何复制它们(字面意思)?你如何从它们中恢复过来?
To make it clear: I'm talking about multi-threaded cluster environment (the most complex one).
澄清一下:我说的是多线程集群环境(最复杂的一个)。
My one:
我的唯一:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
Reproduce:
复制:
- Load the object.
- UPDATE using HQL.
- Try to update (save) the loaded object.
- 加载对象。
- 使用 HQL 更新。
- 尝试更新(保存)加载的对象。
Handle: Not sure...
处理:不确定...
回答by Matt
Lazy loading is one the big issues you'll encounter, especially if you follow a standard DAO pattern. You'll end up with lazy loaded collections, but upon coming out of your DAO layer, spring (or something else if you're not using spring) might close the session.
延迟加载是您会遇到的一大问题,特别是如果您遵循标准 DAO 模式。您最终会得到延迟加载的集合,但是在退出 DAO 层时,spring(或其他东西,如果您不使用 spring)可能会关闭会话。
public class MyDaoImpl implements MyDao {
@Override
@Transactional
public void save(MyObject object) { ... }
}
In this case, when the call to "save" completes, spring will close your session if you are not within another transaction. As a result, any calls to lazily loaded objects will throw a LazyInitializationException.
在这种情况下,当“保存”调用完成时,如果您不在另一个事务中,spring 将关闭您的会话。因此,对延迟加载的对象的任何调用都将引发 LazyInitializationException。
The typical way to handle this is to bind a session to the current thread. In webapps, you can do this easily with the OpenSessionInViewFilter. For command line, you'll probably need to write a utility method which creates a session, binds to the current thread, and then unbinds when you're done. You can find examples of this all over the web.
处理此问题的典型方法是将会话绑定到当前线程。在 web 应用程序中,您可以使用 OpenSessionInViewFilter 轻松完成此操作。对于命令行,您可能需要编写一个实用方法来创建会话、绑定到当前线程,然后在完成后解除绑定。您可以在整个网络上找到此类示例。
And on the subject of collections, if you use the "update" method (again something you'd typically do with a standard DAO pattern), you have to be careful not to replace collection instances, but rather you should manipulate the collection that's already in place. Otherwise, hibernate will have a hard time figuring out what needs to be added/removed/updated.
关于集合,如果您使用“更新”方法(这也是您通常使用标准 DAO 模式执行的操作),您必须小心不要替换集合实例,而应该操作已经存在的集合到位。否则,休眠将很难弄清楚需要添加/删除/更新什么。
回答by Oleksi
The problem you have observed is one of concurrent modification of data. Hibernate has many possible solutionsfor dealing with this.
您观察到的问题是数据的并发修改之一。Hibernate 有许多可能的解决方案来处理这个问题。
Essentially, the problem is that two threads (or two machines in your cluster) are acting on the same piece of data at the same time. Consider this example:
本质上,问题在于两个线程(或集群中的两台机器)同时处理同一块数据。考虑这个例子:
machine 1: reads the data and returns it for editing somewhere else
machine 2: also reads the data for modification
machine 1: updates the data and commits.
machine 2: tries to do an update and commit.
What will happen when the second machine tries to commit its changes? Hibernate will see that the data has changed while machine 2 was working on the data. That is, machine 2's update is on stale data. Hibernate can't always merge the two changes (nor is that always desired behaviour), so it rejects the second update by throwing org.hibernate.StaleObjectStateException
当第二台机器尝试提交其更改时会发生什么?当机器 2 处理数据时,Hibernate 将看到数据已更改。也就是说,机器 2 的更新是在陈旧数据上。Hibernate 不能总是合并这两个更改(也不是总是期望的行为),因此它通过抛出拒绝第二次更新org.hibernate.StaleObjectStateException
As I mentioned above, Hibernate gives you many options to solve this problem. The simplest, perhaps, is to add a version field using @Version
on your data objects. Hibernate will automatically maintain the "version" of the data. Whenever an update takes place, the version will be changed automatically by Hibernate. Your job is the check that the version hasn't changed between when you readthe data and when you updatethe data. If they don't match, you can do something to handle the problem (i.e. tell the user). There are some more sophisticated techniques for preventing concurrent updates, but this is the simplest.
正如我上面提到的,Hibernate 为您提供了许多解决此问题的选项。最简单的方法可能是@Version
在数据对象上添加一个 version 字段。Hibernate 会自动维护数据的“版本”。每当发生更新时,Hibernate 都会自动更改版本。您的工作是检查在读取数据和更新数据之间版本没有更改。如果它们不匹配,您可以做一些事情来处理问题(即告诉用户)。有一些更复杂的技术可以防止并发更新,但这是最简单的。
回答by Vlad Mihalcea
Fetching too much data is probably the biggest problem you can have when you use an ORM tool because it makes it very easy to load way more data than necessary. This problem does not replicate in dev/test scenarios if the amount of test data is rather small, and once data starts to accumulate in production, the data access layer can get exponentially slower.
获取过多数据可能是您使用 ORM 工具时遇到的最大问题,因为它可以很容易地加载比需要更多的数据。如果测试数据量很小,这个问题在开发/测试场景中不会复制,一旦数据开始在生产中积累,数据访问层就会变得很慢。
There are many problems that may occur, as explained in the High-Performance Java Persistencebook:
可能会出现很多问题,如High-Performance Java Persistence一书中所述:
- lack of batch updates
- lack of statement caching
- too much locking
- too many database roundtrips
- exotic associations that generate inefficient SQL statements
- 缺少批量更新
- 缺少语句缓存
- 过多的锁定
- 太多的数据库往返
- 生成低效 SQL 语句的奇异关联