2016-02-04 3 views
1

Я пытаюсь выяснить, как делать транзакции в SQLite, но я ударил стену. Предположим, я хочу перенести 50 долларов США с одного аккаунта на другой. Взгляните на следующий код. Это сильно прокомментировано.Как именно вы делаете транзакции в SQLite?

DROP TABLE IF EXISTS accounts; 
CREATE TABLE IF NOT EXISTS accounts (
    name  VARCHAR(20) NOT NULL, 
    balance INTEGER   NULL -- Money is going to be stored in cents 
); 

INSERT INTO accounts (name, balance) VALUES 
("John Doe", 10050), -- This means 100 dollars and 50 cents 
         -- because 100 dollars and 50 cents is 
         -- 100 * 100 cents + 50 cents = 10050 cents 
("Bob Smith", 20000); -- 200 dollars 



DROP VIEW IF EXISTS view_accounts; 
CREATE VIEW view_accounts AS 
    SELECT rowid, 
      name, 
      printf("$%.2f", balance/100.0) AS balance 
    FROM accounts; 

SELECT * FROM view_accounts; 
-- rowid  name  balance 
-- ---------- ---------- ---------- 
-- 1   John Doe $100.50 
-- 2   Bob Smith $200.00 



BEGIN TRANSACTION; 

-- Subtract $50 from John Doe's balance 
UPDATE accounts SET balance = balance - 5000 WHERE rowid = 1; 
-- And add $50 to Bob Smith's balance, but let's now intentionally 
-- create something erroneous here. Let's say there's been a mistake 
-- and we got the wrong rowid (maybe we received an id that does not 
-- exist in our table from a host language such as PHP, but really it 
-- could be anything from power-down to inadvertent reboot. I'm using 
-- this particular example because it's easy to emulate an exceptional 
-- situation). Instead of rowid 2, we mistakenly used a rowid of 3 
-- which does not exist in our table. 
UPDATE accounts SET balance = balance + 5000 WHERE rowid = 3; 

-- Here's where I get stuck. What exactly should my next steps be? 
-- What statements should I use here? Obviously I should roll all the 
-- changes made so far back with the ROLLBACK command if something 
-- exceptional happens, but I can't know that beforehand because the 
-- value for rowid is received from external sources. On the other hand, 
-- I can't use COMMIT either because what if in fact something 
-- exceptional did happen? I somehow need to detect that something bad 
-- has happened and conditionally either roll all the changes back or, if 
-- everything is okay, commit them. 
+0

Ошибка, которую вы описали, кажется, является проблемой в вашей бизнес-логике, поэтому, возможно, это должно быть до PHP-скрипта для ее исправления. Если ваш уровень приложения может обнаружить эту ошибку, вы можете использовать 'ROLLBACK', чтобы отменить изменения в транзакции. –

ответ

3

Вы не можете сделать это только в SQLite, так как SQLite не имеет никаких команд управления потоком.

Что вы ищете похож на этого псевдо-код:

IF rows-affected = 0 THEN ROLLBACK TRANSACTION 

Заменить ROLLBACK TRANSACTION с любым типом ответа ошибки вы хотели бы.

Поскольку в синтаксисе SQLite нет либо IF, ни синтаксиса SQLite, вы не можете сделать это без помощи языка программирования/программирования, использующего SQLite.

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

Обратите внимание, что тот факт, что вы хотите отменить транзакцию, является частью ответа на ошибку, но эта проблема не связана с транзакциями как таковыми. В основном ваш вопрос касается управления потоком.

+0

Итак, что вы говорите, я должен проверить с языка хоста, была ли проблема и принято решение либо зафиксировать изменения, либо отбросить их назад, отправив COMMIT и ROLLBACKs в среду SQLite? –

+0

Правильно, в SQLite нет синтаксиса, который может сделать это за вас. –

+0

Но как я знаю, что есть проблема с моей второй инструкцией SQL UPDATE? SQLite на самом деле не показывает ошибки, когда он находится в режиме транзакции. –

Смежные вопросы