2013-06-06 3 views
5

Я читал разные уровни изоляции транзакций и перешел на уровень изоляции SERIALIZABLE. Я также знаю, что базы данных, такие как Postgres, Oracle и MySQL, поддерживают синтаксис SELECT .. FOR UPDATE.Сериализуемые транзакции против SELECT FOR UPDATE

Я, однако, путаюсь, как они должны использоваться, когда я хотел бы заблокировать строку (или ряд строк), которые я хочу выполнить.

При использовании JPA в прошлом я всегда использовал @Transactional в сочетании с LockModeType.PESSIMISTIC_WRITE по запросу. Это означает использование уровня изоляции READ_COMMITTED с помощью SELECT .. FOR UPDATE в SQL.

Но теперь, прочитав о SERIALIZABLE, я задаюсь вопросом, что было бы иначе, если бы я использовал @Transactional(isolation=SERIALIZABLE) с нормальным SELECT (например em.findById для извлечения частного лица), за которым следует UPDATE (слияния организация).

Будет ли поведение одинаковым?

Скажите, например, у меня есть банковская система, и я хочу перевести деньги между двумя учетными записями. Я требую, чтобы эти учетные записи не вмешивались, пока передача выполняется. Итак, предположим, что я дебетую одну учетную запись на -100 и передаю ее в другой аккаунт. Каким будет лучший способ гарантировать, что эти учетные записи доступны только для транзакции, выполняющей обновление?

Предположим, что я управляю отдельными объектами JPA, поэтому перед обновлением мне придется их прочитать из БД, например. findById().

  • Использование @Transactional(isolation=READ_COMMITTED), em.findById с LockModeType.PESSIMISTIC_WRITE (т.е. SELECT .. FOR UPDATE), а затем em.merge (т.е. UPDATE)?
  • ИЛИ С помощью @Transactional(isolation=SERIALIZABLE), em.findById, а затем em.merge (т.е. UPDATE)?

ответ

2

Основное отличие между SERIALIZABLE и использованием SELECT FOR UPDATE заключается в том, что при SERIALIZABLE все всегда заблокировано. Где, как и в случае с SELECT FOR UPDATE, вы можете выбрать, что и когда вы блокируете.

Поэтому, если вы хотите заблокировать некоторые данные, то есть BankAccount, но не другие, то есть Branch, AccountTypes, тогда SELECT FOR UPDATE дает вам намного лучший контроль, где SERIALIZABLE блокирует всю вашу систему, поскольку каждая транзакция, выбранная из ACCOUNT_TYPES Таблица. Кроме того, некоторые транзакции могут просто хотеть проверить баланс, поэтому не нужно блокировать таблицу ACCOUNT.

See,

http://en.wikibooks.org/wiki/Java_Persistence/Locking

+6

«* с SERIALIZABLE все всегда заблокировано *» не является истинным в качестве общего утверждения. Это сильно зависит от реализации СУБД (Postgres, например, этого не делает) –

+0

Это правда «PostgreSQL, к примеру, не делает этого» в сериализованном PostgreSQL. Будет делать все команды выбора без блокировки, но когда происходит параллелизм в операторах записи, последняя транзакция получается не удалось обеспечить сериализуемую целостность – deFreitas

0

Мне кажется, что SERIALIZABLE не может работать в этой сделке бизнес, потому что вы должны проверить некоторые условия после выбора объекта (например, если учетная запись имеет достаточно Деньги). Параллельные транзакции могут получить неправильное значение с уровнем SERIALIZABLE, поскольку он содержит общую (прочитанную) блокировку для SELECT.

Но SELECT ...FOR UPDATE будет работать правильно, потому что он будет удерживать исключительную блокировку до конца транзакции и заставит другие транзакции ждать.

Смежные вопросы