|
|
|
Hibernate+Spring transactions. Не понимаю некоторые вещи.
|
|||
|---|---|---|---|
|
#18+
Решил поразбираться с транзакциями, а именно с вопросом конкуррентого доступа к данным. Использую две сущности. Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. Код: java 1. 2. 3. 4. 5. 6. 7. Суть транзакции 1)По айди берем цену машины 2)Увеличиваем цену на 10 и обновляем машину 3)В историю цен пишем запись Реализация Код: 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. Вызов Код: 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. Результаты: 1) Вызов Код: java 1. Нету syncronized - как итог, метод увеличения цены вызвался два раза а в истории цен записано 20,20. 2) Код: java 1. Присутствует synchronized и flush в dao, результат корректен, два вызова - две цены 20,30 3) carAuctionService.increasePriceProblemSynchronizedNoFlush(1, sleep); Присутствует synchronized и НЕТ flush в dao, результат некорректен, два вызова - две цены 20,20. Вот тут непонятно. Стоит synchronized, вызовы последовательные, а транзакция такое ощущение что по окончанию метода не закомитилась что ли? А когда я в цикле вызываю Код: java 1. , то все норм. Тут получается что транзакция закомитилась после окончания метода, а когда в два потока , то нет. Когда транзакция завершается, по выходу из метода или как? 4) Код: java 1. Тут вообще жесть Код: html 1. 2. 3. 4. 5. Помогите пожалуйста разобраться. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2017, 15:50 |
|
||
|
Hibernate+Spring transactions. Не понимаю некоторые вещи.
|
|||
|---|---|---|---|
|
#18+
Проблема понимания вызвана тем что вы намешали в кучу несколько разных проблем и пытаитесь их понять как "транзакцию". Хотя каждую из этих проблем надо понимать отдельно. 1) Транзакция влияет на то чтобы вы вычитали текущее состояние и на то чтобы вы записали то что вы хотите записать. А за урегулирование многопоточного обновления данных влияют блокировки и неблокирующие алгоритмы, которые транзакциям перпендиклулярны. Блокировки могут быть реализованы как в Java, так и в БД. 2) flush тоже транзакциям немного перпендикулярен. 3) Нет, транзакция не комитится по завершению метода. Spring её закомитит при завершении того метода, в котором он её начал. В вашем примере мне до конца не понятно действительно ли работает @Transactional. Или спринг его проигнорировал. 4) Это не жесть. Это так работает SERIALIZABLE в Oracle. Читаем мануал: http://docs.oracle.com/cd/E11882_01/server.112/e40540/consist.htm#CNCPT1320 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2017, 16:24 |
|
||
|
Hibernate+Spring transactions. Не понимаю некоторые вещи.
|
|||
|---|---|---|---|
|
#18+
Спасибо, за ответ и все таки Транзакции работают нормально, проверил так Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. Код: java 1. 2. 3. BlazkowiczSpring её закомитит при завершении того метода, в котором он её начал. Тогда мне непонятно, почему вызов вот этих методов дает разные результаты Код: java 1. 2. Методы то в обоих случаях из-за synchronized вызываются последовательно, значит результат должен быть в обоих случаях одинаковым, а именно 20 и 30 в таблице истории. И судя из BlazkowiczSpring её закомитит при завершении того метода, в котором он её начал. Перед вызовом метода, метод должен видеть результаты камита, но результаты то разные. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2017, 16:54 |
|
||
|
Hibernate+Spring transactions. Не понимаю некоторые вещи.
|
|||
|---|---|---|---|
|
#18+
justcoderМетоды то в обоих случаях из-за synchronized вызываются последовательно, значит результат должен быть в обоих случаях одинаковым, а именно 20 и 30 в таблице истории. И судя из BlazkowiczSpring её закомитит при завершении того метода, в котором он её начал. Перед вызовом метода, метод должен видеть результаты камита, но результаты то разные. Потому как результат не связан с флашем. У вас два потока, две транзакции, два коммита. Если два коммита прошло, значит транзакции прошли. А что именно у вас там комитилось, сказать сложно, так как мы видим только часть кода. Надо бы ещё понимать что EntityManager это тоже не аналог транзакции. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2017, 17:30 |
|
||
|
Hibernate+Spring transactions. Не понимаю некоторые вещи.
|
|||
|---|---|---|---|
|
#18+
BlazkowiczПотому как результат не связан с флашем. У вас два потока, две транзакции, два коммита. Да, все верно два потока и две транзакции, но код самого потока включает один и тот же объект CarAuctionService, метод которого synchronized , и по окночании которого Spriung должен закомитть транзакциию. Потоки вызывают один и тот же метод одного и того же объекта. И мне непонятно, почему когда один и тот же метод одного и того же объекта вызывается в разных потоках, то транзакция камититься не сразу после завершения метода который помечен аннотацией @Transactional, а когда я тоже самое делает в цикле то все в порядке. Я специально поставил synchronized , а так как объект один и тот же для разных потоков, то вызовы должны идти последовательно, они и идут, а транзакции не камитятся сразу же,после выхода из метода. А если я flush добавляю, то все норм. Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. Этот код полный. Код: xml 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. Вот мои DAO Код: 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. Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2017, 17:45 |
|
||
|
Hibernate+Spring transactions. Не понимаю некоторые вещи.
|
|||
|---|---|---|---|
|
#18+
Потому что flush меняет порядок записи в базу. В случае с flush вы сразу пытаетесь сохранить изменение в БД. В случае без явного flush, запись в БД происходит позже - во время закрытие EntityManager-а и коммита транзакции. Чтобы понять как именно влияет flush, стоит посмотреть порядок запросов в логе и сравнить. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2017, 17:50 |
|
||
|
Hibernate+Spring transactions. Не понимаю некоторые вещи.
|
|||
|---|---|---|---|
|
#18+
Разница в том что scope транзакции больше чем scope метода синхронизации. Когда вы вышли из метода, Spring начинает процесс флаша, закрытие сессии и коммит транзакции. Но в это время блокировка synchronized уже освобождена, поэтому второй поток читает старые данные из БД. Он коммита ещё не видит. В случае с flush - запись в БД происходит во время flush. А при выходе из synchronized коммит происходит раньше чем чтение данных вторым потоком. Поэтому второй поток уже видит обновленные данные. Нужно понимать что ни в том, ни в другом случае гарантий у вас нет. И если вдруг ресурсы компьютера будут заняты, то порядок действий может поменяться, как и результат работы вашего кода. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2017, 17:55 |
|
||
|
Hibernate+Spring transactions. Не понимаю некоторые вещи.
|
|||
|---|---|---|---|
|
#18+
Но тогда получается что транзакция не комитится сразу после завершения метода , который помечен аннотацией @transactional. авторSpring её закомитит при завершении того метода, в котором он её начал. Код: java 1. 2. 3. В однопоточной среде Код: java 1. 2. 3. 4. В многопоточной, используем тот же объект Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2017, 18:01 |
|
||
|
Hibernate+Spring transactions. Не понимаю некоторые вещи.
|
|||
|---|---|---|---|
|
#18+
BlazkowiczРазница в том что scope транзакции больше чем scope метода синхронизации. Когда вы вышли из метода, Spring начинает процесс флаша, закрытие сессии и коммит транзакции. Но в это время блокировка synchronized уже освобождена, поэтому второй поток читает старые данные из БД. Он коммита ещё не видит. В случае с flush - запись в БД происходит во время flush. А при выходе из synchronized коммит происходит раньше чем чтение данных вторым потоком. Поэтому второй поток уже видит обновленные данные. Нужно понимать что ни в том, ни в другом случае гарантий у вас нет. И если вдруг ресурсы компьютера будут заняты, то порядок действий может поменяться, как и результат работы вашего кода. Вот, да. Я просто думал что транзакция будет закомичена после выхода из метода. Тогда что ж получается, В однопоточной среде Код: java 1. 2. 3. 4. Что даже здесь нет гарантий, что при последующем проходе метод не увидит свежих данных, так что ли? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2017, 18:05 |
|
||
|
Hibernate+Spring transactions. Не понимаю некоторые вещи.
|
|||
|---|---|---|---|
|
#18+
justcoderНо тогда получается что транзакция не комитится сразу после завершения метода , который помечен аннотацией Ну, потому что "сразу" это субъективная характеристика. Для того чтобы закрыть транзакцию, нужно закрыть сессию (entitymanager aka hibernate session aka unit of work aka level 1 cache). Для того чтобы закрыть сессию, нужно её состояние сохранить в БД. То есть вызвать flush. Всё это происходит "сразу" после выхода из метода. Но ещё раньше происходит высвобождение блокировки synchronized. Если увеличить scope synchronized и вынести его за пределы метода, то, вероятно, эффект от flush-а исчезнет. Код: java 1. 2. 3. Потому что транзакция будет внутри блокировки, а не снаружи. justcoder.//Я ожидал что тут будут данные которые закомичены первым вызовом, а по факту нет из описания процесса у вас потерялся synchronized. Ваш поток выглядит так 1. начали транзакцию 2. захватили лок 3. вычитали данные 4. освободили лок 5. закомитили транзакцию. "вычитали данные" может произойти в любой момент после 4. То есть , это может быть до 5 - когда коммит не произошел, а может быть после 5 - когда коммит произошел. Поэтому значение которое вы вычитали вышей синхронизацией не определяется. Наличие\отсутствие flush влияет на только сколько времени просиходит между 4 и 5. Поэтому второй поток в зависимости от flush, то успевает, то не успевает. Но если у вас будет достаточно быстрая система, второй поток может всегда не успевать. А если достаточно медленная, то всегда успевать, и не важно будет там flush или нет. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2017, 18:15 |
|
||
|
Hibernate+Spring transactions. Не понимаю некоторые вещи.
|
|||
|---|---|---|---|
|
#18+
justcoderдумал что транзакция будет закомичена после выхода из метода. Ну, так и есть. Где у вас получилось иначе? justcoderЧто даже здесь нет гарантий, что при последующем проходе метод не увидит свежих данных, так что ли? Нет, не так. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2017, 18:16 |
|
||
|
Hibernate+Spring transactions. Не понимаю некоторые вещи.
|
|||
|---|---|---|---|
|
#18+
Спасибо вам, теперь все стало понятно. В однопоточный среде (или в цикле) все работает так как положено потому что все идёт последовательно: вызов метода, закрытие сессии, вызов flush и т.д. И лишь потом снова в цикле вызовется транзакционный метод. Ну а так как все эти действия (Закрытие место , flush и т.д.) завершились то очередной вызов метода в цикле видит свежие закомиченные данные. Спасибо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2017, 18:29 |
|
||
|
|

start [/forum/topic.php?fid=59&msg=39423469&tid=2123050]: |
0ms |
get settings: |
8ms |
get forum list: |
14ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
68ms |
get topic data: |
9ms |
get forum data: |
2ms |
get page messages: |
48ms |
get tp. blocked users: |
1ms |
| others: | 224ms |
| total: | 380ms |

| 0 / 0 |
