MySQL データベース - MySQL トランザクション

1.コンセプト

何かを完了するために必要な一連のステップ (操作)。これらの操作は同時に成功するか失敗します。

2. 取引の基本操作

Zhang San と Li Si の口座にはそれぞれ 1,000 元があり、Zhang San は 500 元を Li Si に送金します。

-- 1 创建account表
create table tb_account(
id int(11) auto_increment,
user_name varchar(30) not null,
account_blance  int(11) not null, -- 账户余额
primary key (id)    
)ENGINE=INNODB,default charset =UTF8;

-- 2 插入数据
insert into tb_account(user_name,account_blance)
values('ZS',1000),('LS',1000);

-- 3 执行张三向李四转账500
-- ZS账户-500,LS账户+500
-- 下面两个update语句要么同时执行成功要么同时执行失败
-- 执行下列SQL语句会出现问题:张三的钱减少了,李四的钱没有加上。因为此时的两个update语句并没有使用事务来托管
update tb_account set account_blance=account_blance-500 where id=1;
-- 银行转帐异常情况:如机机房停电
update tb_account set account_blance=account_blance+500 where id=2;

3. 事務の4つの特徴

原子性: トランザクションのすべてのステップを再度分割することはできません

一貫性: 張三と李斯の口座には合計 2,000 元があり、何度送金しても総額は変わりません。

永続性: トランザクションが正常に実行される (完了する) と、データはディスク上のデータ ファイルに永続化されます。たとえば、転送が成功した場合、Zhang San の残高は 500、Li Si の残高は 1,500 になります。

分離: トランザクション A とトランザクション B は同時に 1 つのデータを処理し、相互に影響を与えません。

4. 取引の提出方法、

1) 自動送信

commit を記述する必要はなく、DML ステートメントは永続的に自動的に送信されます。

2) マニュアル提出

-- クエリの結果は、自動送信の場合は 1、手動送信の場合は 0 です。

select @@autocommit;

-- 提出方法の変更(自動提出から手動提出に変更)

set @@autocommit = 0 ;

5. 取引の基本操作

1 取引を開始する

start transaction;

2 トランザクションをコミットする

commit;

3 ロールバックトランザクション

rollback;

注: トランザクションを開始するために「トランザクション開始」を使用すると、自動送信は無効になります。

  すべての操作が正常に実行された場合は commit を使用し、トランザクションをコミットします

  例外が発生してトランザクションがロールバックされると、通常、データ (この場合は tb_account テーブル) はトランザクションが開始される前の状態にロールバックされます。

6. 転送動作

-- 1 开启事务
start transaction;
-- 2 执行SQL语句
update tb_account set account_blance=account_blance-500 where id=1;
 手机转账异常情况:转账过程中手机没电了
update tb_account set account_blance=account_blance+500 where id=2;
-- 3 如果SQL语句全部执行成功就提交事务,如果其中任何一步执行失败,立刻回滚事务
-- 此时第一个update执行成功,第二个update语句执行失败了,并没有提交事务,查询结果如下:
select * from tb_account;
/*
+----+-----------+----------------+
| id | user_name | account_blance |
+----+-----------+----------------+
|  1 | ZS        |            500 |
|  2 | LS        |           1000 |
+----+-----------+----------------+
*/
-- 问题:张三账户的余额减少了,李四账户余额没有增加。这就是脏数据
-- 此时需要将脏数据回滚到开启事务之前
rollback;
-- 回滚完毕再次查询
select * from tb_account;
-- 此时事务回滚到开启之前的状态
/*
+----+-----------+----------------+
| id | user_name | account_blance |
+----+-----------+----------------+
|  1 | ZS        |           1000 |
|  2 | LS        |           1000 |
+----+-----------+----------------+
*/
-- 一个事务一旦开启了,在没有执行commit;或者rollback;之前事务不会结束
-- 相关面试题:工作中有没有用到事务?请解释事务的概念?不使用事务会发生什么问题?使用事务能够解决什么问题?解释事务的四大特征[隔离级别]?

