Mongodb MongoTemplate.save上出现意外的乐观锁定异常

Mongodb MongoTemplate.save上出现意外的乐观锁定异常,mongodb,spring-data-mongodb,Mongodb,Spring Data Mongodb,使用MongoTemplate,我试图存储一个名为Person的实体。因为我想使用乐观锁定,所以使用@Version注释对实体进行版本控制 当我尝试使用MongoTemplate.save将一个新的Person实体存储到一个空集合中时,我得到了OptimisticLockingException。我没想到会这样,因为我正在创建一个新对象,而不是更新一个现有对象。(并且没有其他线程正在访问集合。) 这是预期的行为,还是我做错了什么 (如果我改用MongoOperations.insert,一切都会

使用MongoTemplate,我试图存储一个名为Person的实体。因为我想使用乐观锁定,所以使用@Version注释对实体进行版本控制

当我尝试使用MongoTemplate.save将一个新的Person实体存储到一个空集合中时,我得到了OptimisticLockingException。我没想到会这样,因为我正在创建一个新对象,而不是更新一个现有对象。(并且没有其他线程正在访问集合。)

这是预期的行为,还是我做错了什么

(如果我改用MongoOperations.insert,一切都会正常工作。(但我想使用save,因为crudepository只有save,没有update。)如果我删除@Version注释,它也会正常工作。)

谢谢, 丹尼尔

我的实体类:

import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
import org.springframework.data.mongodb.core.mapping.Document;

@Document
public class Person {

    @Version
    private long versionId;

    @Id
    private ObjectId id;

    private final String name;

    public Person(String name) {
        this.name = name;
    }

    public long getVersionId() {
        return versionId;
    }

    public ObjectId getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Person person = (Person) o;

        if (id != null ? !id.equals(person.id) : person.id != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }
}
我的测试设置(使用EmbeddeMongo设置MongoDb实例):


当version属性的类型为long时,默认值为0,这似乎是SpringDataMongoDB不可接受的

将Person类中versionId的类型更改为Long/Integer

@版本
私有长版本ID;

谢谢Maciej,这证实了我在查看code Spring数据MongoDb后的理解。我的测试还表明,Long在某些情况下失败了(现在不记得是哪个),但Integer似乎工作得很好。
import com.mongodb.Mongo;
import de.flapdoodle.embed.mongo.MongodExecutable;
import de.flapdoodle.embed.mongo.MongodProcess;
import de.flapdoodle.embed.mongo.MongodStarter;
import de.flapdoodle.embed.mongo.config.MongodConfig;
import de.flapdoodle.embed.mongo.distribution.Version;
import de.flapdoodle.embed.process.runtime.Network;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

public class MongoDbTest {

    private MongodExecutable mongodExe;
    private MongodProcess mongod;
    private Mongo mongo;
    private MongoOperations mongoOperations;

    @Before
    public void setUp() throws Exception {
        MongodStarter runtime = MongodStarter.getDefaultInstance();

        mongodExe = runtime.prepare(new MongodConfig(Version.Main.V2_0, 12345, Network.localhostIsIPv6()));
        mongod = mongodExe.start();
        mongo = new Mongo("localhost", 12345);

        MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongo, "database");

        MappingContext mappingContext = new MongoMappingContext();
        MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(mongoDbFactory, mappingContext);

        mongoOperations = new MongoTemplate(mongoDbFactory, mappingMongoConverter);
    }

    @After
    public void tearDown() {
       mongod.stop();
       mongodExe.stop();
    }

    @Test
    public void testSave() {
        Person person = new Person("Joe");
        mongoOperations.save(person);  // This call throws OptimisticLockingException.
    }
}