Grails: В чем разница между незанятым сеансом и откатом транзакции? - PullRequest
10 голосов
/ 03 марта 2012

Я ТАК смущен сессиями и транзакциями. Я в основном не понимаю, в чем смысл того и другого, и меня очень смущает, когда использовать один или другой.

В чем разница между незапущенным сеансом и незафиксированной транзакцией?

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

1 Ответ

21 голосов
/ 03 марта 2012

Транзакция в Hibernate во многом аналогична транзакции в JDBC в целом. Когда вы получаете Connection от DataSource, по умолчанию используется autocommit = true, поэтому для транзакции, которая изменена на autocommit = false. Таким образом, изменения вносятся в базу данных только при явном подтверждении, а не при каждом обновлении.

Hibernate Session делает несколько вещей, но в этом случае он работает как кэш 1-го уровня. Он использует концепцию под названием «транзакционная запись за» для повышения производительности, чтобы ставить в очередь изменения в этом кэше и отправлять их в базу данных только при необходимости. Так, например, если вы извлекаете постоянный экземпляр и изменяете его в сложном многоэтапном рабочем процессе, где каждый метод, возможно, не вносит никаких изменений, или несколько, требуется только один оператор SQL для обновления, поэтому Hibernate ждет, пока не будет необходимо объединить их вместе. Хотя это не зависит от того, выполняете ли вы транзакцию - это всегда происходит.

Там, где кэш сеанса и активная транзакция собираются вместе, сбрасывается во время активной транзакции. Поскольку Hibernate ждет как можно дольше, чтобы сбросить изменения, если вы не участвуете в транзакции и сбрасываете, изменения немедленно становятся постоянными в базе данных. Так что это оптимизация производительности для уменьшения количества записей в базу данных. Но если вы находитесь в транзакции и сбрасываете сеанс, вы вносите изменения в базу данных. Но база данных хранит изменения в своей очереди транзакций. Поэтому, даже если они находятся в базе данных, они не видны другим соединениям, пока вы не совершите транзакцию.

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

Одна вещь, которая заставит Hibernate автоматически обновляться от вашего имени, это запросы. Как я уже сказал, вы можете внести много изменений в постоянные экземпляры (даже удалив их), и они просто будут помещены в очередь в кеше сеанса. Но если вы выполняете запрос (динамический поиск, критерии, HQL и т. Д.), Hibernate не может знать, повлияет ли изменение в очереди на ваш запрос. Так что это пессимистично и сбрасывает со счетов, чтобы быть уверенным, что все соответствует запросу. База данных будет использовать сброшенные, но не зафиксированные данные для вашего запроса и выдаст ожидаемые результаты. По этой причине мы рекомендуем использовать метод withNewSession при выполнении запросов в пользовательских валидаторах классов домена, чтобы не вызывать сброс текущего сеанса во время проверки, что может вызвать странное поведение.

...