#java #database #spring-mvc #h2
#java #База данных #spring-mvc #h2
Вопрос:
Я использую базу данных H2, встроенную в приложение Spring-MVC.
Я объявляю транзакции на своем уровне обслуживания. В частности, у меня есть случай, когда мы делаем следующее:
- Запустите транзакцию
- Выполните вызов webservices
- Выполните последующие вызовы базы данных
- При откате (исключение) вызов webservices откатывается вручную, и диспетчер транзакций Spring обрабатывает вызов отката транзакции DB.
Но я понял, что существование вызова webservices в транзакции DB вызывает блокировку всей таблицы, из-за чего другие пользователи получают ошибки (я могу создать это в системе с одним пользователем и двумя браузерами).
Я пытаюсь разработать свой наилучший план действий.
- Должен ли я изменять уровень изоляции транзакции весной, повлияет ли это на блокировку БД?
- Это просто дурной тон иметь webservice и вызов DB в одной транзакции?
- Должен ли я включить блокировку на уровне строк в базе данных H2 из-за этого?
- Я не думаю о других решениях?
Я должен добавить, что мой метод service serviceA()
вызывает два других метода webServiceX()
и daoMethodY()
. serviceA()
включено в транзакцию, потому что для любого исключения требуется откат как webServiceX()
(функция, которую я предоставляю), так и откат daoMethodY()
операций с базой данных (функция DataSourceTransactionManager
).
Ответ №1:
Я думаю, что ваш подход разумен, и вам обязательно следует попробовать блокировку на уровне строк, если это возможно.
Возможно, вы захотите пересмотреть свой дизайн. Действительно ли состояние дублирования базы данных исходит от веб-службы? В этом случае вы можете вместо этого рассмотреть возможность кэширования вызовов веб-службы. Но это зависит от вашего приложения.
В качестве альтернативы, возможно, вам просто придется запустить собственное управление транзакциями. Пока это общее, это не должно быть слишком большой проблемой. Мы сделали это в нашем проекте, где мы не используем транзакции Spring. Что-то вроде
performTransaction() {
doWSCall();
// no need to worry about WS call exception, because DB call won't happen
try {
doDbCall()
} catch (Exception ex) {
rollbackWSCall()
// rethrow ex
}
}
где все методы являются абстрактными.
Комментарии:
1. Отличный ответ, спасибо! Я думаю, что блокировка на уровне строк — лучшее решение. Но просто блокировки на уровне строк недостаточно, поскольку транзакция все еще может удерживать длительную блокировку для одной или нескольких строк, которые важны для активного пользователя. Похоже, что MVCC (multi-version-concurrency-control) является лучшим решением, ориентированным на базу данных. Это позволяет полностью избежать блокировки записи, позволяя по-прежнему считывать предыдущую версию, пока открыта транзакция обновления. Таким образом, разрешаются длительные обновления.
Ответ №2:
Я бы не стал смешивать вызов веб-службы с вызовом базы данных. Ваш метод нарушает правило, которое гласит «делайте что-то хорошо».
Попросите вашу службу вызвать другие веб-службы и DAO.
Комментарии:
1. Мой метод service выполняет две вещи: 1) вызывает другой метод service, который выполняет webservice, и 2) вызывает метод DAO. Но транзакции обычно обрабатываются на уровне сервиса, что означает, что обе они охватываются одной транзакцией, что в конечном итоге и является проблемой.