ก่อนอื่นวิธีการเขียนโปรแกรมการแทรกชุด JDBC สามวิธีได้รับการแนะนำเพื่อเปรียบเทียบ เนื้อหาเฉพาะมีดังนี้
การแทรกแบทช์ JDBC ส่วนใหญ่จะใช้สำหรับการนำเข้าข้อมูลและการบันทึกเนื่องจากบันทึกโดยทั่วไปจะเขียนในไฟล์ก่อน
ฉันใช้ไดรเวอร์ JDBC ของ MySQL 5.1.5 เพื่อทดสอบวิธีการที่ใช้กันทั่วไปอีกสามวิธี
วิธีที่ 1: ใช้ PreparedStatement เพื่อเพิ่มแบทช์
ลอง {class.forname ("com.mysql.jdbc.driver"); conn = drivermanager.getConnection (O_URL, ชื่อผู้ใช้, รหัสผ่าน); conn.setautocommit (เท็จ); String sql = "แทรก adlogs (ip, เว็บไซต์, yyyymmdd, ชั่วโมง, object_id) ค่า (?,?,?,?,?)"; PreparedStatement perst = conn.preparestatement (SQL, resultset.type_scroll_sensitive, resultset.curcur_read_only); สำหรับ (int x = 0; x <size; x ++) {prest.setstring (1, "192.168.1.1"); prest.setstring (2, "localhost"); prest.setstring (3, "20081009"); prest.setint (4, 8); prest.setstring (5, "11111111"); prest.addbatch (); } prest.executeBatch (); Conn.Commit (); conn.close (); } catch (sqlexception ex) {logger.getLogger (mylogger.class.getName ()). log (level.severe, null, ex); } catch (classnotFoundException ex) {logger.getLogger (mylogger.class.getName ()). log (level.severe, null, ex); - อธิบายความหมายของพารามิเตอร์สองตัวต่อไปนี้เมื่อสร้างคำสั่ง:
พารามิเตอร์แรกระบุประเภทของผลลัพธ์ ตัวเลือกคือ:
type_forward_only: ประเภทเริ่มต้น การเข้าถึงไปข้างหน้าได้รับอนุญาตเพียงครั้งเดียวและจะไม่ได้รับผลกระทบจากการเปลี่ยนแปลงของผู้ใช้รายอื่นในฐานข้อมูล
type_scroll_insensitive: อนุญาตให้มีการเคลื่อนไหวไปข้างหน้าหรือย้อนกลับในรายการและแม้กระทั่งการวางตำแหน่งเฉพาะเช่นการย้ายไปยังระเบียนที่สี่ในรายการหรือย้ายสองระเบียนย้อนกลับจากตำแหน่งปัจจุบัน มันจะไม่ได้รับผลกระทบจากการเปลี่ยนแปลงของผู้ใช้รายอื่นในฐานข้อมูล
type_scroll_sensitive: เช่น type_scroll_insensitive การวางตำแหน่งจะได้รับอนุญาตในบันทึก ประเภทนี้ได้รับผลกระทบจากการเปลี่ยนแปลงของผู้ใช้รายอื่น หากผู้ใช้ลบบันทึกหลังจากดำเนินการสืบค้นบันทึกนั้นจะหายไปจาก ResultSet ในทำนองเดียวกันการเปลี่ยนแปลงค่าข้อมูลจะปรากฏในชุดผลลัพธ์
พารามิเตอร์ที่สองตั้งค่าการเกิดขึ้นพร้อมกันของชุดผลลัพธ์ซึ่งกำหนดว่าสามารถอัปเดตชุดผลลัพธ์ได้หรือไม่ ตัวเลือกคือ:
concur_read_only: นี่คือค่าเริ่มต้นระบุว่าไม่สามารถอัปเดตได้
resultset concur_updatable: ระบุว่าสามารถอัปเดตชุดผลลัพธ์ได้
วิธีที่ 2: ใช้คำสั่งเพื่อเพิ่มวิธีแบทช์
conn.setautocommit (เท็จ); คำสั่ง stmt = conn.createstatement (resultset.type_scroll_sensitive, resultet.concur_read_only); สำหรับ (int x = 0; x <size; x ++) {stmt.addbatch ("แทรกลงใน adlogs (ip, เว็บไซต์, yyyymmdd, ชั่วโมง, object_id) ค่า ('192.168.1.3', 'localhost', '20081009', 8, '23123') } stmt.executeBatch (); Conn.Commit ();วิธีที่ 3: ใช้คำสั่งโดยตรง
conn.setautocommit (เท็จ); คำสั่ง stmt = conn.createstatement (resultset.type_scroll_sensitive, resultet.concur_read_only); สำหรับ (int x = 0; x <size; x ++) {stmt.execute ("แทรกลงใน adlogs (ip, เว็บไซต์, yyyymmdd, ชั่วโมง, object_id) ค่า ('192.168.1.3', 'localhost', '20081009', 8, '23123') } conn.commit (); เวลาทดสอบเฉลี่ยสำหรับการแทรกข้อมูล 100,000 ชิ้นโดยใช้วิธีการข้างต้นคือ:
วิธีที่ 1: 17.844S
วิธีที่ 2: 18.421s
วิธีที่ 3: 16.359s
จะเห็นได้ว่าการแทรกคำสั่งแบทช์ JDBC ไม่เพียง แต่ไม่เพียง แต่ปรับปรุงประสิทธิภาพ แต่ช้ากว่าเมื่อไม่มีการใช้แบทช์ แน่นอนว่าสิ่งนี้อาจเกี่ยวข้องกับวิธีการใช้งานของไดรเวอร์เฉพาะของ JDBC สิ่งที่แนบมาคือรหัสทดสอบของฉันซึ่งสามารถใช้ทำงานบนคอมพิวเตอร์ของฉันได้
เมื่อทำการแทรกแบทช์สิ่งที่สำคัญที่สุดคือการยกเลิกการส่งโดยอัตโนมัติดังนั้นจึงไม่สำคัญว่าจะใช้ไวยากรณ์แบทช์ของ JDBC หรือไม่
conn.setautocommit (เท็จ)
โดยส่วนตัวแล้วฉันคิดว่าวิธีแรกคือวิธีที่สะดวกและใช้งานได้จริงที่สุด
ตัวอย่างคำอธิบาย ของข้อมูลการแทรกชุด JDBC :
เมื่อเร็ว ๆ นี้เมื่อฉันทำงานในโปรแกรมเพื่อนำเข้าข้อมูล Excel ไปยังฐานข้อมูลฉันกำลังเตรียมที่จะใช้การแทรกชุด JDBC เนื่องจากข้อมูลจำนวนมาก ดังนั้นจึงใช้ preperestatement.addbatch (); เมื่อมีการเพิ่มข้อมูล 1W ชิ้นส่วนการแทรกจะดำเนินการจะใช้ PreparedStatement.executeBatch () ฉันคิดว่านี่คงจะเร็ว แต่ใช้เวลานานกว่า 30 นาทีในการแทรกข้อมูล 65,536 ชิ้นซึ่งเกินความคาดหมายของฉันอย่างสมบูรณ์ ดังนั้นฉันจึงถามเพื่อนร่วมงานของฉันว่าพวกเขาประมวลผลการนำเข้าข้อมูลขนาดใหญ่แบบนี้ได้อย่างไร ฉันพบว่าพวกเขายังใช้การประมวลผลการแทรกชุด JDBC แต่ต่างจากฉันพวกเขาใช้ con.setautocommit (เท็จ); จากนั้น preparedStatement.executeBatch () จากนั้นดำเนินการ con.commit (); ดังนั้นฉันจึงลองอีกครั้งปาฏิหาริย์คืออะไร? ใช้เวลาเพียงครึ่งชั่วโมงในการนำเข้าข้อมูลเหล่านี้และหลังจากเพิ่มสองประโยคนี้ใช้เวลาเพียง 15 วินาทีในการทำให้เสร็จ ดังนั้นฉันจึงตรวจสอบเหตุผลและพบคำอธิบายต่อไปนี้ทางออนไลน์:
* เมื่อนำเข้าข้อมูลไปยัง InnoDB ตรวจสอบให้แน่ใจว่า MySQL ไม่ได้เปิดใช้งานโหมด AutoCommit เนื่องจากสิ่งนั้น
ต้องใช้บันทึกการล้างไปยังดิสก์สำหรับทุกเม็ดมีด เพื่อปิดการใช้งาน autocommit ในระหว่างการดำเนินการนำเข้าของคุณล้อมรอบด้วย
ตั้งค่าคำสั่งอัตโนมัติและคำสั่ง:
ตั้งค่า autocommit = 0;
... งบนำเข้า SQL ...
ให้สัญญา;
ครั้งแรกมันเป็นเพราะไม่มี setautocommit (เท็จ); สำหรับแต่ละคำสั่งแทรกบันทึกจะถูกสร้างขึ้นเป็นดิสก์ ดังนั้นแม้ว่าการตั้งค่าแบทช์จะถูกตั้งค่า แต่เอฟเฟกต์ก็เหมือนเม็ดมีดเดียวส่งผลให้มีการแทรกช้ามาก
รหัสบางส่วนมีดังนี้:
String sql = "แทรกลงในตาราง *****"; con.setautocommit (เท็จ); ps = con.prepareStatement (SQL); สำหรับ (int i = 1; i <65536; i ++) {ps.addbatch (); // แทรก 1W บันทึกหนึ่งครั้งถ้า (i % 10,000 == 0) {ps.executeBatch (); Con.Commit (); }} // แทรกน้อยกว่า 1W data ps.executeBatch (); Con.Commit ();ด้านบนเป็นเพียงเครื่องเคียงจากนั้น "เสิร์ฟ" ตามด้วย:
1. การทดสอบแบทช์ข้อมูลการเขียน
Long Start = System.currentTimeMillis (); daorecord daorecord = new daorecord (); รายการ <t> list = new ArrayList <T> (); สำหรับ (int i = 1; i <= 1000; i ++) {สำหรับ (int j = 1; j <= 1000; j ++) {t t = ใหม่ t (); t.seti (i); t.setj (j); list.add (t); }} daorecord.insertBatch (รายการ); System.out.println ("ใช้เวลานาน:" + (System.currentTimeMillis ()-เริ่มต้น) + "MS"); 2. การทดสอบข้อมูลการเขียนแบบแบทช์
โมฆะสาธารณะ INSERTBATCH (รายการ <T> รายการ) {String SQL = "แทรกลงในค่า t (ไปกลับ) (?,?)"; dbhelper dbh = new dbhelper (SQL); การเชื่อมต่อ conn = dbh.returnconn (); ลอง {conn.setautocommit (false); // โปรดทราบว่าประโยคนี้จะต้องเป็นเท็จดูการอ้างอิงครั้งแรกที่เตรียมการ PS = conn.prepareStatement (SQL); สำหรับ (int i = 0; i <list.size (); i ++) {ps.setint (1, list.get (i) .geti ()); ps.setint (2, list.get (i) .getJ ()); ps.addbatch (); if (i % 10,000 == 0) {ps.executeBatch (); Conn.Commit (); }} ps.executeBatch (); Conn.Commit (); conn.close (); } catch (sqlexception e) {// todo สร้างบล็อก catch block โดยอัตโนมัติ E.printStackTrace (); -ตารางข้อมูล:
ผลการทดลอง:
ข้างต้นเป็นเรื่องเกี่ยวกับบทความนี้ฉันหวังว่ามันจะเป็นประโยชน์กับการเรียนรู้ของทุกคน