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

如何在Spring Data Mongodb事务期间使用文档锁防止外部修改记录,mongodb,spring-data-mongodb,spring-transactions,Mongodb,Spring Data Mongodb,Spring Transactions,我有一个关于Spring数据Mongo和Mongo事务的问题 我已经成功地实现了事务,并利用Spring@Transactional注释验证了提交和回滚的工作是否如预期的那样 然而,我很难让事务按照我在Spring数据环境中期望的方式工作 Spring数据执行Mongo->Java对象映射。因此,更新内容的典型模式是从数据库中获取内容,然后进行修改,然后将其保存回数据库。在实现事务之前,我们一直使用Spring的乐观锁定来考虑在获取和更新之间记录发生更新的可能性 我希望,一旦我们能够使用事务,我

我有一个关于Spring数据Mongo和Mongo事务的问题

我已经成功地实现了事务,并利用Spring@Transactional注释验证了提交和回滚的工作是否如预期的那样

然而,我很难让事务按照我在Spring数据环境中期望的方式工作

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

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

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

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

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


提前谢谢

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

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

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

    对于lockForUpdate方法,我利用了Spring已经用于乐观锁定的version字段,这仅仅是因为它很方便,并且可以很容易地修改为简单的锁定操作

    我还将我的实现添加到基本存储库实现中,以便在所有存储库上启用“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();
        }
    }
    

    对于MongoDB事务,如果将获取和更新包装在事务中,则自获取文档以来的任何更改都将导致事务提交抛出WriteConflict。你能解释一下为什么这不是理想的行为吗?或者,也许我在SpringData方面遗漏了一些东西。
    Record record = recordRepository.lockForUpdate(recordId);
    ...make changes to record...
    recordRepository.save();