Artikel ini akan membawa anda memahami transaksi dalam MySQL dan memperkenalkan prinsip MVCC saya harap ia dapat membantu anda!
Transaksi pangkalan data merujuk kepada satu set operasi data Operasi dalam urus niaga sama ada semuanya berjaya atau gagal, dan tiada apa yang dilakukan, tetapi sebahagian daripadanya mungkin dilakukan, tetapi selagi Jika satu langkah gagal, semua operasi mesti digulung semula, yang merupakan sedikit operasi tanpa henti.
Dalam MySQL, sokongan transaksi dilaksanakan pada lapisan enjin. MySQL ialah sistem yang menyokong berbilang enjin, tetapi tidak semua enjin menyokong transaksi. Sebagai contoh, enjin MyISAM asli MySQL tidak menyokong transaksi, yang merupakan salah satu sebab penting mengapa MyISAM digantikan oleh InnoDB .
1.1 Empat ciri utama
1.2 Tahap Pengasingan
Antara empat ciri utama transaksi SQL, atomicity, konsistensi dan ketahanan semuanya agak mudah untuk faham. Tetapi tahap pengasingan transaksi sememangnya lebih sukar Hari ini kita akan bercakap mengenai pengasingan transaksi MySQL.
Pengasingan transaksi standard SQL dari tahap rendah ke tahap tinggi ialah: baca tanpa komitmen, baca komited, baca berulang dan boleh bersiri ). Semakin tinggi tahap, semakin rendah kecekapan .
1.3 Isu serentak diselesaikan
Tahap pengasingan urus niaga SQL direka bentuk untuk menyelesaikan isu konkurensi sepenuhnya:
Tahap pengasingan transaksi SQL yang berbeza boleh menyelesaikan masalah konkurensi yang berbeza, seperti yang ditunjukkan dalam jadual berikut: Hanya tahap pengasingan bersiri menyelesaikan ketiga-tiga masalah, dan yang lain 3 Setiap tahap pengasingan mempunyai kelemahan.
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | 可能 | 可能 | 可能 |
读已提交 | 不可能 | 可能 | 可能 |
可重复读 | 不可能 | 不可能 | 可能 |
串行化 | 不可能 | 不可能 | 不可能 |
PS: Mudah untuk mengelirukan bacaan tidak berulang dan bacaan hantu memfokuskan pada pengubahsuaian, dan bacaan hantu memfokuskan pada penambahan atau pemadaman. Untuk menyelesaikan masalah bacaan tidak berulang, anda hanya perlu mengunci baris yang memenuhi syarat Untuk menyelesaikan masalah bacaan hantu, anda perlu mengunci jadual
1.4 Untuk. contoh,
seperti ini Mungkin agak sukar untuk difahami, jadi berikan saya contoh. Masih struktur jadual dan data jadual sebelumnya
CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `age` int(11) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 66 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
Katakan sekarang, saya mahu memulakan dua makanan pada masa yang sama, transaksi A pertanyaan id = 2 Umur pelajar, transaksi B mengemas kini umur pelajar dengan id = 2. Prosesnya adalah seperti berikut. Apakah nilai X1, X2, dan X3 di bawah empat tahap pengasingan?
Lalu mengapa keputusan ini berlaku? Bagaimanakah tahap pengasingan transaksi dilaksanakan?
Bagaimanakah tahap pengasingan transaksi dilaksanakan? Saya menemui jawapan dalam kelas Cikgu Ding Qi pada Masa Geek:
Malah, paparan akan dibuat dalam pangkalan data, dan hasil logik paparan akan diutamakan apabila mengakses. Di bawah tahap pengasingan "Baca Berulang", paparan ini dibuat apabila transaksi bermula dan digunakan sepanjang transaksi. Di bawah tahap pengasingan "komit baca", pandangan ini dibuat pada permulaan setiap pernyataan SQL. Apa yang perlu diperhatikan di sini ialah di bawah tahap pengasingan "baca tidak komited", nilai terkini pada rekod dikembalikan secara langsung, tanpa konsep pandangan manakala di bawah tahap pengasingan "sirialisasi", penguncian digunakan secara langsung untuk mengelakkan selari; akses .
1.5 Tetapkan tahap pengasingan transaksi
Pangkalan data yang berbeza mempunyai tahap pengasingan transaksi lalai yang sangat berbeza Tahap pengasingan lalai pangkalan data Oracle ialah Read-commit, manakala MySQL ialah Repeatable Read. Oleh itu, apabila sistem anda perlu memindahkan pangkalan data daripada Oracle ke MySQL, sila tetapkan tahap agar selaras dengan itu sebelum pemindahan (read-commit) untuk mengelakkan masalah yang tidak dapat diramalkan .
1.5.1 Lihat tahap pengasingan transaksi
# 查看事务隔离级别 5.7.20 之前 SELECT @@transaction_isolation show variables like 'transaction_isolation'; # 5.7.20 以及之后 SELECT @@tx_isolation show variables like 'tx_isolation' +---------------+-----------------+ | Variable_name | Value | +---------------+-----------------+ | tx_isolation | REPEATABLE-READ | +---------------+-----------------+
1.5.2 Tetapkan tahap pengasingan
Format pernyataan untuk mengubah suai tahap pengasingan ialah: tetapkan [skop] tahap pengasingan transaksi [tahap pengasingan transaksi]
Skop adalah pilihan: SESI (sesi), GLOBAL (global) ; Tahap pengasingan adalah empat yang dinyatakan di atas dan tidak peka huruf besar-kecil.
Contohnya: Tetapkan tahap pengasingan global untuk membaca komited
set global transaction isolation level read committed;
1.6 Permulaan transaksi
Permulaan transaksi MySQL Terdapat beberapa cara:
# 更新学生名字 START TRANSACTION; update student set name = '张三' where id = 2; commit;
理解了隔离级别,那事务的隔离是怎么实现的呢?要想理解事务隔离,先得了解 MVCC 多版本的并发控制这个概念。而 MVCC 又依赖于 undo log 和 read view 实现。
2.1 什么是 MVCC?
百度上的解释是这样的:
MVCC,全称 Multi-Version Concurrency Control,即多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。
MVCC 使得数据库读不会对数据加锁,普通的 SELECT 请求不会加锁,提高了数据库的并发处理能力;数据库写才会加锁。 借助 MVCC,数据库可以实现 READ COMMITTED,REPEATABLE READ 等隔离级别,用户可以查看当前数据的前一个或者前几个历史版本,保证了 ACID 中的 I 特性(隔离性)。
MVCC 只在 REPEATABLE READ 和 READ COMMITIED 两个隔离级别下工作。其他两个隔离级别都和 MVCC 不兼容 ,因为 READ UNCOMMITIED 总是读取最新的数据行,而不是符合当前事务版本的数据行。而 SERIALIZABLE 则会对所有读取的行都加锁。
2.1.1 InnDB 中的 MVCC
InnDB 中每个事务都有一个唯一的事务 ID,记为 transaction_id。它在事务开始时向 InnDB 申请,按照时间先后严格递增。
而每行数据其实都有多个版本,这就依赖 undo log 来实现了。每次事务更新数据就会生成一个新的数据版本,并把 transaction_id 记为 row trx_id。同时旧的数据版本会保留在 undo log 中,而且新的版本会记录旧版本的回滚指针,通过它直接拿到上一个版本。
所以,InnDB 中的 MVCC 其实是通过在每行记录后面保存两个隐藏的列来实现的。一列是事务 ID:trx_id;另一列是回滚指针:roll_pt。
2.2 undo log
回滚日志保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读。
根据操作的不同,undo log 分为两种: insert undo log 和 update undo log。
2.2.1 insert undo log
insert 操作产生的 undo log,因为 insert 操作记录没有历史版本只对当前事务本身可见,对于其他事务此记录不可见,所以 insert undo log 可以在事务提交后直接删除而不需要进行 purge 操作。
purge 的主要任务是将数据库中已经 mark del 的数据删除,另外也会批量回收 undo pages
所以,插入数据时。它的初始状态是这样的:
2.2.2 update undo log
UPDATE 和 DELETE 操作产生的 Undo log 都属于同一类型:update_undo。(update 可以视为 insert 新数据到原位置,delete 旧数据,undo log 暂时保留旧数据)。
事务提交时放到 history list 上,没有事务要用到这些回滚日志,即系统中没有比这个回滚日志更早的版本时,purge 线程将进行最后的删除操作。
Satu transaksi mengubah suai data semasa:
Satu transaksi lain mengubah suai data:
Terdapat berbilang versi rekod yang sama dalam pangkalan data, iaitu MVCC kawalan penukaran berbilang versi yang dinyatakan di atas.
Selain itu, anda boleh menggunakan log batal untuk kembali ke keadaan versi sebelumnya. Sebagai contoh, untuk kembali ke V1, anda hanya perlu melakukan dua rollback mengikut urutan.
2.3 paparan baca
pandangan baca ialah pandangan baca yang konsisten yang digunakan oleh InnDB semasa melaksanakan MVCC untuk menyokong Pelaksanaan RC ( Read Committed) dan tahap pengasingan RR (Repeatable Read) .
pandangan baca tidak benar-benar wujud, ia hanyalah satu konsep, dan buat asal log ialah penjelmaannya. Ia terutamanya dikira melalui versi dan undolog. Fungsinya adalah untuk menentukan data apa yang boleh dilihat oleh transaksi.
Setiap transaksi atau penyata mempunyai pandangan konsistensi tersendiri. Pernyataan pertanyaan biasa ialah bacaan yang konsisten menentukan keterlihatan versi data berdasarkan trx_id baris dan paparan yang konsisten.
2.3.1 Peraturan keterlihatan versi data
Paparan baca terutamanya mengandungi transaksi baca dan tulis aktif lain dalam sistem semasa pelaksanaan, InnDB membina tatasusunan untuk setiap transaksi untuk menyimpan transaksi aktif (belum diserahkan) pada masa ini apabila transaksi dimulakan.
Seperti yang dinyatakan sebelum ini, ID transaksi meningkat dengan ketara mengikut masa Nilai maksimum ID transaksi yang diserahkan dalam sistem direkodkan sebagai paras air rendah tatasusunan, dan ID transaksi 1 yang dibuat ialah. direkodkan sebagai paras air yang tinggi.
Tatasusunan pandangan ini dan paras air yang tinggi membentuk pandangan konsistensi transaksi semasa (pandangan baca)
Lukis gambar tatasusunan ini, ia kelihatan seperti ini:
Peraturannya adalah seperti berikut:
3 Jika ia berada di kawasan hijau, akan terdapat dua situasi:
Mata ketiga saya melihat saya agak keliru semasa tutorial, tetapi mujurlah beberapa netizen yang bersemangat menjawab:
jatuh di kawasan hijau bermakna ID transaksi berada dalam julat paras air rendah dan paras air tinggi sama ada benar-benar kelihatan bergantung kepada sama ada terdapat nilai ini di kawasan hijau. Jika kawasan hijau tidak mempunyai ID transaksi ini, ia boleh dilihat, jika ada, ia tidak kelihatan. Berada dalam julat ini tidak bermakna julat ini mempunyai nilai ini, seperti [1,2,3,5], 4 berada dalam julat 1-5 tatasusunan ini, tetapi tidak dalam tatasusunan ini.
Ini mungkin agak sukar untuk difahami. Biar saya andaikan satu senario: tiga pertanyaan transaksi dan kemas kini data yang sama Saya melukis gambar untuk pemahaman yang lebih mudah:
.
Data asal masih seperti yang ditunjukkan di bawah Kemas kini maklumat untuk Zhang San dengan id = 2:
Saya ingin bertanya tentang gambar di atas. Di bawah tahap pengasingan RC (Read Committed) dan RR (Repeatable Read), apakah nilai umur pertanyaan masing-masing pada titik masa T4 dan T5? Apakah nilai kemas kini T4? Fikirkan sejenak, saya percaya setiap orang ada jawapannya sendiri. Jawapannya ada di penghujung artikel saya harap anda boleh teruskan membaca dengan soalan anda sendiri.
2.3.2 Keputusan di bawah RR (Baca Berulang)
Pada peringkat RR, pertanyaan hanya diterima sebelum transaksi dibuat dimulakan Untuk data lengkap yang telah diserahkan, paparan akan dibina sebaik sahaja transaksi dimulakan. Jadi gunakan transaksi mula dengan arahan syot kilat yang konsisten dan paparan akan dibuat serta-merta .
现在假设:
在这种隔离级别下,他们创建视图的时刻如下:
根据上图得,事务 A 的视图数组是[2,3];事务 B 的视图数组是 [2,3,4];事务 C 的视图数组是[2,3,4,5]。分析一波:
T4 时刻,B 读数据都是从当前版本读起,过程是这样的:
T5 时刻,A 读数据都是从当前版本读起,过程是这样的:
这样执行下来,虽然期间这一行数据被修改过,但是事务 A 不论在什么时候查询,看到这行数据的结果都是一致的,所以我们称之为一致性读。
其实视图是否可见主要看创建视图和提交的时机,总结下规律:
事务 B 的 update 语句,如果按照上图的一致性读,好像结果不大对?
如下图周明,B 的视图数组是先生成的,之后事务 C 才提交。那就应该看不见 C 修改的 age = 23 呀?最后 B 怎么得出 24 了?
没错,如果 B 在更新之前执行查询语句,那返回的结果肯定是 age = 22。问题是更新就不能在历史版本更新了呀,否则 C 的更新不就丢失了?
所以,更新有个规则:更新数据都是先读后写(读是更新语句执行,不是我们手动执行),读的就是当前版本的值,叫当前读;而我们普通的查询语句就叫快照读。
因此,在更新时,当前读读到的是 age = 23,更新之后就成 24 啦。
除了更新语句,查询语句如果加锁也是当前读。如果把事务 A 的查询语句 select age from t where id = 2 改一下,加上锁(lock in mode 或者 for update),也都可以得到当前版本 4 返回的 age = 24
下面就是加了锁的 select 语句:
select age from t where id = 2 lock in mode; select age from t where id = 2 for update;
假设事务 C 不马上提交,但是 age = 23 版本已生成。事务 B 的更新将会怎么走呢?
事务 C 还没提交,写锁还没释放,但是事务 B 的更新必须要当前读且必须加锁。所以事务 B 就阻塞了,必须等到事务 C 提交,释放锁才能继续当前的读。
2.3.3 RC(读提交)下的结果
在读提交隔离级别下,查询只承认在语句启动前就已经提交完成的数据;每一个语句执行之前都会重新算出一个新的视图。
注意:在上图的表格中用于启动事务的是 start transaction with consistent snapshot 命令,它会创建一个持续整个事务的视图。所以,在 RC 级别下,这命令其实不起作用。等效于普通的 start transaction(在执行 sql 语句之前才算是启动了事务)。所以,事务 B 的更新其实是在事务 C 之后的,它还没真正启动事务,而 C 已提交。
现在假设:
Di bawah tahap pengasingan ini, saat mereka mencipta paparan adalah seperti berikut:
Mengikut rajah di atas, tatasusunan paparan transaksi A ialah [2,3,4], tetapi paras airnya yang tinggi ialah 6 atau lebih tinggi (ID transaksi 1 telah dibuat); bagi transaksi B ialah [2,4]; tatasusunan paparan transaksi C ialah [2,5]. Gelombang analisis:
Pada masa T4, B membaca data daripada versi semasa Prosesnya adalah seperti berikut:
Pada masa T5, A membaca data dari semasa. versi. Prosesnya adalah seperti berikut:
tutorial video mysql]
Atas ialah kandungan terperinci Artikel yang menerangkan prinsip transaksi dan MVCC dalam MySQL secara terperinci. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!