Hibernate SaveOrUpdate - 多个工作线程

6

虽然我已经找到了有关Hibernate事务如何工作以避免数据库损坏的信息,但是理解Hibernate如何处理在多个线程之间共享的对象,并且每个线程都尝试将其保存到数据库中的对象却更为困难。

这是我的理论问题:

1)我有一个人员对象,带有属性(ssn,姓名,地址)。 2)三个线程引用此人员对象,每个线程调用savePersonToHibernate(...)方法。

public void savePersonToHibernate(Person person)
{
...
session.saveOrUpdate(person)
...
}

Hibernate在处理三个线程同时向存储中写入同一对象时,会如何应对?它会将所有事务放入队列中,因此当第一个线程创建行和标识符(设置ID)时,剩余的两个线程只会进行更新(在这种情况下没有更改)吗?还是说我实际上有可能在数据库中有2或3行,而当前对象只引用最后创建的标识符?
我希望这有些意义...我正在制作一个队列系统,数据需要参考需要即时创建的类别...如果两个或多个线程获取一些数据,它们都需要创建相同的类别,我不想重复。
希望这有些意义...你会怎么做?
1个回答

4
我假设所有提到的线程都使用不同的会话,否则您会遇到麻烦,因为Hibernate会话不是线程安全的。
只是为了让事情更清楚,如果所有三个线程都在使用相同的人员实例并且这是一个新对象,则您将遇到麻烦,因为当访问或修改对象时Hibernate不会进行任何同步操作。基本上,每个线程的工作方式就好像其他线程不存在一样,因此每个线程都会首先检查person是否具有非空id,并尝试生成它(如果id为null),然后将其分配给适当的实体字段。根据不同线程中检查-生成-分配的时间以及更改的可见性效果,同时创建的结果是不可预测的。
让我们看看如果所有线程都使用不同的person实例但具有相同的属性值会发生什么。在这种情况下,每个线程都会尝试在数据库中创建三个不同的行,如果底层表没有唯一约束(如唯一名称),则将成功。
您的特定类别创建方案不太容易实现。想法是尝试创建类别,但如果已经存在,则捕获异常并从数据库中读取现有的类别并使用它。但请记住,条件插入的实现并不简单,可能与RDBMS有关。您可以在PostgreSQLSQL Server上找到稍微更复杂但相关的upsert操作示例。

1
谢谢你的回答。由于这一步骤很关键,我决定创建一个“预分类队列”,使用一个线程创建一个类别并将其投入到映射中,将类别对象引用主对象,然后将其投入到真正的队列中,供多个线程使用。它运行得很好,但不完全是按照书本上的方式进行的,但可以避免一般情况下对数据库的访问。 - Peter Goodheart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接