LINUX.ORG.RU

Что будет, если выполнить commit() во время SQL записи?

 ,


0

1

Дано: import psycopg2

В базе данных есть две таблицы users и accounts

В двум таблицам подключены две программы (два разных процесса python)

В первой таблице есть колонка country.

Я первой программе я выполняю код:

cur.execute(f"UPDATE users SET country='{country}' WHERE email='{email}'")

Во второй программе в таблице accounts в это время выполнился conn.commit(), т.е. cur.execute не прекратил выполнение.

Может ли от этого сломаться таблица users или как делать commit только на определенные таблицы?

Второй вопрос.

В одной программе работают несколько асинронных нитей пишущих в одну таблицу, но в разные строки. Нужно ли вешать python thread блокировку перед операцией commit()?

★★★★★

Последнее исправление: steemandlinux (всего исправлений: 2)

Может ли от этого сломаться таблица users или как делать commit только на определенные таблицы?

Нет. У каждого коннекшена своя сессия. Но логика в программе может сломаться, в том смысле, что ожидается что процесс1 сохранил данные, а по факту после сохранения они были перезатерты процессом2. Если терять данные нежелательно то нужна блокировка. Блокировки бывают оптимистичными и пессимистичными. Первые можно проделать против любых баз, вторые только против поддерживающих их СУБД.

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

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

P.S. Мимокрокодил, может я вообще ничего не понял что тут за вопрос.

anonymous
()

Смотри что такое уровни изоляции транзакций.

urxvt ★★★★★
()
Ответ на: комментарий от anonymous

такое может шарить один конекшен но потокобезопасно. Не вижу причин для блокировки.

Ага, спасибо, у меня один connection

Нет. У каждого коннекшена своя сессия. Но логика в программе может сломаться, в том смысле, что ожидается что процесс1 сохранил данные, а по факту после сохранения они были перезатерты процессом2. Если терять данные нежелательно то нужна блокировка. Блокировки бывают оптимистичными и пессимистичными. Первые можно проделать против любых баз, вторые только против поддерживающих их СУБД.

Да это будет смерть данным. А сделать блокировку через базу данных?

steemandlinux ★★★★★
() автор топика
Ответ на: комментарий от steemandlinux

Можно средствами базы...

Да это будет смерть данным. А сделать блокировку через базу данных?

https://www.postgresql.org/docs/9.1/explicit-locking.html

...а можно оптимистичную на коленке написать, для этого в таблицах заводится колонка version которую нужно инкрементить при записи изменений. В отрытой транзакции перед записью изменений проверять, что исходный version не поменялся, если поменялось, значит кто-то успел первым, тогда падать с LockException или как-то обработать ситуацию.

anonymous
()
Ответ на: комментарий от anonymous

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

Я кажется понял отличие uncommited и commited.

steemandlinux ★★★★★
() автор топика
Последнее исправление: steemandlinux (всего исправлений: 1)
Ответ на: комментарий от anonymous

В отрытой транзакции перед записью изменений проверять, что исходный version не поменялся, если поменялось, значит кто-то успел первым,

Ой, я тут налажал в логике, что значит через фрейморки работаю, сам такое не пишу. Наверное сработал бы update с условием «where version = {origenalVesion}» и проверять количество обновленных записей, если 0 то генерировать LockExcetpion. Не уверен, тыж там фрейморком пользуешься для базы? Там наверняка что-то готовое уже есть. Да и блокировка фичами постгриса наверное лучше получится.

anonymous
()

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

steemandlinux ★★★★★
() автор топика
Ответ на: комментарий от steemandlinux

Если в первом приложении выполняется операция execute, а во втором commit, то после commit в первом приложении запишется результат execute первого приложения, а после второго commit запишется результат execute второго приложения? Если так, то меня это более чем устраивает.

В первом приложении выполняется execute, во втором commit:

 App1:       [select] --> [ execute update ] ---> [commit]
                |                                    |
 App2: [select] --> [ execute update ] -->[commit]   |
           |    |                            |       |
    T: ----+----+----------------------------+-------+----->
После commit в первом приложении результаты второго приложения будут затерты результатами первого приложения.

anonymous
()
Ответ на: комментарий от anonymous

commit() полностью затирает таблицы или вносит только изменяемые данные?

steemandlinux ★★★★★
() автор топика
Ответ на: комментарий от anonymous

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

steemandlinux ★★★★★
() автор топика
Последнее исправление: steemandlinux (всего исправлений: 1)

Может ли от этого сломаться таблица users или как делать commit только на определенные таблицы?

Да вообще-то на и существуют транзакции, чтобы ждать там где заблочена таблица, например на update. Сломаться может, тогда будет deadlock. Но это скорее исключение ...

Jopich1
()
Ответ на: комментарий от pon4ik

Да, оказывается у postges очень специфическая связь с вызывающим ЯП, большая часть исключений решается внутри базы, а не снаружи.

steemandlinux ★★★★★
() автор топика
Ответ на: комментарий от steemandlinux

commit исполняется для тех таблиц, которые затронуты в транзакции ( сюприз !!). Вообще можешь посомтреть - в PostgreSQL показывается где другая транзакция ждет выполнение предыдущей.

Jopich1
()
Ответ на: комментарий от steemandlinux

большая часть исключений решается внутри базы, а не снаружи.

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

Jopich1
()
Ответ на: комментарий от steemandlinux

нужно сначала поставить параметр: SET lock_timeout, чтобы вывалился exception. Ну или заранее проверять на LOCKи перед запросом ...

Jopich1
()
Последнее исправление: Jopich1 (всего исправлений: 4)

https://www.postgresql.org/docs/current/transaction-iso.html - читаешь, открываешь для себя детсадовские основы acid, прозреваешь без боли без регистрации.

нити потоки

Один коннект к базе это один нить/поток. Если два потока натравить на один коннект, даже под мутексом на каком-то уровне (кроме явного лок-бегин-...-коммит-анлок), то ты получишь просто адскую мешанину команд в коннекте. Возможно враппер очень хитрый и сам рулит коннектами, надо читать доку на него. Но скорее всего ты просто абузишь коннект с двух потоков и пока не нащупал грабли ногой.

ps. куда скатился лор, что вы обсуждаете вообще итт? Какие клиентские блокировки, какие колонки версий, какие эксцепшены, какие затирания таблиц? Ояепу что с людьми творит этот дегенератский mysql.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.