|
Hibernate блокировки - как работает пример?
|
|||
---|---|---|---|
#18+
Реализация примера из официальной доки по хиберу - оптимистическая блокировка с исключением определенного поля при проверки ентити на изменение (https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#locking-optimistic (глава - Excluding attributes)). Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83.
Метод DoInJPA: Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27.
Здесь все работает как положено. 1) В транзацкции №1 создается запись в бд. 2) В транзакции №2 эта запись читается, после чего изменяется состояние entity (поле "номер"). 3) Затем запускается вложенная транзакция №3, которая меняет поле callCount и завершается. 4) В конце завершается транзакция №2. Консоль: Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9.
Мне интеречно, что происходит, когда мы помещаем код транзакции №1 в начало транзакции №2: Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38.
Консоль: Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62.
... |
|||
:
Нравится:
Не нравится:
|
|||
07.05.2021, 16:06 |
|
Hibernate блокировки - как работает пример?
|
|||
---|---|---|---|
#18+
Пробовал расставить задержки и посмотреть, что происходит в бд: Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40.
В базе никакие изменения не происходили (удаление и сохранение новой записи). Но при этом Hiber выводит лог (delete ... ; insert ...;). Правильно ли я понимаю, что до конца транзакции никакие фзические модификации бд не происходят, а все это деле делается виртуально? А эксепшен в последнем примере вызван тем, что встроенная транзакция №3 не может завершится из-за того, что запись вроде еще не существует (она должна появиться после выполнения транзакции №2, но она в свою очередь ждет завершения транзакции №3)? ... |
|||
:
Нравится:
Не нравится:
|
|||
07.05.2021, 16:29 |
|
Hibernate блокировки - как работает пример?
|
|||
---|---|---|---|
#18+
Две транзакции не будут видеть изменения друг друга пока одна из них не закоммитит изменения. Однако если они изменяют одну и ту же строку (UPDATE/DELETE), то 2ая будет заблокирована и будет ждать пока первая не закончится. Однако в твоем примере я не вижу такой ситуации пока. Может в таблице уже эта строка на момент когда ты запускаешь пример? Например, осталась с прошлых запусков? ... |
|||
:
Нравится:
Не нравится:
|
|||
07.05.2021, 16:51 |
|
Hibernate блокировки - как работает пример?
|
|||
---|---|---|---|
#18+
Stanislav Bashkyrtsev, да она есть на момент запуска. Но почему все работает, когда очистка таблицы и создание новой записи вынесена в отдельную транзакцию, и не работает когда все это совмещено? И в первом и во втором примере происходит изменение одной и той же энтити (записи в бд). ... |
|||
:
Нравится:
Не нравится:
|
|||
07.05.2021, 17:15 |
|
Hibernate блокировки - как работает пример?
|
|||
---|---|---|---|
#18+
Да и вроде ж как для энтити используется оптимистичная блокировка. (flush mode и isolation lvl дефолтные, бд - MySql). Так если Боб в своей транзакции (в первом рабочем примере) вместе с изменением количества вызовов изменит и номер - то сработает optimistic locking и выпадет соответсвующий эксепшн. ... |
|||
:
Нравится:
Не нравится:
|
|||
07.05.2021, 17:29 |
|
Hibernate блокировки - как работает пример?
|
|||
---|---|---|---|
#18+
Интуиция подсказывает, что решение искать нужно где то тут: В первом случае когда транзакции №2 и №3 изменяют одну и ту же запись, она существует в бд (очистка таблицы и вставка записи уже закомичены в перврой транзакции). Т.е. они работают с физически существующей записью. Во втором же случае запись перед стартом существует, потом вторая транзакция удаляет все и создает новую запись и потом ее изменяет (я так понимаю где то во временных таблицах), а вот с чем работает транзакция №3 - с изначальной записью, которая была при запуске примера или записью, которую создала транзакция №2 (возможно это разные записи). Это все догадки, я еще толком не понимаю как это работает ... ... |
|||
:
Нравится:
Не нравится:
|
|||
07.05.2021, 17:44 |
|
Hibernate блокировки - как работает пример?
|
|||
---|---|---|---|
#18+
И еще момент, раз до конца транзакции изменения физически не происходят в таблице, но при этом лог хибернейта выводит, что изменения произошли (delete ..., insert ..., ), то получается что он отсылает все запросы (*.executeQuery()) в бд а она уже на своей стороне решает что с ними делать ? (Разруливает блокировки). Т.е. решение надо искать в доках СУБД? ... |
|||
:
Нравится:
Не нравится:
|
|||
07.05.2021, 17:54 |
|
Hibernate блокировки - как работает пример?
|
|||
---|---|---|---|
#18+
faustgreen, Сабж о двух параллельных транзакциях. Зачем ты все запутал третьей? ... |
|||
:
Нравится:
Не нравится:
|
|||
07.05.2021, 19:05 |
|
Hibernate блокировки - как работает пример?
|
|||
---|---|---|---|
#18+
faustgreen, вам надо копать в направлении работы RR (repeatable read) в MySQL с оптимистичными блокировками хибера: - то что во втором случае вылетает PessimisticLockException - судя по всем до запуска теста в БД что-то уже есть, и эту строку внутренняя транзакция видит - а вот то что в первом случае все проходит чисто - мне не особо очевидно (видно опыт основной с Oracle и PostgreSQL, где RC по умолчанию, дает о себе знать): раз там RR, то финальный апдейт от внешней транзакции не видит обновление версии, которое произвела внутренняя транзакция, хотя чего оно (БД) не ругается на то что обновляемая строка поменялась для меня загадка (ибо нет опыта с RR и MySQL) т.е.: faustgreen Здесь все работает как положено . 1) В транзацкции №1 создается запись в бд. 2) В транзакции №2 эта запись читается, после чего изменяется состояние entity (поле "номер"). 3) Затем запускается вложенная транзакция №3, которая меняет поле callCount и завершается. 4) В конце завершается транзакция №2. нифига оно не работает как положено ... |
|||
:
Нравится:
Не нравится:
|
|||
07.05.2021, 21:08 |
|
Hibernate блокировки - как работает пример?
|
|||
---|---|---|---|
#18+
faustgreen Stanislav Bashkyrtsev, да она есть на момент запуска. Но почему все работает, когда очистка таблицы и создание новой записи вынесена в отдельную транзакцию, и не работает когда все это совмещено? И в первом и во втором примере происходит изменение одной и той же энтити (записи в бд). 1. Перед коммитом транзакции 2. Перед select'ом 3. Если вручную вызвать flush() В твоем же коде ничего такого не происходит. Т.е. ты поменял Entity, однако UPDATE не произойдет сразу. В твоем случае он будет происходить только по выходу из doInJPA(). Поэтому 1ое обновление на самом деле запись не лочит. И 2ая транзакция спокойно обновляет запись. А вот entityManager.createQuery("Delete from Phone24") - вот он сразу выполняется, т.к. запрос написан явно. Вот этот DELETE лочит запись и не дает 2ой транзакции ее обновить. faustgreenВ первом случае когда транзакции №2 и №3 изменяют одну и ту же запись, она существует в бд (очистка таблицы и вставка записи уже закомичены в перврой транзакции).Если же таблица пустая на момент старта, то этот DELETE ничего не залочит, INSERT даже если и произойдет (зависит от ID Generation Strategy), то новую запись 2ая транзакция еще не увидит. Ну и т.к. UPDATE во 2ой транзакции ничего не увидит, то и ничего и не заблочит. ... |
|||
:
Нравится:
Не нравится:
|
|||
07.05.2021, 21:12 |
|
Hibernate блокировки - как работает пример?
|
|||
---|---|---|---|
#18+
Андрей Панфилов а вот то что в первом случае все проходит чисто - мне не особо очевидно (видно опыт основной с Oracle и PostgreSQL, где RC по умолчанию, дает о себе знать): раз там RR, то финальный апдейт от внешней транзакции не видит обновление версии, которое произвела внутренняя транзакция, хотя чего оно (БД) не ругается на то что обновляемая строка поменялась для меня загадка (ибо нет опыта с RR и MySQL) Код: java 1. 2.
Т.е. версия в принципе не обновляется, так что независимо от уровня изоляции OptimisticLockingException мы не получим если обновляем только это поле. ... |
|||
:
Нравится:
Не нравится:
|
|||
07.05.2021, 21:26 |
|
|
start [/forum/topic.php?fid=59&msg=40068987&tid=2120455]: |
0ms |
get settings: |
25ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
45ms |
get topic data: |
9ms |
get forum data: |
3ms |
get page messages: |
256ms |
get tp. blocked users: |
2ms |
others: | 405ms |
total: | 767ms |
0 / 0 |