7. トランザクション分離レベル

トランザクション分離レベル

ダーティリード

反復不可能な読み取り

幻の読書

読み取り-未コミット

はい

はい

はい

読み取りコミット済み

いいえ

はい

はい

反復読み取り可能

いいえ

いいえ

はい

シリアル化可能

いいえ

いいえ

いいえ

 クエリ分離レベル

select @@tx_isolation

職場では 1 も 4 も使用せず、2 と 3 の間でのみ切り替えます。

MySQLのデフォルトのトランザクション分離レベルは 3 で、 Oracleのデフォルトの分離レベルは2 です。

SELECT @@global.tx_isolation; //查询全局事务
SELECT @@session.tx_isolation; //查询当前会话事务

トランザクション分離レベルのレベルを設定する

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
//测试可以不用设置全局事务
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
//(这个可以不用设,只设置上面一行就可以了进行测试了)

ダーティリード:

1 つのトランザクション (A) が、コミットされていないデータを別のトランザクション (B) から読み取ります (分離を解除します)。

  例: トランザクション A は転送用のトランザクションを開き、DML ステートメントは正常に実行されますがコミットは行われません。トランザクション B は別のウィンドウで開かれ、Select ステートメントが実行されて tb_account データを読み取り、読み取られた結果は次のデータです。トランザクション A は送信されていません。

反復不可能な読み取り:

同じトランザクション内で複数回読み取られたデータは不整合です (整合性の破壊、更新と削除)

  例: トランザクション A は転送用のトランザクションを開き、DML ステートメントは正常に実行されますが、コミットは行われません。トランザクション B は別のウィンドウで開かれ、Select ステートメントが実行されて tb_account データを読み取り、読み取り結果は正しい (1000) 、1000)。

  トランザクション A でトランザクションが送信されました。次に、トランザクション B が再度選択操作を実行し、クエリ結果は正しい (500,1500) になります。

  問題: トランザクション B は 1 つのトランザクションで tb_account テーブルに対して 2 つの選択操作を実行しましたが、2 つの操作のクエリ結果は一貫していませんでした。

ファントムの読み方:

トランザクション Aはデータを 1 つ挿入し、select を使用して結果を取得できます。このとき、トランザクション B はほぼ同時に 1 つまたは大量のデータを挿入します。このとき、トランザクション A はトランザクション B の更新を見ることができません。 (一貫性を壊す場合は、 を挿入してください)。

コミットされていないダーティ読み取りテストの読み取り:

f67e3147f2ff45fbbed5c9a1edb7c4f5.png

 トランザクションが開始されると、別のトランザクションは送信をコミットせずに、このトランザクションのステートメント更新を読み取ることができます。

ダーティ リードの問題を解決するにはどうすればよいですか? トランザクション分離レベルの変更: コミットされた読み取り

set session transaction isolation level read committed;

5daaa016c45a40418485f6987095cc4c.png

反復不可能な読み取りの問題を解決するにはどうすればよいですか? トランザクション分離レベルを「反復読み取り」反復読み取りに設定します。 

076df366e0d4488d9f087aba635263af.png

ファントム読み取り問題のデモンストレーション:

bddd074a429642bc858db7ac0a4fb183.png 

シリアル化可能なテスト

すべての問題を解決できますが、非効率であり、Java の同期に似ています。

Java はオブジェクトをロックするために synchronized を使用します。MySQL は、serializable を使用してテーブルをロックします。トランザクション A はトランザクションを開始して DML 操作を実行しますが、送信されません。このとき、トランザクション B がトランザクションを開始して選択操作を実行しますが、この時点では tb_account テーブルがトランザクション A によって占有されている (ロックされている) ため、データはクエリされません。

set session transaction isolation level serializable;

 3d470f16220b417aa5cfec7b7a5c0db8.png

 

 

おすすめ

転載: blog.csdn.net/shengshanlaolin_/article/details/128460801