MySQL มุ่งมั่นที่จะไม่เห็นข้อมูลเพื่อเลือกแบบสอบถาม


13

บริบท: เฟรมเวิร์กที่ใช้คือ Spring และเคียวรีทั้งหมดรันด้วย JdbcTemplate เซิร์ฟเวอร์ Mysql คือ 5.6.19 tableเป็นInnoDB tableและค่าเริ่มต้นเหมือนauto commitและระดับการแยกทำซ้ำอ่านเป็นชุด

ปัญหา : Insertเกิดขึ้นภายในธุรกรรมและselectที่อ่านข้อมูลเดียวกันที่แทรกไว้ไม่เห็นข้อมูล selectวิ่งหลังจากinsertและหลังการทำธุรกรรมมีinsertcommited

ฉันได้เปิดใช้งาน bin log รวมถึง log ทั่วไปใน mysql แล้ว บันทึกที่เกี่ยวข้องด้านล่าง

ถังเข้าสู่ระบบ:

SET TIMESTAMP=1438265764/*!*/;
BEGIN
/*!*/;
# at 249935389
#150730 14:16:04 server id 1  end_log_pos 249935606 CRC32 0xa6aca292    Query   thread_id=40    exec_time=0     error_code=0
SET TIMESTAMP=1438265764/*!*/;
insert into user_geo_loc_latest(user_id, lat, lng) values(x,y,z) on duplicate key update lat=y, lng=z
/*!*/;
# at 249935606
#150730 14:16:06 server id 1  end_log_pos 249936255 CRC32 0x2a52c734    Query   thread_id=40    exec_time=0     error_code=0
SET TIMESTAMP=1438265766/*!*/;
INSERT INTO table(txnid) VALUES ('885851438265675046')
/*!*/;
# at 249936255
#150730 14:16:06 server id 1  end_log_pos 249936514 CRC32 0x6cd85eb5    Query   thread_id=40    exec_time=0     error_code=0
SET TIMESTAMP=1438265766/*!*/;
INSERT INTO table2(x) VALUES (y)
/*!*/;
# at 249936514
#150730 14:16:06 server id 1  end_log_pos 249936545 CRC32 0xceb9ec56    Xid = 9406873
COMMIT/*!*/;

บันทึกการสืบค้น

150730 14:16:04    40 Query ...
....
40 Query     select count(*) from table where txnid = '885851438265675046'
                   40 Query     select @@session.tx_read_only
                   40 Query     INSERT INTO table(txnid) VALUES ('885851438265675046')
                   40 Query     select @@session.tx_read_only
                   40 Query     INSERT INTO table2(x) values(y)
                   40 Query     commit
....
150730 14:16:07    36 Query     select pp.*, b.create_date from table pp left join bill b on pp.bill_id = b.bill_id where pp.txnid = '885851438265675046'

อยากรู้อยากเห็นครั้งแรกinsert(249935389) ไม่ควรเป็นส่วนหนึ่งของการทำธุรกรรมทั้งหมด เป็นการเรียก API ที่แยกต่างหากและไม่เกี่ยวข้องอย่างสมบูรณ์ อาจเป็นการผสมกับธุรกรรมหรือฉันกำลังอ่านบันทึกที่ไม่ถูกต้อง AFAIK เนื่องจากมีอยู่ในเธรดเดียวกันซึ่งแสดงถึงการแทรกอยู่ในธุรกรรม

สองรายการถัดไปinsertsเป็นส่วนหนึ่งของธุรกรรมและดูเหมือนว่าจะกระทำ (249936514) ตอนนี้แบบสอบถามแบบใช้เลือกข้อมูล (แบบสอบถามสุดท้ายในบันทึกทั่วไป) จะทำงานหลังจากการส่งข้อมูลและจะไม่เห็นข้อมูล ส่งคืน 0 แถว สิ่งนี้จะเกิดขึ้นเมื่อพิจารณาจากข้อมูลได้committedอย่างไร หรือcommitไม่อยู่ในเธรด 40? เนื่องจากมันไม่มี id ของเธรด

เพื่อสรุปฉันมีสองคำถาม

  1. การทำงานBEGINใน binlog อยู่ก่อนหน้านี้INSERT INTO user_geo_loc(ซึ่งไม่ได้เป็นส่วนหนึ่งของการทำธุรกรรม) หรือไม่นี่เป็นข้อผิดพลาดของ spring / Jdbc หรือ MySql เพียงแค่ทำสิ่งนี้เพราะรู้ว่าธุรกรรมนี้ได้ทำไปแล้ว (เนื่องจากธุรกรรมถูกเขียนลงใน binlog สำเร็จแล้ว) ดังนั้นจะไม่มีการย้อนกลับ

  2. การให้คอมมิชชันเกิดขึ้นก่อนการเลือก (commit อยู่ที่ 14:16:06 และ select เป็นเวลา 14:16:07) การเลือกไม่ส่งคืนแถวที่แทรกโดยธุรกรรม?

นี่มันน่างงมาก ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชม

