Как отклонить одновременные дубликаты сохранений с помощью приложения Objectify для AppEngine

У нас есть сущность, определенная как (id, name, school, & OTHER-FIELDS). id автоматически назначается хранилищем данных. И мы хотим убедиться, что комбинация <name, school> уникальна в хранилище данных.

Наш код пишется так:

/* First check uniqueness, then save */
public void savePerson(final Person newPerson) {
    List<Person> existing = ofy().load().type(Person.clas)
            .filter("name=", name)
            .filter("school=", school)
            .list();
    if (existing == null || existing.isEmpty()) {
        ofy.transact(new VoidWork() {
            @Override
            public void vrun() {
                ofy.save.entity(newPerson).now();
            }
        }
    }
}

Но все же бывает, если одновременно происходит несколько одинаковых вызовов savePerson (неизбежно мы с этим столкнемся), проверка дубликатов не пройдет (думаю потому, что при запуске вызова savePerson() данные фактически не сохраняются), и мы находим в хранилище данных AppEngine это закончилось дублированием сущностей с одинаковыми <name, school> комбинациями.

Мы действительно хотим убедиться, что в нашем хранилище данных, заданном <name, school>, мы получим уникальный объект. Может ли кто-нибудь научить меня, как добавить проверку дубликатов атомарно? Это поможет, если я перенесу существующий код проверки объекта в контекст транзакции?

Например, будет ли работать следующий код?

/* Put filtering search into transaction too */
public void savePerson(final Person newPerson) {
    ofy.transact(new VoidWork() {
        @Override
        public void vrun() {
            List<Person> existing = ofy().load().type(Person.class)
                    .filter("name=", name)
                    .filter("school=", school)
                    .list();
            if (existing == null || existing.isEmpty()) {
                ofy.save.entity(newPerson).now();
            }
        }
    }
}

Дайте мне знать, если я должен предоставить более подробную информацию.


person user1630753    schedule 30.01.2014    source источник
comment
Это потребует некоторой реструктуризации вашей базы данных, но допустим ли уникальный идентификатор на уровне приложения? Это будет работать лучше, чем более высокие накладные расходы на область уникальности для типа Person. См. недавнее обсуждение StackOverflow.   -  person Martin Berends    schedule 30.01.2014


Ответы (1)


Чтобы делать то, что вы хотите, обязательно используйте одну транзакцию для чтения, если уже есть данное имя + школа, и для сохранения объекта; в противном случае, если у вас будет много одновременных пользователей, у вас закончатся дубликаты. Вместо того, чтобы загружать весь список, вы можете просто загрузить первый объект [т.е. первый()]. Убедитесь, что «имя» и «школа» проиндексированы (например, @Index). Также убедитесь, что у вас есть ObjectifyFilter в web.xml.

Однако обратите внимание, что в одной и той же школе могут быть два разных человека с одним и тем же именем, поэтому вам следует добавить еще один способ различать людей.

person Alejandro C.    schedule 27.08.2014