Как да отхвърлите едновременни дублирани записвания с помощта на приложението 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