-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path28_Transactions.sql
More file actions
246 lines (192 loc) · 7.32 KB
/
28_Transactions.sql
File metadata and controls
246 lines (192 loc) · 7.32 KB
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/**************************************************************
* MySQL 8.0 Transactions Tutorial
* This script demonstrates transaction management
* in MySQL 8.0 using InnoDB, including:
* - Basic START TRANSACTION / COMMIT / ROLLBACK.
* - SAVEPOINT and ROLLBACK TO SAVEPOINT.
* - Nested savepoints.
* - Implicit transactions (autocommit).
* - Detached / distributed transactions with XA.
* - Error handling inside transactions using EXIT HANDLER.
**************************************************************/
-------------------------------------------------
-- Region: 0. Initialization and Sample Tables
-------------------------------------------------
USE mysql_course;
DROP TABLE IF EXISTS accounts;
CREATE TABLE accounts
(
account_id INT PRIMARY KEY AUTO_INCREMENT,
account_holder VARCHAR(100) NOT NULL,
balance DECIMAL(10,2) NOT NULL
) ENGINE = InnoDB;
INSERT INTO accounts (account_id, account_holder, balance)
VALUES
(1, 'Alice', 1000.00),
(2, 'Bob', 1500.00),
(3, 'Charlie', 2000.00);
-------------------------------------------------
-- Region: 1. Basic Transaction with COMMIT / ROLLBACK
-------------------------------------------------
/*
1.1 Transfer $200 from Alice to Bob.
Check Alice's balance after the debit; commit if non-negative,
otherwise roll back.
*/
START TRANSACTION;
UPDATE accounts SET balance = balance - 200.00 WHERE account_id = 1;
UPDATE accounts SET balance = balance + 200.00 WHERE account_id = 2;
-- Verify the intermediate state (only visible within this transaction)
SELECT account_id, account_holder, balance FROM accounts;
-- Commit if Alice's balance remains non-negative
-- In a stored procedure you would test @@ROWCOUNT / a SELECT result;
-- here we inspect inline:
SELECT balance INTO @alice_balance FROM accounts WHERE account_id = 1;
-- MySQL does not support inline IF in a plain SQL script the same way
-- T-SQL does; wrap the decision in a BEGIN...END block or a procedure.
-- Shown as a procedure call in Region 5.
COMMIT;
-------------------------------------------------
-- Region: 2. Rolling Back on Error
-------------------------------------------------
/*
2.1 Demonstrate ROLLBACK when an error is detected.
*/
START TRANSACTION;
UPDATE accounts SET balance = balance - 5000.00 WHERE account_id = 2; -- overdraft
SET @bob_balance = (SELECT balance FROM accounts WHERE account_id = 2);
-- Bob cannot go below zero – roll back the bad debit
ROLLBACK;
SELECT account_id, account_holder, balance FROM accounts;
-------------------------------------------------
-- Region: 3. Transaction with SAVEPOINT
-------------------------------------------------
/*
3.1 SAVEPOINT lets you roll back a portion of a transaction without
abandoning the whole unit of work.
*/
START TRANSACTION;
SAVEPOINT sp_after_debit;
UPDATE accounts SET balance = balance - 500.00 WHERE account_id = 2;
UPDATE accounts SET balance = balance + 500.00 WHERE account_id = 3;
-- If Bob's balance is negative, roll back only to the savepoint
SET @bob_bal = (SELECT balance FROM accounts WHERE account_id = 2);
-- Simulating an insufficient-funds check:
-- ROLLBACK TO SAVEPOINT sp_after_debit; -- uncomment to test rollback path
COMMIT;
SELECT account_holder, balance FROM accounts;
-------------------------------------------------
-- Region: 4. Autocommit Behaviour
-------------------------------------------------
/*
4.1 With autocommit ON (MySQL default), each statement is its own
transaction. Disable it to group statements manually.
*/
SHOW VARIABLES LIKE 'autocommit';
-- Disable autocommit for the session
SET autocommit = 0;
UPDATE accounts SET balance = balance + 100 WHERE account_id = 1;
-- At this point the change is pending in the current transaction.
-- Another session cannot see it yet (with default READ COMMITTED or
-- REPEATABLE READ isolation).
ROLLBACK; -- discard the pending change
SET autocommit = 1; -- restore default
-- Confirm balance is unchanged
SELECT account_holder, balance FROM accounts WHERE account_id = 1;
-------------------------------------------------
-- Region: 5. Transaction Decision Inside a Stored Procedure
-------------------------------------------------
/*
5.1 wrap the commit/rollback decision inside a procedure so it can
use IF logic together with a transaction.
*/
DROP PROCEDURE IF EXISTS TransferFunds;
DELIMITER //
CREATE PROCEDURE TransferFunds(
IN p_from_id INT,
IN p_to_id INT,
IN p_amount DECIMAL(10,2)
)
BEGIN
DECLARE v_from_balance DECIMAL(10,2);
DECLARE v_sqlstate CHAR(5) DEFAULT '00000';
DECLARE v_message TEXT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
v_sqlstate = RETURNED_SQLSTATE,
v_message = MESSAGE_TEXT;
ROLLBACK;
SELECT v_sqlstate AS sqlstate, v_message AS error_message;
END;
START TRANSACTION;
UPDATE accounts SET balance = balance - p_amount WHERE account_id = p_from_id;
UPDATE accounts SET balance = balance + p_amount WHERE account_id = p_to_id;
SELECT balance INTO v_from_balance
FROM accounts
WHERE account_id = p_from_id;
IF v_from_balance < 0 THEN
ROLLBACK;
SELECT 'Insufficient funds – transaction rolled back.' AS result;
ELSE
COMMIT;
SELECT 'Transfer committed successfully.' AS result;
END IF;
END //
DELIMITER ;
/*
5.2 Valid transfer: Bob to Charlie.
*/
CALL TransferFunds(2, 3, 300.00);
SELECT account_holder, balance FROM accounts;
/*
5.3 Invalid transfer: debit more than Alice has.
*/
CALL TransferFunds(1, 3, 9999.00);
SELECT account_holder, balance FROM accounts;
-------------------------------------------------
-- Region: 6. Nested Savepoints
-------------------------------------------------
/*
6.1 You can set multiple named savepoints and roll back selectively.
*/
START TRANSACTION;
UPDATE accounts SET balance = balance + 50 WHERE account_id = 1; -- step 1
SAVEPOINT sp_step1;
UPDATE accounts SET balance = balance + 50 WHERE account_id = 2; -- step 2
SAVEPOINT sp_step2;
UPDATE accounts SET balance = balance + 50 WHERE account_id = 3; -- step 3
-- Undo only step 3 and step 2; keep step 1
ROLLBACK TO SAVEPOINT sp_step1;
-- Verify: Alice +50, Bob unchanged, Charlie unchanged
SELECT account_holder, balance FROM accounts;
COMMIT;
-------------------------------------------------
-- Region: 7. XA (Distributed) Transactions
-------------------------------------------------
/*
7.1 XA transactions coordinate a two-phase commit across multiple
MySQL instances or other XA-compliant resource managers.
The XID is a tuple (gtrid, bqual [, formatID]).
*/
XA START 'xa_txn_001';
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
XA END 'xa_txn_001';
XA PREPARE 'xa_txn_001';
-- At this point the transaction is prepared; the coordinator decides.
-- Commit:
XA COMMIT 'xa_txn_001';
-- To roll back a prepared XA transaction instead:
-- XA ROLLBACK 'xa_txn_001';
/*
7.2 List prepared XA transactions (useful for recovery after a crash).
*/
XA RECOVER;
-------------------------------------------------
-- Region: 8. Cleanup
-------------------------------------------------
DROP PROCEDURE IF EXISTS TransferFunds;
DROP TABLE IF EXISTS accounts;
-------------------------------------------------
-- Region: End of Script
-------------------------------------------------