1. คำนำ
เมื่อใช้ Java เพื่อพัฒนาซอฟต์แวร์แอปพลิเคชันระดับองค์กร Spring+MyBatis+MySQL มักจะใช้ในการสร้างกรอบฐานข้อมูล หากปริมาณข้อมูลมีขนาดใหญ่ห้องสมุด MySQL จะเก็บประสิทธิภาพการเข้าถึงข้อมูลต่ำมากและมักจะใช้วิธีการจัดการการจัดเก็บข้อมูลย่อยย่อย บทความนี้อธิบายถึงวิธีการสร้างสถาปัตยกรรมการเข้าถึงแบบหลายชั้นผ่าน Spring+MyBatis และใช้มัลติเธรดเพื่อปรับปรุงประสิทธิภาพการเข้าถึงฐานข้อมูล
ควรสังเกตว่าวิธีนี้เหมาะสำหรับสถานการณ์ที่จำนวนฐานข้อมูลและชื่อได้รับการแก้ไขและไม่ใหญ่โดยเฉพาะ ในการตอบสนองต่อสถานการณ์ที่จำนวนฐานข้อมูลไม่ได้รับการแก้ไขฉันจะเขียนแผนการประมวลผลอื่นในภายหลัง
2. แผนโดยรวม
3. การเตรียมสภาพแวดล้อมการพัฒนา
3.1 ดาวน์โหลด Spring, MyBatis, MySQL ส่วนประกอบ
3.2 Eclipse: Java Development IDE มีการแนะนำแพ็คเกจขวดต่อไปนี้:
โครงสร้างรหัสมีดังนี้:
4. สร้างคลัสเตอร์ฐานข้อมูล
สร้างฐานข้อมูล 11 ฐานใน MySQL (test1/2/3/4/5/6/7/7/8/9/10/11) เพื่อสร้างตารางง่าย ๆ :
แทรกข้อมูล 50 ล้านชิ้นลงในตาราง TBL_DEMO ใน TEST1 และข้อมูล 5 ล้านชิ้นลงในตาราง TBL_DEMO ในฐานข้อมูลอีก 10 ฐานข้อมูล (ใช้ฟังก์ชั่น)
แทรกข้อมูล 50 ล้านชิ้นลงในตาราง TBL_DEMO ใน TEST1 และข้อมูล 5 ล้านชิ้นลงในตาราง TBL_DEMO ในฐานข้อมูลอีก 10 ฐานข้อมูล (ใช้ฟังก์ชั่น)
5. สร้างอินเทอร์เฟซการแมปฐานข้อมูล MyBatis
/** * อินเทอร์เฟซการแมป mybatis * * * @author elon * @version 1.0, 23 ตุลาคม 2015 */ส่วนต่อประสานสาธารณะ idemo {โมฆะสาธารณะ InsertDemo (Demodao Demo); รายการสาธารณะ <จำนวนเต็ม> selectgroup ();}/** * * อินเตอร์เฟสบริการการแมป mybatis * * @author elon * @version 1.0, 23 ตุลาคม 2015 */ส่วนต่อประสานสาธารณะ idemoservice {โมฆะสาธารณะ InsertDemo (Demodao Demo); รายการสาธารณะ <จำนวนเต็ม> selectgroup ();}/** * * การใช้บริการแมป MyBatis การใช้งาน * * @author elon * @version 1.0, 23 ตุลาคม 2015 */DemoserviceImpl ระดับสาธารณะ โมฆะสาธารณะ SetIdemo (Idemo Idea) {this.idemo = Idea; } @Override โมฆะสาธารณะ InsertDemo (Demodao Demo) {ideamo.insertdemo (ตัวอย่าง); } @Override รายการสาธารณะ <จำนวนเต็ม> selectGroup () {return idea.selectGroup (); -6. สร้างการจัดการข้อมูลประจำตัวฐานข้อมูลและแหล่งข้อมูลแบบไดนามิก
/** * * บันทึกรหัสฐานข้อมูล แต่ละเธรดจะถูกเก็บไว้โดยวัตถุอิสระ * * @author elon * @version 1.0, 23 ตุลาคม 2015 */คลาสสาธารณะ dbindetifier {private static threadlocal <string> dbkey = new ThreadLocal <String> (); โมฆะคงที่สาธารณะ setDBKEY (สตริงสุดท้าย dbkeypara) {dbkey.set (dbkeypara); } สตริงคงที่สาธารณะ getDBKEY () {return dbkey.get (); }}/*** แหล่งข้อมูลแบบไดนามิก ฐานข้อมูลที่แตกต่างกันสามารถเชื่อมต่อได้ตามดัชนีข้อมูลที่แตกต่างกัน * * @author elon * @version 1.0, 23 ตุลาคม 2015 */คลาสสาธารณะ DynamicDataSource ขยาย AbstractroutingDataSource {@Override วัตถุสาธารณะกำหนด -7. สร้างวัตถุการเข้าถึงฐานข้อมูล
/** * * วัตถุการเข้าถึงฐานข้อมูล ใช้เพื่อแทรกข้อมูล * * @author elon * @version 1.0, 23 ตุลาคม 2015 */ชั้นเรียนสาธารณะ Demodao {ส่วนตัว int a; สตริงส่วนตัว B; INT ส่วนตัว C; สาธารณะ int geta () {return a; } โมฆะสาธารณะ seta (int a) {this.a = a; } สตริงสาธารณะ getB () {return b; } โมฆะสาธารณะ setB (สตริง b) {this.b = b; } public int getc () {return c; } โมฆะสาธารณะ setc (int c) {this.c = c; }}/** * คำจำกัดความผลลัพธ์การแมป * * @author elon * @version 1.0, 23 ตุลาคม 2015 */คลาสสาธารณะ demoresult ใช้ serializable {/** * ความคิดเห็นสำหรับ <code> serialVersionuid </code> <br> * */ส่วนตัว ผลรวมยาวส่วนตัว; Public Long Getsum () {ผลรวมผลรวม; } โมฆะสาธารณะ setsum (ผลรวมยาว) {this.sum = sum; } @Override สตริงสาธารณะ toString () {return string.valueof (ผลรวม); -8. สร้างงานการเข้าถึงฐานข้อมูล
/*** นิยามงานการเข้าถึงฐานข้อมูล แพคเกจแต่ละคำขอไปยังการเข้าถึงฐานข้อมูลลงในวัตถุงานวางไว้ในการจัดการงานแล้วรอการดำเนินการงานเพื่อให้เสร็จสมบูรณ์และดึงผลลัพธ์การดำเนินการ * * @author elon * @version 1.0, 23 ตุลาคม 2015 */คลาสสาธารณะ DBTASK ใช้งาน {// ข้อมูลข้อมูลฐานข้อมูลการดำเนินงานที่ใช้เพื่อระบุฐานข้อมูลที่เข้าถึงได้ สอดคล้องกับคำจำกัดความแหล่งข้อมูลแบบไดนามิกข้อมูลในไฟล์การกำหนดค่าสปริง สตริงสุดท้ายส่วนตัว dbkey; // MyBatis ฐานข้อมูลการเข้าถึงวัตถุส่วนตัววัตถุสุดท้าย dbaccessObject; // ชื่อวิธีการเข้าถึงฐานข้อมูล MySbatis ซึ่งใช้เพื่อสะท้อนการโทรส่วนตัววิธีสุดท้ายของสตริงสุดท้าย; // จัดเก็บค่าของพารามิเตอร์ตัวแปรส่วนตัววัตถุสุดท้าย [] paraarray; // จัดเก็บประเภทพารามิเตอร์ตัวแปร @SuppressWarnings ("Rawtypes") คลาสสุดท้ายส่วนตัว [] Paraclassarray; // ผลการดำเนินการฐานข้อมูล การดำเนินการแบบสอบถามส่งคืนผลลัพธ์การสืบค้น ส่วนแทรกลบและแก้ไขการดำเนินการส่งคืนค่า NULL Operateresult วัตถุส่วนตัว; // ข้อมูลข้อยกเว้นที่ถูกส่งโดยข้อยกเว้นฐานข้อมูลการดำเนินการข้อยกเว้นส่วนตัว; // ระบุว่างานได้ดำเนินการบูลีนส่วนตัวเสร็จหรือไม่ / *** constructor* @param dbkey database id* @param dbaccessObject ฐานข้อมูลการเข้าถึงวัตถุ* @param เมธอดฐานข้อมูลวิธีการเข้าถึงชื่อชื่อ* @param paraarray รายการพารามิเตอร์*/ dbtask สาธารณะ this.dbaccessObject = dBaccessObject; this.methodname = methodName; this.paraarray = paraarray; เสร็จสิ้น = false; ข้อยกเว้น = null; paraclassarray = คลาสใหม่ [paraarray.length]; สำหรับ (int index = 0; index <paraarray.length; ++ ดัชนี) {paraclassarray [index] = paraarray [index] .getClass (); } operateresult = null; } / *** ฟังก์ชั่นการดำเนินการงาน** / @Override โมฆะสาธารณะเรียกใช้ () {ลอง {dbIndetifier.setDbkey (dbkey); วิธีการ = dBaccessObject.getClass (). getMethod (MethodName, Paraclassarray); // การดำเนินการแบบสอบถามส่งคืนผลลัพธ์การสืบค้น การแทรก, ลบและแก้ไขการดำเนินการส่งคืน null operateresult = method.invoke (dbaccessobject, paraarray); } catch (Exception E) {Exception = E; E.PrintStackTrace (); } เสร็จสิ้น = true; } /** * * ส่งคืนผลการดำเนินการ การดำเนินการแบบสอบถามส่งคืนผลลัพธ์การสืบค้น แทรกลบและแก้ไขการดำเนินการส่งคืน null * * @return ผลการดำเนินการ */ วัตถุสาธารณะ getRetValue () {return operateresult; } / *** ข้อยกเว้นการดำเนินการฐานข้อมูลโยนข้อยกเว้น** @return Exception* / ข้อยกเว้นสาธารณะ getException () {return exception; } / **** ส่งคืนว่างานได้ถูกดำเนินการ** @return tag* / บูลีนสาธารณะ isfinish () {return finish; -9. สร้างตัวจัดการงานฐานข้อมูล
/*** การจัดการงานการเข้าถึงฐานข้อมูล ใส่งานการเข้าถึงฐานข้อมูลลงในพูลเธรดเพื่อดำเนินการ * * * @author elon * @Version 1.0, 23 ตุลาคม 2015 */คลาสสาธารณะ DBTASKMGR {คลาสคงที่คลาสคงที่ DBTASKMGRINSTANCE {Public Static Final DBTASKMGR อินสแตนซ์ = ใหม่ DBTASKMGR (); } public Static DBTASKMGR อินสแตนซ์ () {return DBTASKMGRINSTANCE.INSTANCE; } Private Threadpoolexecutor พูล; สาธารณะ dbtaskmgr () {pool = new Threadpoolexecutor (10, 50, 60, TimeUnit.seconds, arrayblockingqueue ใหม่ <Runnable> (10,000), ThreadPoolexecutor.CALLERRUNSPOLICY ()); } โมฆะสาธารณะ excute (งาน runnable) {pool.execute (งาน); -10. สร้างไฟล์กำหนดค่า mybatis
10.1 mybatis.xml
<? xml version = "1.0" การเข้ารหัส = "utf-8"?> <! การกำหนดค่า doctype สาธารณะ "-// mybatis.org//dtd config 3.0 // en" "http://mybatis.org/dtd/mybatis-3-config.dtd Resource = "cfg/demomapper.xml"/> </mappers> </การกำหนดค่า>
10.2 demomapper.xml
<? xml version = "1.0" การเข้ารหัส = "utf-8"?> <! doctype mapper สาธารณะ "-// mybatis.org//dtd mapper 3.0 // en" "http://mybatis.org/dtd/mybatis-3-mapper.dtd id = "InsertDemo" พารามิเตอร์ = "com.elon.demodao"> แทรกลงใน tbl_demo (a, b, c) ค่า ( #{a}, #{b}, #{c}); </insert> <resultmap id = "demoresult" type = "com.elon.demoresult"> <id property = "sum" คอลัมน์ = "sumcolum"/> </resultmap> <select id = "selectgroup" resultmap = "demoresult"> เลือกผลรวม (a) </select> </ mapper>11. สร้างไฟล์การกำหนดค่าสปริง
11.1 Spring.xml
<? xml version = "1.0" การเข้ารหัส = "utf-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns: xsi = "http://ww.w3.org/2001/xml XSI: schemalocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" value = "com.mysql.jdbc.driver"> </คุณสมบัติ> <property name = "url" value = "jdbc: mysql: //10.70.69.69: 3306/test1"> </คุณสมบัติ> <property name = "username" value = "user123" value = "100"> </property> <property name = "MaxIdle" value = "30"> </คุณสมบัติ> <property name = "MaxWait" value = "500"> </property> <property name = "defaultAutoCommit" value = "true"> </property> </epean> value = "com.mysql.jdbc.driver"> </คุณสมบัติ> <property name = "url" value = "jdbc: mysql: //10.70.69.69: 3306/test2"> </property> <property name = "username" value = "user123" value = "100"> </คุณสมบัติ> <property name = "MaxIdle" value = "30"> </คุณสมบัติ> <property name = "MaxWait" value = "500"> </property> <property name = "defaultAutoCommit" value = "true"> </property> value = "com.mysql.jdbc.driver"> </คุณสมบัติ> <property name = "url" value = "jdbc: mysql: //10.70.69.69: 3306/test3"> </คุณสมบัติ> <property name = "username" value = "user123" value = "100"> </property> <property name = "MaxIdle" value = "30"> </คุณสมบัติ> <property name = "MaxWait" value = "500"> </property> <property name = "defaultAutocommit" value = "true"> </property> </epean> value = "com.mysql.jdbc.driver"> </คุณสมบัติ> <property name = "url" value = "jdbc: mysql: //10.70.69.69: 3306/test4"> </คุณสมบัติ> <property name = "username" value = "user123" value = "100"> </property> <property name = "MaxIdle" value = "30"> </คุณสมบัติ> <property name = "MaxWait" value = "500"> </property> <property name = "defaultAutoCommit" value = "true"> </property> </epean> value = "com.mysql.jdbc.driver"> </คุณสมบัติ> <property name = "url" value = "jdbc: mysql: //10.70.69.69: 3306/test5"> </คุณสมบัติ> <property name = "username" value = "user123" value = "100"> </property> <property name = "MaxIdle" value = "30"> </คุณสมบัติ> <property name = "MaxWait" value = "500"> </คุณสมบัติ> <property name = "defaultAutocommit" value = "true"> </property> </epean> value = "com.mysql.jdbc.driver"> </คุณสมบัติ> <property name = "url" value = "jdbc: mysql: //10.70.69.69: 3306/test6"> </คุณสมบัติ> <property name = "username" value = "user123" value = "100"> </property> <property name = "MaxIdle" value = "30"> </คุณสมบัติ> <property name = "MaxWait" value = "500"> </property> <property name = "defaultAutoCommit" value = "true"> </property> </epean> value = "com.mysql.jdbc.driver"> </คุณสมบัติ> <property name = "url" value = "jdbc: mysql: //10.61.67.246: 3306/test7"> </คุณสมบัติ> <property name = "username" value = "user123" name = "maxactive" value = "100"> </property> <property name = "MaxIdle" value = "30"> </property> <property name = "maxWait" value = "500"> </คุณสมบัติ> <property name = "defaultAutoCommit" value = "true" value = "com.mysql.jdbc.driver"> </คุณสมบัติ> <property name = "url" value = "jdbc: mysql: //10.61.67.246: 3306/test8"> </คุณสมบัติ> <property name = "username" value = "user123" name = "maxactive" value = "100"> </property> <property name = "maxidle" value = "30"> </property> <property name = "maxwait" value = "500"> </คุณสมบัติ> <property name = "defaultAutoCommit" value = "true" value = "com.mysql.jdbc.driver"> </คุณสมบัติ> <property name = "url" value = "jdbc: mysql: //10.61.67.246: 3306/test9"> </คุณสมบัติ> <property name = "username" value = "user123" name = "maxactive" value = "100"> </property> <property name = "maxidle" value = "30"> </property> <property name = "maxwait" value = "500"> </คุณสมบัติ> <property name = "defaultautocommit" value = "true"> </property> value = "com.mysql.jdbc.driver"> </คุณสมบัติ> <property name = "url" value = "jdbc: mysql: //10.61.67.246: 3306/test10"> </คุณสมบัติ> <property name = "username" value = "user123" name = "maxactive" value = "100"> </property> <property name = "maxidle" value = "30"> </property> <property name = "maxwait" value = "500"> </คุณสมบัติ> <property name = "defaultautocommit" value = "true"> </property> value = "com.mysql.jdbc.driver"> </คุณสมบัติ> <property name = "url" value = "jdbc: mysql: //10.61.67.246: 3306/test11"> </คุณสมบัติ> <property name = "username" value = "user123" name = "maxactive" value = "100"> </property> <property name = "maxidle" value = "30"> </property> <property name = "maxwait" value = "500"> </คุณสมบัติ> <property name = "defaultautocommit" value = "true" key = "test1" value-ref = "dataSource_1"/> <entry key = "test2" value-ref = "dataSource_2"/> <entry key = "test3" value-ref = "dataSource_3"/> <entry = "test4" value-ref = "DataSource_4"/> key = "test6" value-ref = "dataSource_6"/> <entry key = "test7" value-ref = "dataSource_7"/> <entry key = "test8" value-ref = "dataSource_8"/> <entry = "test9 key = "test11" value-ref = "dataSource_11"/> </map> </porement> </ebean> <bean id = "SQLSessionFactory"> <property name = "configlocation" value = "classpath: cfg/mybatis.xml"> <property name = "mapperinterface" value = "com.elon.idemo"> </คุณสมบัติ> <property name = "sqlsessionfactory" ref = "sqlsessionfactory"> </prevent> </epean> <bean id = "idemoservice"
12. รหัสทดสอบ
การทดสอบคลาสสาธารณะ {/** * รหัสทดสอบ * * * @param args */โมฆะคงที่สาธารณะหลัก (สตริง [] args) {@suppresswarnings ("ทรัพยากร") บริบท ApplicationContext = ใหม่ classpathxmlapplicationContext ("cfg/spring.xml"); IDEMOSERVICE SERVICE1 = (IDEMOSERVICE) Context.getBean ("Idemoservice"); // สร้างวัตถุงาน DBTASK TASK1 = ใหม่ DBTASK ("TEST1", Service1, "SelectGroup"); dbtask task2 = ใหม่ dbtask ("test2", service1, "selectgroup"); dbtask task3 = ใหม่ dbtask ("test3", service1, "selectgroup"); dbtask task4 = ใหม่ dbtask ("test4", service1, "selectgroup"); dbtask task5 = ใหม่ dbtask ("test5", service1, "selectgroup"); dbtask task6 = ใหม่ dbtask ("test6", service1, "selectgroup"); dbtask task7 = ใหม่ dbtask ("test7", service1, "selectgroup"); dbtask task8 = ใหม่ dbtask ("test8", service1, "selectgroup"); dbtask task9 = ใหม่ dbtask ("test9", service1, "selectgroup"); DBTASK TASK10 = ใหม่ DBTASK ("TEST10", Service1, "SelectGroup"); DBTASK TASK11 = ใหม่ DBTASK ("TEST11", Service1, "SelectGroup"); Demodao Demo = New Demodao (); demo.seta (10,000,000); demo.setb ("12121212"); demo.setc (100); DBTASK TASKINSERT = ใหม่ DBTASK ("TEST2", Service1, "InsertDemo", DEMO); SimpledateFormat format = new SimpledateFormat ("yyyy-mm-dd hh: mm: ss"); System.out.println ("เริ่มข้อมูลแทรก:" + format.format (วันที่ใหม่ ())); dbtaskmgr.instance (). excute (taskInsert); ในขณะที่ (จริง) {ถ้า (! taskInsert.isfinish ()) {ลอง {thread.sleep (1,000); } catch (interruptedException e) {e.printStackTrace (); }} else {break; }} system.out.println ("แทรกข้อมูลข้อมูล:" + format.format (วันที่ใหม่ ())); System.out.println ("เริ่มสอบถามตารางข้อมูล 50 ล้านตาราง:" + format.format (วันที่ใหม่ ())); dbtaskmgr.instance (). excute (task1); ในขณะที่ (จริง) {ถ้า (! task1.isfinish ()) {ลอง {thread.sleep (1,000); } catch (interruptedException e) {e.printStackTrace (); }} else {break; }} system.out.println (task1.getRetValue ()); System.out.println ("สอบถาม 50 ล้านตารางข้อมูลสิ้นสุด:" + format.format (วันที่ใหม่ ())); รายการ <Dbtask> taskList = arrayList ใหม่ <Dbtask> (); tasklist.add (task2); tasklist.add (task3); tasklist.add (task4); tasklist.add (task5); tasklist.add (task6); tasklist.add (task7); tasklist.add (task8); tasklist.add (task9); tasklist.add (task10); tasklist.add (task11); System.out.println ("เริ่มค้นหา 10 5 ล้านตารางข้อมูล:" + format.format (วันที่ใหม่ ())); สำหรับ (DBTASK Task: TASKLIST) {DBTASKMGR.INSTANCE (). ECCUTE (งาน); } ในขณะที่ (จริง) {int success = 0; สำหรับ (DBTASK Task: TaskList) {ถ้า (! task.isfinish ()) {ลอง {thread.sleep (1,000); } catch (interruptedException e) {e.printStackTrace (); }} else {++ ความสำเร็จ; }} if (success == 10) {break; }} สำหรับ (DBTASK Task: taskList) {system.out.println (task.getRetValue ()) ;; } system.out.println ("10 5 ล้านข้อมูลการสืบค้นตารางข้อมูลสิ้นสุดลง:" +format.format (วันที่ใหม่ ())); -13. ผลการทดสอบ
ใช้เวลา 45 วินาทีในการสืบค้นฐานข้อมูล 50 ล้านข้อมูล
ต้องใช้ฐานข้อมูล 22 วินาทีถึง 10 ฐานข้อมูลที่มีข้อมูล 5 ล้านข้อมูลในลักษณะแบบซิงโครนัส
เนื่องจากฐานข้อมูล 10 ฐานอยู่บนเซิร์ฟเวอร์สองตัวเซิร์ฟเวอร์หนึ่งแห่งมีฐานข้อมูล 5 ฐาน หากมีการปรับใช้ข้อมูล 10 ข้อมูลให้กับเซิร์ฟเวอร์ 10 เซิร์ฟเวอร์แยกประสิทธิภาพจะสูงขึ้น
สรุป
ด้านบนเป็นบทนำของบรรณาธิการใน Spring+MyBatis+MySQL เพื่อสร้างกรอบการเข้าถึงฐานข้อมูลแบบกระจาย ฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน หากคุณมีคำถามใด ๆ โปรดฝากข้อความถึงฉันและบรรณาธิการจะตอบกลับทุกคนในเวลา ขอบคุณมากสำหรับการสนับสนุนเว็บไซต์ Wulin.com!