Play 1.2.3 framework - правильный способ совершения транзакции - PullRequest
2 голосов
/ 14 февраля 2012

У нас есть конечная точка HTTP, выполнение которой занимает много времени и которая также может вызываться пользователями одновременно.В рамках этого запроса мы обновляем модель внутри синхронизированного блока, чтобы другие (возможно, параллельные) запросы воспринимали это изменение.

Например,

MyModel m = null;
synchronized (lockObject) {
    m = MyModel.findById(id);
    if (m.status == PENDING) {
        m.status = ACTIVE;
    } else {
        //render a response back to user that the operation is not allowed
    }
    m.save(); //Is not expected to be called unless we set m.status = ACTIVE
}
//Long running operation continues here. It can involve further changes to instance "m"

Причина, по которой блок синхронизирован , заключается в том, что даже одновременные запросы могут получить последний статус.Однако базовый JPA не фиксирует мои изменения (m.save ()) до тех пор, пока запрос не будет завершен.Поскольку это длительный запрос, я не хочу ждать, пока запрос будет завершен, и все же хочу убедиться, что другие абоненты будут уведомлены об изменении статуса.Я пытался вызвать "m.em (). Flush (); JPA.em (). GetTransaction (). Commit ();"после m.save (), но это делает транзакцию недоступной для последующего действия как части того же запроса.Могу ли я просто дать "JPA.em (). GetTransaction (). Begin ();"и позволить Play обрабатывать транзакции с тех пор?Если нет, то как лучше всего справиться с этим вариантом использования?

ОБНОВЛЕНИЕ: На основании ответа я изменил свой код следующим образом:

MyModel m = null;
synchronized (lockObject) {
    m = MyModel.findById(id);
    if (m.status == PENDING) {
        m.status = ACTIVE;
    } else {
        //render a response back to user that the operation is not allowed
    }
    m.save(); //Is not expected to be called unless we set m.status = ACTIVE
}
new MyModelUpdateJob(m.id).now();

И в моей работе у меня есть следующая строка:

doJob() {
    MyModel m = MyModel.findById(id);
    print m.status; //This still prints the old status as-if m.save() had no effect...
}

Что мне не хватает?

Ответы [ 2 ]

2 голосов
/ 14 февраля 2012

Поместите свой код обновления в работу, позвоните

new MyModelUpdateJob(id).now().get();

, таким образом, обновление будет выполнено в другой транзакции, которая передается в конце задания

0 голосов
/ 15 февраля 2012

ой, как только вы добавите больше игровых серверов, у вас будут проблемы. Вы можете поиграть с оптимистической блокировкой в ​​вашем примере или я советую против нее пессимистическую блокировку .... ick.

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

В вашем случае, если 1. пользователь 1 и пользователь 2 оба вызывают этот метод и ожидают его, затем он переходит в активное состояние (Идемпотент) Если победит пользователь 1 или пользователь 2, хорошо, что у вас все равно будет блок синхронизации.

Я уверен, однако, что у вас есть более сложный сценарий, который здесь не показан, НО ПРОЧИТАЙТЕ эту статью, основанную на зыбучих песках, поскольку она действительно меняет традиционный образ мышления и то, как работают системы Google и Amazon, а также системы очень большого масштаба.

Другой вариант для распределенных транзакций на игровых серверах - это zookeeper, который большие и большие nosql используют НО только в качестве крайней меры;);)

позже, Декан

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...