У меня есть 2 таблицы без транзакций. Я хочу выполнить "вставку" на один и "обновить" на другой.
Я хочу сделать это атомарно, оба должны пройти или оба не должны.
Как это сделать для не транзакционных таблиц? Я использую MySql
Используйте блокировка:
LOCK TABLES t1, t2 WRITE;
...
UNLOCK TABLES;
ПРИМЕЧАНИЕ:, если какой-либо из запросов завершился неудачей, вам придется вручную отменить их! Поэтому убедитесь, что вы собрали INSERT_ID()
или некоторые другие способы определения строк, которые вы вставляете. (10x ring0)
Если это слишком часто происходит в вашем приложении - вы получите ужасную производительность. В этом случае вам лучше переключиться на InnoDB со своей функцией блокировки строк и транзакциями.
И убедитесь, что вы ВСЕГДА либо отключите сразу после этой операции, либо выполните запрос UNLOCK TABLES
! В противном случае (например, забыть разблокировать/умереть с исключением при использовании постоянного соединения с БД - в итоге вы столкнулись с тупиком!)
Без механизма транзакций вам необходимо защитить код чтения и записи, который будет обращаться к базе данных.
Некоторые псевдокоды для выполнения операций записи и чтения в критических разделах, защищенных с помощью семафора:
Semaphore sem;
bool method write (data) {
lock(sem);
ok = do (insert data into table);
prevdata = do (select olddata from table2);
ok2 = do (update data into table2);
if (ok && !ok2) do (delete date from table);
else if (!ok && ok2) do (update olddata into table2);
unlock(sem);
return (ok && ok2);
}
datacontainer method read () {
lock (sem);
data = do (select data from table);
unlock(sem);
return data;
}
datacontainer method read2 () {
lock (sem);
data = do (select data from table2);
unlock(sem);
return data;
}
Синхронизация может быть оптимизирована в зависимости от ваших потребностей.
Если вы можете использовать InnoDB, это намного проще: в коде MySQL
START TRANSACTION;
INSERT INTO table (...) VALUES (...);
UPDATE table2 SET data=... WHERE ...;
COMMIT;