1.19.2015

10. Транзакции баз данных. Hibernate



Давайте рассмотрим, какие интересные моменты могут случаться в "черном  ящике"  Баз Данных:

1) lost update - может случиться, когда две транзакции одновременно выполняют операцию update над некоторой записью и вторая транзакция (самая последняя транзакция по времени)  заканчивается не удачно, она откатывает все изменения внесенные первой и  второй транзакцией. Такая ситуация может случиться когда БД не использует блокировок  (locking) и конкурирующие транзакции (concurrent transactions) в ней  не изолированы друг от друга.
2) dirty read - может случиться, когда первая транзакция изменяет строку, вторая транзакция читает эту строку, первая откатывает изменения, сделанные в транзакции.  Соответственно вторая транзакция имеет не достоверные данные.
3) unrepeatable read - может случиться,  когда первая транзакция дважды читает одну и ту же строку, и получает разные результаты, в промежутке между двумя чтениями,  вторая транзакция изменяет ту же строку, и первая транзакция при повторном чтении  получает новые данные. Так же частным случаем unrepeatable read является проблема second lost updates problem.  Представьте себе, что две конкурирующих  транзакций одновременно читают одну и ту же строчку, потом первая транзакция изменяет её и завершается удачно (commit), потом вторая транзакция изменяет ту же строчку и перезаписывает данные, при этом теряются все изменения внесенные первой транзакцией.
4) phantom read - может случиться, когда одна и та же первая, транзакция читает строки дважды через какой-то промежуток времени, и вторая транзакция вставляет новую  строчку или удаляет, до второго чтения.
  
Для предотвращения этих казусов,  в ANSI SQL стандарте предусмотрены  standard isolation levels:

1) read uncommitted transaction isolation - здесь может случиться  dirty read, но никогда не случиться lost update. Ни какая транзакция не может перезаписать не подтвержденные данные, достигается за счет блокировки (exclusive write locks), однако они могут быть прочтены любой транзакцией.
2) read committed transaction isolation - здесь может случиться  unrepeatable read, но никогда не случиться dirty read. Транзакции чтения ни когда не блокируют читаемые строки, но при изменении данных, блокируются изменяемые строки.
3) repeatable read transaction isolation - здесь может случиться  phantom read, но никогда не случиться dirty read и unrepeatable read. Транзакции чтения блокируют данные строки. И в них не могут писать, ни какие свои данные транзакции, читать могут все. Транзакции записи блокируют все другие транзакции.
4) serializable transaction isolation - представьте очередь из транзакций, и они выполняются одна, за другой по "очереди", самый высший уровень блокировки.

И так отсюда следует что, чем выше уровень транзакции, тем неповоротней становиться работа с базой данных, по этому, нужно правильно выбрать устраивающий вас уровень  транзакции, чем и займемся далее. Каждая база данных имеет по умолчанию  transaction isolation level - обычно это read committed, это чаще встречается или может быть repeatable read.  Мы конечно можем изменить этот уровень в объекте java.sql.Connection драйвера JDBC:

   1—Read uncommitted isolation
   2—Read committed isolation
   4—Repeatable read isolation
   8—Serializable isolation

или в Hibernate в параметре hibernate.connection.isolation проставить,  нужный нам
уровень изоляции транзакции:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- Database connection settings -->       
        <property name="connection.username">sa</property>
        <property name="connection.password"></property>
...       
        <property name="connection.isolation">1</property>
        <!--
             1—Read uncommitted isolation
             2—Read committed isolation
             4—Repeatable read isolation
             8—Serializable isolation   -->
...
    </session-factory>
</hibernate-configuration>

при запуске приложения в логе hibernate  появятся такая строчка:

2014-09-10 21:31:32,346 INFO [org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl] - <HHH000149: JDBC isolation level: READ_UNCOMMITTED>

Если вы используете пул подключения баз данных через application server, допустим  пул jboss, то меняйте настройки у сервера,  параметр hibernate.connection.isolation не влияет на настройки application server.  Хочу обратить ваше внимание,  что у Hibernate реализованы  два механизма контроля транзакций - это version checking , версионность - это оптимистическая блокировка, реализовано через специальный внутренний механизм в Hibernate. Второй механизм - это pessimistic locking, пессимистическая блокировка  реализуется блокировками  уровня баз данных, а не самим hibernate.

Комментариев нет:

Отправить комментарий