หมายเหตุ: แบบสอบถามทั้งในถังขยะและบันทึกแบบสอบถามได้รับการแก้ไขเพื่อลบข้อมูลที่ละเอียดอ่อน แต่สาระสำคัญของการสืบค้นยังคงเหมือนเดิม

แก้ไข: อัปเดตด้วยบันทึกทั่วไปและบันทึกแบบสอบถามพร้อมด้วยตัวอย่างโดยละเอียด


คุณติดแท็ก 5.5 แต่กล่าวถึง 5.6; มันคืออะไร การจำลองแบบมีส่วนเกี่ยวข้องหรือไม่?
Rick James

@RickJames ขออภัยมันคือ 5.6.19 ฉันได้อัปเดตคำถามด้วยตัวอย่างจากทั้งคิวรีและบันทึกถังขยะ นอกจากนี้ยังไม่มีการจำลองแบบที่เกี่ยวข้องฉันเปิดใช้งานบันทึกถังขยะเท่านั้นหลังจากสังเกตเห็นปัญหาในการตรวจแก้จุดบกพร่อง ขอบคุณ
Ahmed Aeon Axan

ขอบคุณที่ช่วย ฉันไม่เห็นหรือBEGIN START TRANSACTIONคุณใช้แทนautocommit=0ไหม (ฉันชอบเริ่มต้น ... กระทำมันทำให้ขอบเขตของการทำธุรกรรมชัดเจน)
Rick James

ดังนั้นเฟรมเวิร์ก (สปริง) จะจัดการธุรกรรมและโดยปกติแล้วจะตั้งค่า autocommit = 0 และกระทำในตอนท้าย ฉันเดาว่าเราไม่เห็น autocommit = 0 ที่นี่เพราะการเชื่อมต่ออยู่ในสถานะนั้นแล้ว
Ahmed Aeon Axan

คำตอบ:


3

ฉันพยายามตั้งสมมติฐานเกี่ยวกับคำถามที่สอง:

การให้คอมมิชชันเกิดขึ้นก่อนการเลือก (commit อยู่ที่ 14:16:06 และ select เป็นเวลา 14:16:07) การเลือกไม่ส่งคืนแถวที่แทรกโดยธุรกรรม?

ธุรกรรมได้รับการจัดการโดย Spring ดังนั้นจึงอาจเป็นไปได้ว่าก่อนที่จะเรียกใช้selectสปริงได้เพิ่มstart transactionหรือมีการใช้การเชื่อมต่อสำหรับการเรียกใช้แบบสอบถามอื่นแล้ว

ฉันเริ่มเซสชันแรกที่ฉันจำลองการแทรกลงในตารางt:

session1> create table t (i int auto_increment primary key);
Query OK, 0 rows affected (0,32 sec)

session1> insert into t values();
Query OK, 1 row affected (0,00 sec)

session1> select * from t;
+---+
| i |
+---+
| 1 |
+---+
1 row in set (0,00 sec)

session1> start transaction;
Query OK, 0 rows affected (0,00 sec)

session1> insert into t values();
Query OK, 1 row affected (0,00 sec)

ฉันสร้างเซสชันใหม่เซสชัน 2 ซึ่งautocommitถูกตั้งค่าเป็น 0 ในเซสชันใหม่นี้ธุรกรรมจะเริ่มโดยปริยายเมื่อเรียกใช้ตัวเลือก

session2> set autocommit = 0;
Query OK, 0 rows affected (0,00 sec)

session2> select * from t;  -- this starts a transaction
+---+
| i |
+---+
| 1 |
+---+
1 rows in set (0,00 sec)

ย้ายไปที่ session1 เพื่อยืนยันการแทรก

session1> commit;

ตอนนี้ย้ายอีกครั้งไปที่ session2:

session2> select * from t;
+---+
| i |
+---+
| 1 |
+---+
1 row in set (0,00 sec)

Session2 ไม่เห็นแถวที่เพิ่งแทรก ถ้า a commitถูกยกขึ้นใน session2 เราจะเห็นแถวใหม่ที่แทรกใน session1

session2> commit
1 row in set (0,00 sec)

session2> select * from t;
+---+
| i |
+---+
| 1 |
| 2 |
+---+
2 rows in set (0,00 sec)

บันทึกทั่วไปมีลักษณะดังนี้:

150804 14:04:10     2 Query select * from t

150804 14:04:30     1 Query start transaction
150804 14:04:39     1 Query insert into t values ()
150804 14:04:44     1 Query commit
150804 14:04:51     2 Query select * from t

150804 14:05:07     2 Query commit
150804 14:05:10     2 Query select * from t

แถวแรกเกี่ยวข้องกับเซสชั่น 2 เมื่อเซสชัน 2 เปิดธุรกรรม

ฉันไม่รู้ว่านี่คือสิ่งที่เกิดขึ้นในกรณีของคุณหรือไม่ คุณสามารถตรวจสอบในบันทึกทั่วไปของคุณว่า connection_id 36 ใช้สำหรับการสืบค้นอื่น ๆ หรือไม่ แจ้งให้เราทราบ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.