gpt4 book ai didi

mongodb - Spring Data Mongodb 事务期间如何使用文档锁来防止外部修改记录

转载 作者:行者123 更新时间:2023-12-02 23:33:06 32 4
gpt4 key购买 nike

我有一个关于 Spring Data Mongo 和 Mongo Transactions 的问题。

我已经成功实现了事务,并使用 Spring @Transactional 注释验证了提交和回滚是否按预期工作。

但是,我很难让事务按照我在 Spring Data 环境中期望的方式工作。

Spring 数据进行 Mongo -> Java 对象映射。因此,更新某些内容的典型模式是从数据库中获取它,然后进行修改,然后将其保存回数据库。在实现事务之前,我们一直在使用 Spring 的乐观锁来考虑在获取和更新之间记录发生更新的可能性。

我希望一旦我们能够使用事务,我就能够在所有更新中不包含乐观锁定基础设施。因此,我希望在事务的上下文中,获取操作会创建一个锁,以便我可以进行更新并保存,并且我将被隔离,以便没有人可以像以前一样进入并进行更改。

但是,根据我所看到的,提取不会创建任何类型的锁,因此没有任何东西可以阻止任何其他连接更新记录,这意味着我似乎必须维护所有乐观锁定代码,尽管有原生 mongodb 事务支持。

我知道我可以使用 mongodb findAndUpdate 方法来进行更新,并且不允许发生临时修改,但这与 Spring Data 将数据加载到 Java 对象中的标准模式相反。因此,我不仅仅能够操作 Java 对象,还必须在整个应用程序中散布 mongo 特定代码,或者为我想要进行的每种特定类型的更新创建存储库方法。

有人对如何干净地处理这种情况有什么建议,同时保持仅使用 Java 对象的 Spring Data 范例吗?

提前致谢!

最佳答案

我无法找到任何方法在 Spring/MongoDB 事务中执行“读”锁定。

但是,为了能够继续使用以下模式:

  1. 获取记录
  2. 进行更改
  3. 保存记录

我最终创建了一个执行 findAndModify 的方法,以便在获取期间“锁定”记录,然后我可以进行更改并进行保存,这一切都发生在同一个事务中。如果另一个进程/线程尝试在事务期间更新“锁定”记录,它将被阻止,直到我的事务完成。

对于lockForUpdate方法,我利用了Spring已经用于乐观锁定的版本字段,只是因为它很方便并且可以轻松地修改简单的锁定操作。

我还将我的实现添加到基本存储库实现中,以在所有存储库上启用“lockForUpdate”。

这是我的解决方案的要点,删除了一些特定于领域的复杂性:

public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleMongoRepository<T, ID>
implements BaseRepository<T, ID> {

private final MongoEntityInformation<T, ID> entityInformation;
private final MongoOperations mongoOperations;

public BaseRepositoryImpl(MongoEntityInformation<T, ID> metadata, MongoOperations mongoOperations) {
super(metadata, mongoOperations);

this.entityInformation = metadata;
this.mongoOperations = mongoOperations;
}

public T lockForUpdate(ID id) {
// Verify the class has a version before trying to increment the version in order to lock a record
try {
getEntityClass().getMethod("getVersion");
} catch (NoSuchMethodException e) {
throw new InvalidConfigurationException("Unable to lock record without a version field", e);
}

return mongoOperations.findAndModify(query(where("_id").is(id)),
new Update().inc("version", 1L), new FindAndModifyOptions().returnNew(true), getEntityClass());
}

private Class<T> getEntityClass() {
return entityInformation.getJavaType();
}
}

然后,您可以在事务上下文中按照以下方式进行调用:

Record record = recordRepository.lockForUpdate(recordId);
...make changes to record...
recordRepository.save();

关于mongodb - Spring Data Mongodb 事务期间如何使用文档锁来防止外部修改记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56297931/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com