Зачем мне нужна транзакция в спящем режиме для операции только для чтения?


зачем мне нужна транзакция в спящем режиме для операции только для чтения?
Ставит ли следующая транзакция блокировку на БД?

пример кода для выборки из БД:

Transaction tx = HibernateUtil.getCurrentSession().beginTransaction(); // why begin transaction?
//readonly operation here

tx.commit() // why tx.commit? I don't want to write anything


Могу ли я использовать session.close() вместо tx.commit()??

4 76

4 ответа:

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

  1. транзакции для чтения могут выглядеть действительно странно, и часто люди не отмечают методы для транзакций в этом случае. Но JDBC все равно создаст транзакцию, просто она будет работать в autocommit=true если параметр не задан явно.
  2. но нет никакой гарантии, что ваш метод не пишет в базу данных. Если вы отмечаете метод как @Transactional(readonly=true), Весна установит JDBC транзакция в режиме только для чтения, таким образом, вы будете диктовать, является ли это на самом деле возможна запись в БД в рамках данной транзакции. Если ваша архитектура довольно громоздка, и некоторые члены команды могут не следовать разумному пути, этот флаг укажет вам на проблемное место.
  3. также транзакции только для чтения могут быть оптимизированы DBs, но это, конечно, специфично для DB. Например, MySQL добавил поддержку для этого только в InnoDB, начиная с версии 5.6.4.
  4. если вы не используете JDBC напрямую, а скорее ORM, что может быть проблематичным. Например, сообщество Hibernate говорит, что работа вне транзакции может вызвать непредсказуемое поведение. Это связано с тем, что Hibernate откроет транзакцию, но не закроет ее самостоятельно, поэтому соединение будет возвращено в пул соединений, когда транзакция не будет зафиксирована. Что же тогда происходит? JDBC молчит, таким образом, это специфическая реализация (MySQL откатывает транзакцию, Oracle afair фиксирует ее). Это также может быть настроено на уровне пула соединений (например, C3P0 дает вам такую опцию, откат по умолчанию).
  5. другое дело, когда дело доходит до спящего режима, Spring устанавливает FlushMode в ручную в случае транзакций только для чтения, что приводит к другим оптимизациям, таким как отсутствие необходимости в грязных проверках.
  6. вы можете переопределить или явно установить уровень изоляции транзакций. Это также влияет на транзакции чтения, так как вы делаете или не хотите читать незафиксированные изменения, быть под воздействием фантомных чтений и т. д.

подводя итог-вы можете пойти в обе стороны, но вам нужно понять последствия.

все операторы базы данных выполняются в контексте физической транзакции,даже если мы явно не объявляем границы транзакций (НАЧАТЬ/COMMIT И ROLLBACK).

Если вы не объявляете границы транзакций явно, то каждый оператор должен быть выполнен в отдельной транзакции (autocommit режим). Это может даже привести к открытию и закрытию одного соединения на инструкцию, если ваша среда не может иметь дело с соединением на поток обязательный.

объявление услуги как @Transactional даст вам одно соединение на всю длительность транзакции, и все операторы будут использовать это одно соединение изоляции. Это лучше, чем не использовать явные транзакции в первую очередь.

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

JPA не применяет транзакции к операциям чтения. Только записи в конечном итоге вызывают исключение транзакции, необходимое в случае, если вы забыли запустить транзакционный контекст. Тем не менее, всегда лучше объявлять границы транзакций даже для транзакций только для чтения (весной @Transactional позволяет отмечать транзакции только для чтения, что имеет большое преимущество в производительности).

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

теперь, если Вам повезет и ваши запросы к БД таковы, что ORM всегда сопоставляет их с отдельными SQL-запросами, вы можете уйти без явно транзакции, опираясь на встроенное поведение автоматической фиксации БД, но ORMs являются относительно сложными системами, поэтому совсем не безопасно полагаться на такое поведение, если вы не перейдете к гораздо большей работе, проверяя, что на самом деле делает реализация. Написание явной транзакции границы в гораздо проще получить правильно (особенно если вы можете сделать это с помощью AOP или какой-либо аналогичной ORM-управляемой техники; от Java 7 и далее try-with-resources тоже может использоваться, я полагаю).

не имеет значения, читаете ли вы только или нет - база данных все равно должна отслеживать ваш набор результатов, потому что другие клиенты базы данных могут захотеть записать данные, которые изменят ваш набор результатов.

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