LINUX.ORG.RU

Одновременное изменение одной записи в БД с разных соединений


0

0

Проблема: есть строка в таблице БД, которая может одновременно редактироваться несколькими (например двумя) пользователями с разных соединений, при этом если не предпрнимать никаких мер, то пользователь сохранивший изменения последним, затрёт изменения сделанные предыдущим пользователем.

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

Как можно решить эту проблему?

База данных MySQL 4.1, т.к. в конторе для которой я это делаю она и стоит, а админ ничего другого ставить не хочет. Но в принципе варианты с другими СУБД тоже возможны, если будут веские причины, то модно будет пробить и установку другой базы.

Самому мне в голову приходят следующие варианты: 1. При сохранении записи в базу проверяется, чтобы запись в базы была бы в таком же состоянии как и при считывании. Если запись в другом состоянии, предложить замёрджить изменения в ручную. минусы такого подхода: надо делать новую форму для мёрджа

2. Запустить на сервере отдельный процесс, который все клиенты будут информировать, какие документы открыты на редактирование, и разрещать редактировать один документ только одному человеку клиенту одновременно. минусы такого подхода: разграничение доступа на добровольных началах, т.е. левая программа всё равно сможет поменять базу в обход этого процесса

новый велосипед == cvs?

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

Хранить версии желания нет.

Т.к. это именно база данных с информацией о клиентах. (Поэтому это не RCS, CVS, SVN, git, darcs, monotone, codeville и даже не Visual Source Safe боже упаси, как и не любой другой VCS)

Толку от разных версий нет, т.к. в любом случае запись болжна быть ОДНА, и кто-то должен будет принять решение о том какая из них правильная.

Вопрос скорее про лочинье записей в БД и транзакции. Т.к. я в них не силён, а прогу писать надо...

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

>в любом случае запись болжна быть ОДНА, и кто-то должен будет принять решение о том какая из них правильная

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

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

Информация о клиентах, ну пусть будет: имя, фамилия, ИНН, не суть важно короче.

К базе есть подключения с разных машин, разных опреаторов и т.д. Понятно, что это ненормальная ситуация когда два оператора правят одного клиента, но такая ситуация ВОЗМОЖНА.

И меня интересует способ красиво разрулить такую ситуацию.

Т.е. что происходит: Оператор 1 делает что-то типа: SELECT * FROM clients WHERE id = 123;

Данные отображаются на форме, затем он их правит в течении 5 минут и нажимает кнопку сохранить, и происходит что-то типа:

UPDATE clients SET name="Vasya", last_name="Pupkin" WHERE id=123;

И всё бы было хорошо, но в это время Оператор2 тоже успел под редактировать клиента: SELECT * FROM clients WHERE id = 123; UPDATE clients SET name="Pupa", last_name="Vasykin" WHERE id=123;

Т.е. клиент станет Vasya Pupkin, хотя он мог бы быть Pupa Vasykin если бы апдейты прошли в другом порядке. Понятно что это идиотская ситуация, но надо же предусмотреть способ разруливания такой ситуации.

Если использовать SELECT * FROM clients WHERE id=123 FOR UPDATE; UPDATE clients SET name="Pupa", last_name="Vasykin" WHERE id=123;

То другие операторы даже не смогут сделать SELECT * FROM clients; пока не будет сделан UPDATE

В принципе нашёл в инете такой вариант: сделать столбец version и каждый раз при изменении информации мнкрементировать его и перед UPDATE-ом проверять что версия в базе не изменилась.

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

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

На 4-ке. тип таблиц InnoDB

set autocommit=0;
begin;
SELECT * FROM t;
/* лочим запись */
UPDATE t SET col1=col1 where PK_ID=123;
/* редактируем */
/* обновляем */
UPDATE t SET /* то что надо */ where PK_ID=123;
/* кладем изменения в базу */
commit;

не проверял, но работать должно.

При дефолтном уровне изоляции один апдейтит все читают.
Лучше перед тем как принимать решение стоит прочитать про уровни изоляции транзакций в MySQL(доки есть на сайте dev.mysql.com) и выбрать то что подходит тебе.

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

Хм.. но второй оператор чуть позже все равно сможет все изгадить )) Тут как-то по другому надо разрулить.. на клиенте лучше всего... Какое-нибудь предупреждение оператору что лиент уже есть в базе и не надо его данные менять.. Если я правильно понял конечно..

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

Проблема решается так, по крайней мере с MySQL 4.1: Тип таблицы InnoDB, уровень изоляции транзакций REPEATABLE READ или READ COMMITTED, READ UNCOMMITTED не пробовал, т.к. это не изоляция а фигня какая-то.

Первый: set autocommit=0; begin; select * from clients where id=1 for update; ..... ..... update clients set name="Pupkin" wherer id=1; commit;

В это время второй может спокойно сделать: select * from clients и ничего не заблокируется (на уровне SERIALIZABLE - заблокируется :-)

А если он захочет чего-то изменить и скажет: begin; select * from clients where id=1 for update;

То эта комманда подвиснет до тех пор пока первый не сделает commit или пока не вывалится по таймауту.

Т.е. потери данных при таком способе не произойдёт. Единственно жалко, что если какой балбес тупо сделайт UPDATE без предварительного SELECT .... FOR UPDATE то вся защита пойдёт коту под хвост, но это в любом случае не хуже чем защита на уровне клиента.

Всем спасибо за участие

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

А вы кнопочку сделайте

"Редактировать" - а по ее нажатии активируйт кнопку сохранить.
и при нажатии на нее делайте свой for update. Ну и если ошибка то соответсвенно пишите в клиентах типа запись заблокирована редактировать запрещено. К сожалению не в курсе какие локи поддерживает MySQL.

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