คำนำ
บทความนี้ส่วนใหญ่บันทึกว่าฤดูใบไม้ผลิสนับสนุนสิ่งต่าง ๆ เป็นหลักและมันจะใช้ฟังก์ชั่นสิ่งต่าง ๆ ของฐานข้อมูลได้อย่างไรเมื่อฤดูใบไม้ผลิรวม mybatis ฉันจะไม่พูดมากเกี่ยวกับเรื่องนี้ด้านล่างเรามาดูการแนะนำรายละเอียดด้วยกัน
CASE1: สิ่งที่สนับสนุนสถานการณ์ในสองตาราง
ก่อนเตรียมสองตารางตารางผู้ใช้หนึ่งตารางและหนึ่งโต๊ะเรื่องราวโครงสร้างมีดังนี้
สร้างตาราง `user` (` id` int (11) ที่ไม่ได้ลงชื่อไม่ใช่ null auto_increment, `name` varchar (20) ไม่ใช่ค่าเริ่มต้น null '' ความคิดเห็น 'ชื่อผู้ใช้',` pwd` varchar (26) ไม่ใช่ค่าเริ่มต้น '' upted uptive ' varchar (13) ไม่ใช่ค่าเริ่มต้น null '0', คีย์หลัก (`id`), คีย์` name` (`name`))) engine = innoDB เริ่มต้น charset = utf8mb4; สร้างตาราง` Story` (`id` int (11) ไม่ได้ลงนาม null Auto_increment,` userid ' '' ความคิดเห็น 'ผู้แต่ง', `title` varchar (26) ไม่ใช่ค่าเริ่มต้น '' ความคิดเห็น 'รหัสผ่าน',` เรื่องราว 'ข้อความแสดงความคิดเห็น' เนื้อหาเรื่องราว ', `isdeleted` tinyint (1) ไม่ใช่ค่าเริ่มต้นที่เป็นโมฆะ' 0 ',` `` `` `` `` `` `` `` `` `` Engine = InnoDB เริ่มต้น charset = UTF8MB4;
สถานการณ์ของเราคือเมื่อผู้ใช้แก้ไขชื่อชื่อของทั้งสองตารางจะต้องได้รับการแก้ไขด้วยกันและไม่อนุญาตให้มีความไม่สอดคล้องกัน
CASE2: รองรับตารางเดี่ยว
โอนเงินผู้ใช้หนึ่งคนลดเงินผู้ใช้รายอื่นเพิ่มเงิน
สร้างตาราง `money` (` id` int (11) ที่ไม่ได้ลงชื่อไม่ใช่ null auto_increment, `name` varchar (20) ไม่ใช่ค่าเริ่มต้น null '' ความคิดเห็น 'ชื่อผู้ใช้',` money` int (26) ไม่เป็นค่าเริ่มต้น '0' ความคิดเห็น '13) ไม่ใช่ค่าเริ่มต้น null '0', คีย์หลัก (`id`), คีย์` name '(`name`)) engine = innoDB เริ่มต้น charset = utf8mb4;
เมื่อเทียบกับกรณีข้างต้นมันง่ายกว่า ตัวอย่างต่อไปนี้ส่วนใหญ่จะอธิบายตามสิ่งนี้ สำหรับกรณีที่ 1 มันจะถูกขยายออกไป
ขั้นแรกให้ใช้ DAO และเอนทิตีที่เกี่ยวข้อง
@Datapublic Class MoneyEntity ใช้ serializable {ส่วนตัวคงที่สุดท้าย Long SerialVersionUid = -7074788842783160025L; ID int ส่วนตัว; ชื่อสตริงส่วนตัว; เงิน int ส่วนตัว; INT INT ISDELETED ส่วนตัว; INT ส่วนตัวสร้างขึ้น; อัปเดต INT ส่วนตัว;} อินเตอร์เฟสสาธารณะ Moneydao {MoneyEntity QueryMoney (@Param ("id") int userId); // เพิ่มเงินเมื่อลบมันหมายถึงการลดเงิน int incrementMoney (@param ("id") int userId, @param ("addMoney") int addMoney);}ไฟล์ mapper ที่เกี่ยวข้องคือ
<? xml version = "1.0" การเข้ารหัส = "utf-8"?> <! doctype mapper สาธารณะ "-// mybatis.org//dtd mapper 3.0 // en" "http://mybatis.org/dtd/mybatis-3-mapper.dtd namespace = "com.git.hui.demo.mybatis.mapper.moneydao"> <sql id = "moneyentity"> id, `name`,` money`, `isdeleted`,` สร้าง ', `updated` </sql> resultType = "com.git.hui.demo.mybatis.entity.moneyentity"> เลือก <รวม refid = "moneyEntity"/> จากเงินที่ id =#{id} </select> <update id = "upderpermoney"> อัปเดตเงินการกำหนดค่าที่สอดคล้องกันของแหล่งข้อมูลการเชื่อมต่อ MyBatis
<ebean> <property name = "locations"> <value> classpath*: jdbc.properties </value> </property> </epean> <bean id = "dataSource" init-method = "init" destroy-method = "Close"> <property name = "value =" $} " name = "username" value = "$ {username}"/> <property name = "รหัสผ่าน" value = "$ {รหัสผ่าน}"/> <property name = "filters" value = "stat"/> <property name = "maxactive" value = "20"/> value = "1"/> <property name = "timebetweenevictionrunsmillis" value = "60000"/> <property name = "minevictableidletiTimeLis" value = "300000"/> <property name = "ValidationQuery" value = "select 'x'"/> name = "testOnBorrow" value = "false"/> <property name = "testOnReturn" value = "false"/> <property name = "PoolPreparedStatements" value = "true"/> <property name = "MaxPoolPreparedStatementerConnectiones ref = "dataSource"/> <!-ระบุไฟล์ Mapper-> <property name = "mapperlocations" value = "classpath*: mapper/*. xml"/> </ebean> <!ผ่านการสืบค้นออนไลน์มีสี่วิธีในการจัดการสิ่งฤดูใบไม้ผลิ นี่คือการสาธิตทีละวิธีการเล่นแต่ละวิธีจากนั้นดูวิธีการเลือกในโครงการจริง
การจัดการการเขียนโปรแกรมสิ่งที่ตระหนักถึงการจัดการสิ่งของของการดำเนินการ DB หลายรายการผ่าน TransactionTemplate
. การดำเนินการ
จากนั้นกรณีการถ่ายโอนของเราสามารถนำไปใช้ดังนี้
@RepositoryPublic คลาส codedemo1 {@autowired ส่วนตัว moneydao moneydao; @autowired TransactionTemplate TransactionTemplate; / ** * โอน * * @param inuserid * @param outuserid * @param paymoney * @param สถานะ 0 หมายถึงการถ่ายโอนปกติ 1 หมายถึงข้อยกเว้นถูกโยนลงภายใน 2 หมายถึงเธรดใหม่ปรับเปลี่ยนเงินของ inuserid + 200 สถานะ) {TransactionTemplate.execute (TransactionCallbackWithoutresult () {void doinTransactionWithoutresult (transactionstatus transactionStatus) {entity moneyentity = moneydao.querymoney moneydao.incrementmoney (outuserid, -paymoney); } // ต่อไปนี้เป็นกรณีทดสอบที่เกี่ยวข้องทั้งหมดเป็นโมฆะ testcase (สุดท้าย int inuserid, int outuserid สุดท้าย, สถานะ int สุดท้าย) {ถ้า (สถานะ == 1) {โยน unlegalargumentException ใหม่ ("การถ่ายโอนข้อยกเว้น !!!"); } อื่นถ้า (สถานะ == 2) {addMoney (inUserId); ลอง {thread.sleep (3000); } catch (interruptedException e) {e.printStackTrace (); }} อื่นถ้า (สถานะ == 3) {addMoney (outuserId); ลอง {thread.sleep (3000); } catch (interruptedException e) {e.printStackTrace (); }}} โมฆะสาธารณะ addMoney (ขั้นสุดท้าย int userId) {system.out.printf ("addMoney ภายใน:" + system.currentTimeLis ()); เธรดใหม่ (ใหม่ runnable () {public void run () {moneydao.incrementmoney (userid, 200); system.out.println ("ย่อยแก้ไขความสำเร็จ! -ส่วนใหญ่ดูที่วิธีการแปลงด้านบน การห่อหุ้มสิ่งต่าง ๆ ได้รับการรับรู้ผ่าน TransactionTemplate ภายใน มีการดำเนินการ DB สามครั้งภายในหนึ่งการสืบค้นและการอัปเดตสองครั้ง การวิเคราะห์เฉพาะจะได้รับการอธิบายในภายหลัง
รหัสข้างต้นค่อนข้างง่าย สิ่งเดียวที่คุณต้องให้ความสนใจคือการกำหนด transactionTemplate bean หากคุณไม่วางไฟล์ XML และไฟล์ก่อนหน้าเพียงแค่วางรหัสคีย์ หนึ่งคือ TransactionManager ที่สร้างขึ้นตามแหล่งข้อมูลและอื่น ๆ คือ TransactionTemplate ที่สร้างขึ้นตาม TransactionManager
<!-การเขียนโปรแกรมสิ่งต่าง ๆ-> <bean id = "transactionManager"> <property name = "DataSource" ref = "DataSource"/> </ebean> <bean id = "transactionTemplate"> <property name = "transactionManager" ref = "transactionManager"/>
ข. กรณีทดสอบ
สถานการณ์การสาธิตปกติการสาธิตไม่มีข้อยกเว้นและไม่ได้พิจารณาสถานการณ์พร้อมกัน
@runwith (springjunit4classrunner.class) @contextconfiguration ({"classpath*: spring/service.xml", "classpath*: test-datasource1.xml"}) คลาสสาธารณะ codedemo1test {@autowired codedemo1 codedemo1; @autowired Moneydao Moneydao; @Test Public Void TestTransfor () {System.out.println ("----------------------"); System.out.println ("id: 1 money =" + moneydao.querymoney (1) .getMoney ()); System.out.println ("id: 2 money =" + moneydao.querymoney (2) .getMoney ()); codedemo1.transfor (1, 2, 10, 0); System.out.println ("-----------------------"); System.out.println ("id: 1 money =" + moneydao.querymoney (1) .getMoney ()); System.out.println ("id: 2 money =" + moneydao.querymoney (2) .getMoney ()); -ผลลัพธ์มีดังนี้ไม่มีปัญหากับเงินของบัญชีทั้งสองบัญชี
-
ID: 1 เงิน = 10,000
ID: 2 เงิน = 50000
การโอนเสร็จสมบูรณ์! ตอนนี้: 1526130394266
-
ID: 1 เงิน = 10010
ID: 2 เงิน = 49990
ความผิดปกติเกิดขึ้นในระหว่างกระบวนการโอนโดยเฉพาะอย่างยิ่งเมื่อผู้โอนได้หักเงินและผู้รับไม่ได้รับเงินนั่นคือสถานการณ์ที่สถานะในกรณีคือ 1
// ข้อยกเว้นภายในการขว้าง @TestPublic เป็นโมฆะ testTransforexception () {system.out.println ("----------------------"); System.out.println ("id: 1 money =" + moneydao.querymoney (1) .getMoney ()); System.out.println ("id: 2 money =" + moneydao.querymoney (2) .getMoney ()); ลอง {codedemo1.transfor (1, 2, 10, 1); } catch (exception e) {e.printstacktrace (); } system.out.println ("---------------------------"); System.out.println ("id: 1 money =" + moneydao.querymoney (1) .getMoney ()); System.out.println ("id: 2 money =" + moneydao.querymoney (2) .getMoney ());}ในเรื่องนี้เราหวังว่าจะคืนเงินจากผู้โอนและส่งออกดังนี้ เราพบว่าไม่มีเงินใดเปลี่ยนแปลง
-
ID: 1 เงิน = 10010
ID: 2 เงิน = 49990
-
ID: 1 เงิน = 10010
java.lang.illegalargumentException: การถ่ายโอนข้อยกเว้น !!!
... // ละเว้นข้อมูลข้อยกเว้น
ID: 2 เงิน = 49990
เมื่อสถานะคือ 2 หมายความว่าระหว่างเงินของผู้โอนถูกหักออกและเงินของผู้รับเงินยังไม่ได้รับใครบางคนโอนไปยังผู้รับเงิน 200 คน ในเวลานี้ตามกลไกการล็อคของ MySQL การถ่ายโอนของบุคคลอื่นควรได้รับทันที (เนื่องจากบัญชีของผู้รับเงินไม่ได้ล็อค) และไม่ควรมีปัญหากับจำนวนเงิน
ผลลัพธ์ผลลัพธ์มีดังนี้:
-
ID: 1 เงิน = 10010
ID: 2 เงิน = 49990
## ทางด้านขวาคือหมายเหตุ: ในระหว่างกระบวนการโอนเงินถูกฝากเงินทันทีและเงินถูกเพิ่มเข้าไปข้างในไม่ได้ถูกล็อค: 1526130827480
ย่อยปรับเปลี่ยนความสำเร็จ! ตอนนี้: 1526130827500
## การโอนเสร็จสมบูรณ์หลังจากประหยัดเงิน! ตอนนี้: 1526130830488
-
ID: 1 เงิน = 10220
ID: 2 เงิน = 49980
เมื่อสถานะคือ 3 หมายความว่าเงินของผู้โอนถูกหักออกและเงินของผู้รับเงินยังไม่ได้รับและมีคนโอนไป 200 คนไปยังผู้โอน ในเวลานี้เนื่องจากมีการเพิ่มบันทึกของผู้โอนและการเขียนล็อคเขาสามารถรอการโอนเพื่อส่งการโอนเพื่อประสบความสำเร็จก่อนที่จะประสบความสำเร็จ +200 แน่นอนว่าจำนวนสุดท้ายจะต้องเหมือนกัน
ผลลัพธ์ผลลัพธ์มีดังนี้
-
ID: 1 เงิน = 10220
ID: 2 เงิน = 49980
## ทางด้านขวาคือหมายเหตุ: ฉันประหยัดเงินภายใน แต่ก็ไม่ประสบความสำเร็จทันที
## มันไม่ได้จนกว่าการถ่ายโอนจะเสร็จสมบูรณ์ว่าจะสำเร็จได้ทันที ให้ความสนใจกับการเพิ่มเงินให้กับการประทับเวลาสองครั้ง: 1526131101046
การโอนเสร็จสมบูรณ์! ตอนนี้: 1526131104051
ย่อยปรับเปลี่ยนความสำเร็จ! ตอนนี้: 1526131104053
-
ID: 1 เงิน = 10230
ID: 2 เงิน = 50170
ค. สรุป
จนถึงตอนนี้การเขียนโปรแกรมได้แสดงให้เห็นในตัวอย่าง จากกระบวนการข้างต้นมันให้ความรู้สึกเช่นเดียวกับการเขียนสิ่งที่เกี่ยวข้องกับ SQL
เริ่มทำธุรกรรม
- นี่คือตรรกะภายใน TransactionTemplate#วิธีการดำเนินการ
- นั่นคือชุดของ SQL ที่ต้องมีการจัดการสิ่งต่างๆให้สัญญา;
สามถัดไปคือการจัดการสิ่งที่ประกาศซึ่งใช้น้อยกว่าเพราะแต่ละชั้นเรียนการจัดการจะต้องเพิ่มลงในธุรกรรม ProxyFactoryBean
. การดำเนินการ
นอกเหนือจากการฆ่า TransactionTemplate และลบตรรกะ SQL ภายในเมื่อเปรียบเทียบกับอันก่อนหน้านี้ฉันพบว่าโดยทั่วไปไม่มีความแตกต่าง
ชั้นเรียนสาธารณะ FactoryBeandemo2 {@autowired ส่วนตัว Moneydao Moneydao; / ** * โอน * * @param inuserid * @param outuserid * @param paymoney * @param สถานะ 0 หมายถึงการถ่ายโอนปกติ 1 หมายถึงข้อยกเว้นถูกโยนลงไปภายใน 2 หมายถึงเธรดใหม่ปรับเปลี่ยนเงินของ inuserid + 200, 3 หมายถึงการจ่ายค่าสุดท้าย สถานะ) {MoneyEntity Entity = Moneydao.QueryMoney (outuserid); if (entity.getMoney ()> payMoney) {// คุณสามารถโอนเงิน // ลดเงิน moneydao.incrementmoney (outuserid, -paymoney); testcase (inuserid, outuserid, สถานะ); // เพิ่มเงินให้กับ moneydao.incrementmoney (inuserid, paymoney); System.out.println ("การถ่ายโอนเสร็จสมบูรณ์แล้วตอนนี้:" + System.currentTimeMillis ()); }} private void testcase (int intinuserid สุดท้าย, int outuserid สุดท้าย, สถานะ int สุดท้าย) {ถ้า (สถานะ == 1) {โยน unlegalargumentException ใหม่ ("การถ่ายโอนข้อยกเว้น !!!"); } อื่นถ้า (สถานะ == 2) {addMoney (inUserId); ลอง {thread.sleep (3000); } catch (interruptedException e) {e.printStackTrace (); }} อื่นถ้า (สถานะ == 3) {addMoney (outuserId); ลอง {thread.sleep (3000); } catch (interruptedException e) {e.printStackTrace (); }}} โมฆะสาธารณะ addMoney (ขั้นสุดท้าย int userId) {system.out.println ("ภายในเพิ่มเงิน:" + system.currentTimeLis ()); เธรดใหม่ (ใหม่ runnable () {public void run () {moneydao.incrementmoney (userid, 200); system.out.println ("ย่อยแก้ไขความสำเร็จ! -ประเด็นสำคัญคือเราต้องกำหนดค่า TransactionProxyBeanFactory เรารู้ว่า beanfactory เป็นวิธีการสำหรับเราในการสร้างถั่วด้วยตัวเอง การกำหนดค่า XML ที่เกี่ยวข้องมีดังนี้
<!-การเขียนโปรแกรมสิ่งต่าง ๆ-> <bean id = "transactionManager"> <property name = "dataSource" ref = "DataSource"/> </ebean> <bean id = "FactoryBeanDemo2"/> <!-กำหนดค่าพร็อกซีสำหรับเลเยอร์ธุรกิจ-> ref = "FactoryBeandEmo2" /> <!-ฉีดผู้จัดการธุรกรรม-> <ชื่อคุณสมบัติ = "transactionManager" ref = "transactionManager" /> <!-ฉีดคุณสมบัติของธุรกรรม-> <property name = "TransactionAttributes"> <props> <! ข้อยกเว้นใด ๆ ที่ย้อนกลับธุรกรรม* +ข้อยกเว้น: ข้อยกเว้นใดที่ไม่ย้อนกลับธุรกรรม-> <!-คีย์นี้สอดคล้องกับวิธีการในคลาสเป้าหมาย-> <prop key = "transfor"> propagation_required </prop> <!-<prop key = "transfer"> propagation_required <!-<prop key = "transfer"> propagation_required,+java.lang.arithmeticexception </prop>-> </props> </porement> </ebean>
ผ่านการกำหนดค่าข้างต้นเราสามารถเข้าใจได้อย่างคร่าวๆว่า TransactionProxyFactoryBean สร้างระดับพร็อกซีของ FactoryBeandemo2 คลาสพร็อกซีนี้ห่อหุ้มตรรกะที่เกี่ยวข้องกับสิ่งที่ดีภายในซึ่งถือได้ว่าเป็นนามธรรมทั่วไปของการเขียนโปรแกรมก่อนหน้านี้
ข. ทดสอบ
รหัสทดสอบนั้นเหมือนเดิมก่อน ความแตกต่างเพียงอย่างเดียวคือเราควรใช้ถั่วที่สร้างขึ้นโดย beanfactory ด้านบนแทนที่จะใช้โดยตรงจาก FactoryBeandemo2
กรณีการสาธิตปกติ:
@runwith (springjunit4classrunner.class) @contextconfiguration ({"classpath*: spring/service.xml", "classpath*: test-datasource2.xml"}) ชั้นเรียนสาธารณะ @autowired Moneydao Moneydao; @Test โมฆะสาธารณะ testTransfor () {system.out.println ("----------------------"); System.out.println ("id: 1 money =" + moneydao.querymoney (1) .getMoney ()); System.out.println ("id: 2 money =" + moneydao.querymoney (2) .getMoney ()); FactoryBeandemo2.transfor (1, 2, 10, 0); System.out.println ("------------------------------"); System.out.println ("id: 1 money =" + moneydao.querymoney (1) .getMoney ()); System.out.println ("id: 2 money =" + moneydao.querymoney (2) .getMoney ()); -เอาท์พุท
-
ID: 1 เงิน = 10,000
ID: 2 เงิน = 50000
การโอนเสร็จสมบูรณ์! ตอนนี้: 1526132058886
-
ID: 1 เงิน = 10010
ID: 2 เงิน = 49990
หากสถานะคือ 1 และข้อยกเว้นภายในไม่ใช่กรณีเราหวังว่าจะไม่มีปัญหากับเงิน
@TestPublic เป็นโมฆะ testTransforexception () {system.out.println ("-----------------------"); System.out.println ("id: 1 money =" + moneydao.querymoney (1) .getMoney ()); System.out.println ("id: 2 money =" + moneydao.querymoney (2) .getMoney ()); ลอง {FactoryBeandEmo2.transfor (1, 2, 10, 1); } catch (exception e) {system.out.println (e.getMessage ()) ;; } system.out.println ("--------------------------"); System.out.println ("id: 1 money =" + moneydao.querymoney (1) .getMoney ()); System.out.println ("id: 2 money =" + moneydao.querymoney (2) .getMoney ());}ผลลัพธ์คือ
-
ID: 1 เงิน = 10010
ID: 2 เงิน = 49990
ถ่ายโอนความผิดปกติ !!!
-
ID: 1 เงิน = 10010
ID: 2 เงิน = 49990
เมื่อสถานะคือ 2 ผลการวิเคราะห์ควรจะเหมือนกับข้างต้นและเอาต์พุตมีดังนี้
-
ID: 1 เงิน = 10010
ID: 2 เงิน = 49950
เงินภายใน: 1526133325376
ย่อยปรับเปลี่ยนความสำเร็จ! ตอนนี้: 1526133325387
การโอนเสร็จสมบูรณ์! ตอนนี้: 1526133328381
-
ID: 1 เงิน = 10220
ID: 2 เงิน = 49940
เมื่อสถานะคือ 3 เอาต์พุต
-
ID: 1 เงิน = 10220
ID: 2 เงิน = 49940
เงินภายใน: 1526133373466
การโอนเสร็จสมบูรณ์! ตอนนี้: 1526133376476
ย่อยปรับเปลี่ยนความสำเร็จ! ตอนนี้: 1526133376480
-
ID: 1 เงิน = 10230
ID: 2 เงิน = 50130
ค. สรุป
แนวคิดของ TransactionProxyFactoryBean คือการใช้โหมดพร็อกซีเพื่อใช้งานการจัดการสิ่งต่าง ๆ สร้างคลาสพร็อกซีวิธีการสกัดกั้นเป้าหมายและห่อหุ้มชุดการดำเนินการ SQL ลงในสิ่งต่าง ๆ เมื่อเปรียบเทียบกับรหัสยากมันไม่ได้เป็นการรุกรานและรองรับวิธีการกำหนดค่าที่ยืดหยุ่น
ข้อเสียก็ชัดเจนเช่นกันแต่ละต้องกำหนดค่าซึ่งค่อนข้างซับซ้อน
ฤดูใบไม้ผลิมีสองลักษณะสำคัญคือ IOC และ AOP สำหรับสิ่งนี้เราสามารถใช้ AOP เพื่อทำมันได้หรือไม่?
สำหรับวิธีการที่จำเป็นต้องเปิดใช้งานสกัดกั้นสิ่งต่าง ๆ ก่อนที่จะดำเนินการส่งสิ่งต่าง ๆ หลังจากดำเนินการและย้อนกลับเมื่อมีข้อยกเว้นเกิดขึ้น
จากมุมมองนี้มันให้ความรู้สึกที่ค่อนข้างมีแนวโน้มและมีการเล่นสองท่าต่อไปนี้ด้วยวิธีนี้ดังนั้นจึงจำเป็นต้องมีการพึ่งพาแง่มุม
<การพึ่งพา> <roupId> org.aspectj </groupId> <ratifactid> AppistjWeaver </artifactId> <version> 1.8.7 </SerfiS
. การดำเนินการ
คลาส Java นั้นเหมือนกับประเภทที่สองและมีการเปลี่ยนแปลง XML เท่านั้น
<!-ก่อนอื่นเพิ่ม namespace-> xmlns: tx = "http://www.springframework.org/schema/tx" xmlns: aop = "http://www.springframework.org/schema http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd-tx. id = "txAdvice" ธุรกรรม-manager = "transactionManager"> <tx: คุณลักษณะ> <!-การแพร่กระจาย: การแยกการทำธุรกรรมการแยกพฤติกรรม: การแยกการทำธุรกรรมระดับการอ่านอย่างเดียว: การอ่านอย่างเดียว-การย้อนกลับ:> <tx- </tx: แอตทริบิวต์> </tx: คำแนะนำ> <!-ส่วนการกำหนดค่า-> <aop: config> <!-จุดกำหนดจุดตัด-> <aop: pointcut expression = "การดำเนินการ (* com.git.hui.demo.mybatis.Repository.Transaction.xmldemo3 <AOP: Advisor Advice-ref = "TxAdvice" PointCut-ref = "PointCut1"/> </aop: config>
สังเกตการกำหนดค่าข้างต้นและคิดเกี่ยวกับวิธีที่สอง ความคิดเกือบจะเหมือนกัน แต่วิธีนี้เห็นได้ชัดว่าทั่วไปมากขึ้น ผ่านส่วนและจุดตัดจำนวนการกำหนดค่าจำนวนมากสามารถลดลงได้
ข. ทดสอบ
@runwith (springjunit4classrunner.class) @contextconfiguration ({"classpath*: spring/service.xml", "classpath*: test-datasource3.xml"}) คลาสสาธารณะ xmlbeantest {@autowired ส่วนตัว xmldemo3 xmldemo; @autowired Moneydao Moneydao; @Test โมฆะสาธารณะ testTransfor () {system.out.println ("---------------------"); System.out.println ("id: 1 money =" + moneydao.querymoney (1) .getMoney ()); System.out.println ("id: 2 money =" + moneydao.querymoney (2) .getMoney ()); xmldemo.transfor (1, 2, 10, 0); System.out.println ("------------------------"); System.out.println ("id: 1 money =" + moneydao.querymoney (1) .getMoney ()); System.out.println ("id: 2 money =" + moneydao.querymoney (2) .getMoney ()); -การทดสอบนี้ไม่แตกต่างจากวิธีการเขียนทั่วไปและง่ายกว่าวิธีการฉีดของโรงงานที่สอง
เอาต์พุตปกติ
-
ID: 1 เงิน = 10,000
ID: 2 เงิน = 50000
การโอนเสร็จสมบูรณ์! ตอนนี้: 1526135301273
-
ID: 1 เงิน = 10010
ID: 2 เงิน = 49990
สถานะ = 1 เมื่อมีข้อยกเว้นเกิดขึ้นผลลัพธ์คือ
-
ID: 1 เงิน = 10010
ID: 2 เงิน = 49990
ถ่ายโอนความผิดปกติ !!!
-
ID: 1 เงิน = 10010
ID: 2 เงิน = 49990
สถานะ = 2 สถานการณ์ของการออมเงินในระหว่างกระบวนการโอนผลผลิตสอดคล้องกับความคาดหวังก่อนหน้านี้
-
ID: 1 เงิน = 10010
ID: 2 เงิน = 49990
เงินภายใน: 1526135438403
ย่อยปรับเปลี่ยนความสำเร็จ! ตอนนี้: 1526135438421
การโอนเสร็จสมบูรณ์! ตอนนี้: 1526135441410
-
ID: 1 เงิน = 10220
ID: 2 เงิน = 49980
ผลลัพธ์ของสถานะ = 3 สอดคล้องกับความคาดหวังก่อนหน้านี้
-
ID: 1 เงิน = 10220
ID: 2 เงิน = 49980
เงินภายใน: 1526135464341
การโอนเสร็จสมบูรณ์! ตอนนี้: 1526135467349
ย่อยปรับเปลี่ยนความสำเร็จ! ตอนนี้: 1526135467352
-
ID: 1 เงิน = 10230
ID: 2 เงิน = 50170
นี่คือการกำจัด XML และใช้คำอธิบายประกอบเพื่อทำซึ่งคือการแทนที่การกำหนดค่าใน XML ก่อนหน้าด้วย @Transactional Annotation
. การดำเนินการ
@RepositoryPublic Class Annodemo4 {@autowired Moneydao Moneydao; /** * โอน * * @param inuserid * @param outuserid * @param paymoney * @param สถานะ 0 หมายถึงการถ่ายโอนปกติ 1 หมายถึงข้อยกเว้นถูกโยนลงไปภายใน 2 หมายถึงเธรดใหม่ปรับเปลี่ยนเงินของ inuserid + 200 อ่านอย่างเดียว: อ่านอย่างเดียว* Rollbackfor: มีข้อยกเว้นใดที่เกิดขึ้น Norollbackfor: ข้อยกเว้นเกิดขึ้นที่จะไม่ย้อนกลับ* RollbackForClassName ย้อนกลับตามชื่อคลาสข้อยกเว้น*/ @transactional (การแพร่กระจาย = การแพร่กระจาย entity entity = moneydao.QueryMoney (outuserid); if (entity.getMoney ()> payMoney) {// คุณสามารถโอนเงิน // ลดเงิน moneydao.incrementmoney (outuserid, -paymoney); testcase (inuserid, outuserid, สถานะ); // เพิ่มเงินให้กับ moneydao.incrementmoney (inuserid, paymoney); System.out.println ("การถ่ายโอนเสร็จสมบูรณ์แล้วตอนนี้:" + System.currentTimeMillis ()); }} private void testcase (int intinuserid สุดท้าย, int outuserid สุดท้าย, สถานะ int สุดท้าย) {ถ้า (สถานะ == 1) {โยน unlegalargumentException ใหม่ ("การถ่ายโอนข้อยกเว้น !!!"); } อื่นถ้า (สถานะ == 2) {addMoney (inUserId); ลอง {thread.sleep (3000); } catch (interruptedException e) {e.printStackTrace (); }} อื่นถ้า (สถานะ == 3) {addMoney (outuserId); ลอง {thread.sleep (3000); } catch (interruptedException e) {e.printStackTrace (); }}} โมฆะส่วนตัว addMoney (ขั้นสุดท้าย int userId) {system.out.println ("ภายในเพิ่มเงิน:" + system.currentTimeLis ()); เธรดใหม่ (ใหม่ runnable () {public void run () {moneydao.incrementmoney (userid, 200); system.out.println ("ย่อยแก้ไขความสำเร็จ! -ดังนั้นจึงจำเป็นต้องกำหนดค่าใน XML เพื่อเปิดใช้งานคำอธิบายประกอบของสิ่งต่าง ๆ
<!-การเขียนโปรแกรมสิ่งต่าง ๆ-> <bean id = "transactionManager"> <property name = "DataSource" ref = "DataSource"/> </ebean> <tx: Transaction-Driven Transaction-Manager = "TransactionManager"/>>
สิ่งนี้ทำให้ชัดเจนขึ้น ในโครงการจริงวิธี XML และคำอธิบายประกอบเป็นสถานการณ์ที่ใช้กันมากที่สุด
ข. กรณีทดสอบ
มันเหมือนกับกรณีทดสอบที่สามและผลลัพธ์ผลลัพธ์จะเหมือนกันและถูกละเว้นโดยตรง
ข้างต้นพูดถึงสี่วิธีในการใช้สิ่งต่าง ๆ ในฤดูใบไม้ผลิ ในหมู่พวกเขาวิธีการที่ใช้รหัสยากอาจเป็นความเข้าใจที่ดีที่สุดซึ่งเทียบเท่ากับการแปลวิธีการใช้สิ่งต่าง ๆ ใน SQL ลงในรหัส Java ที่เกี่ยวข้องโดยตรง และวิธีการจากโรงงานนั้นเทียบเท่ากับการรักษาสถานการณ์พิเศษและรักษาแต่ละสิ่งด้วยพร็อกซีคลาสเพื่อเพิ่มฟังก์ชั่นของสิ่งต่าง ๆ หลักการสองหลังเกือบจะถูกนำไปใช้โดยใช้การแจ้งเตือน (AOP) เพื่อกำหนดจุดสัมผัสและข้อมูลที่เกี่ยวข้อง
การเขียนโปรแกรม:
transactionTemplate#execute Methodพร็อกซี Beanfactory:
การกำหนดค่า XML:
วิธีการอธิบายประกอบ:
tx:annotation-driven transaction-manager="transactionManager"/>เอกสาร
สี่วิธีในการจัดการธุรกรรมฤดูใบไม้ผลิ
รหัสต้นฉบับ
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com