索引独特的奇怪行为

时间:2017-04-29 20:48:45

标签: spring mongodb indexing unique spring-data-mongodb

我是弹簧数据和mongo的新手,所以可能是我的pbm真的很容易......

我有一个简单的文档User,其ID为object ID,登录String的注释为@Indexed(unique = true)

使用MongoOperations : mongoOperations.save(user);

保存用户

我创建了一个简单的单元测试来检查重复登录是否被拒绝。它似乎工作正常。

之后,我添加了另一项测试来检查是否找不到未知用户...

对我来说非常奇怪的是因为这个新测试在第一个测试之前执行,第一个测试失败:2个具有相同登录的用户被插入到DB中。

如果我直接检查mongo客户端,我可以看到存储了2个具有相同登录名的对象。

db.user.find({})

{
    "_id" : ObjectId("5904f59c5ea29c288c593280"),
    "_class" : "com.test.User", "login" : "toto"
}

{
    "_id" : ObjectId("5904f59c5ea29c288c593282"), 
    "_class" : "com.test.User", "login" : "toto"
}

对此有任何解释吗?

我正在使用:

  • mongo 3.4.3
  • spring-boot-starter-parent 1.5.2.RELEASE
  • spring-boot-starter-data-mongodb 1.5.2.RELEASE

请在下面找到我的代码的一部分(我希望我没有错过任何重要的事情)。

application.properties

spring.data.mongodb.uri=mongodb://localhost/mydb

文档用户

@Document
public class User {
    @Id
    private ObjectId id;

    @Indexed(unique = true)
    public String login;

    private String pass;

    public User() {
    }

    public User(String login, String pass) {
        this.login = login;
        this.pass = pass;
    }

    public ObjectId getId() {
        return id;
    }
}

我的Junit测试:

@EnableAutoConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = { UserController.class })
@ComponentScan("com.test")
public class TestUserController {

    @Autowired
    private DbInitialisatioController dbInitController;

    @Autowired
    private UserController controller;

    @Autowired
    MongoTemplate mongoTemplate;

    @Before
    public void setup() {
        mongoTemplate.getDb().dropDatabase();

        // Should not be usefull, but without that call test is not successfull
        dbInitController.init();
    }

    @Test
    public void testFindUnknownUser() {
        Assert.assertNull("User bob should be null as does not exists", controller.findByLogin("bob"));
    }

    @Test
    public void testCreateUser_ErrorSavingTwice() throws MyException {
        User user = new User("toto", "pass");

        controller.createUser(user);

        try {
            controller.createUser(user);
            Assert.fail("User must not be saved twice");
        } catch (MyException e) {
            Assert.assertEquals(ErrorCode.INTERNAL_ERROR, e.getErrorCode());
        }
    }
}

"控制器"它的作用是执行对DB的访问。

@Component
public class UserController {

    final static Logger logger = LoggerFactory.getLogger(UserController.class);

    @Autowired
    MongoOperations mongoOperations;

    @Autowired
    ProfilController profilController;

    public User findByLogin(String login) {
        Query query = new Query();
        query.addCriteria(Criteria.where("login").is(login));

        return mongoOperations.findOne(query, User.class);
    }

    public void createUser(User user) throws MyException {
        if (user.getId() != null) {
            throw new MyException(ErrorCode.INTERNAL_ERROR, "could not saveNewUser for existing user");
        }

        logger.info("Creating user {}", user);

        try {
            mongoOperations.save(user);
            logger.info("Created {}", user);
        } catch (org.springframework.dao.DuplicateKeyException e) {
            throw new MyException(ErrorCode.LOGIN_ALREADY_EXITS, user.login);
        }
    }

    // ... some other methods
}

此类不应退出,但如果没有,则测试失败

@Component
public class DbInitialisatioController {

final static Logger logger = LoggerFactory.getLogger(UserController.class);
    @Autowired
    MongoOperations mongoOperations;

    @Autowired
    UserController userController;

    /**
    * Note I don't understand why I need to create indexes here. I was expecting that Indexed annotation in User and Profil would do the same...
    */
    public void init() {
        logger.info("Initializing DB");
        mongoOperations.indexOps(User.class).ensureIndex(new Index().on("login", Direction.ASC).unique());
        mongoOperations.indexOps(Profile.class).ensureIndex(new Index().on("login", Direction.ASC).unique());
    }
}

0 个答案:

没有答案