การวิจัยหลักในบทความนี้คือระดับเซสชันของ Hibernate และระดับความโดดเดี่ยว การแนะนำและตัวอย่างเฉพาะมีดังนี้
มาดูแนวคิดบางอย่างก่อน:
1. การอ่านสกปรก: การอ่านสกปรกเรียกอีกอย่างว่าการอ่านข้อมูลที่ไม่ถูกต้อง หมายความว่าในระหว่างการเข้าถึงฐานข้อมูลสิ่งที่ T1 ปรับเปลี่ยนค่าที่แน่นอนจากนั้นสิ่งที่ T2 จะอ่านค่า หลังจากนั้น T1 ยกเลิกการปรับเปลี่ยนค่าด้วยเหตุผลบางอย่างซึ่งทำให้ข้อมูลที่อ่านโดย T2 ไม่ถูกต้อง Dirty Reading หมายความว่าเมื่อมีการเข้าถึงข้อมูลและแก้ไขข้อมูลและการปรับเปลี่ยนนี้ไม่ได้ถูกส่งไปยังฐานข้อมูลสิ่งอื่นยังเข้าถึงข้อมูลนี้แล้วใช้ข้อมูลนี้ เนื่องจากข้อมูลนี้ยังไม่ได้ส่งข้อมูลที่อ่านโดยสิ่งอื่นคือข้อมูลที่สกปรกและการดำเนินการที่ดำเนินการตามข้อมูลสกปรกไม่ถูกต้อง
2. ไม่ได้อ่านซ้ำ: ตัวอย่างเช่นเมื่อฉันอ่านโพสต์ข้อมูลที่ฉันพบคือจางซานและหลี่ศี้ จากนั้นหลังจากที่ฉันรีเฟรชฉันพบว่าจางซานแรกกลายเป็นจาง BA นี่คือการอ่านที่ไม่สามารถทำซ้ำได้เนื่องจากข้อมูลที่ฉันอ่านไม่ได้ทำซ้ำ
3. การอ่านแฟนตาซี: เมื่อฉันค้นหาข้อมูลฉันเริ่มค้นหา 3 ระเบียน เมื่อฉันรีเฟรชมันฉันพบว่าบันทึกกลายเป็น 8 นี่คือการอ่านแฟนตาซี
4. ส่งการอ่าน: คุณสามารถอ่านได้หลังจากส่งเท่านั้น Oracle เริ่มต้นนี้ ไม่มีการอ่านสกปรกในลักษณะนี้
5. การทำซ้ำ: เห็นได้ชัดว่าตรงกันข้ามกับการอ่านที่ไม่สามารถทำซ้ำได้ มันสามารถหลีกเลี่ยงการอ่านที่ไม่สามารถทำซ้ำได้ แต่สิ่งนี้ไม่สามารถหลีกเลี่ยงการอ่าน Phantom
6. การทำให้เป็นอนุกรม: วิธีนี้เข้มงวดมาก ในแง่ของคนธรรมดาเมื่อฉันทำอะไรบางอย่างไม่มีใครสามารถทำได้ ปลอดภัยมาก แต่ก็ไม่มีประสิทธิภาพมาก
ด้านล่างเราใช้ตัวอย่างที่เป็นประโยชน์เพื่อทำความเข้าใจการประยุกต์ใช้การกวาดล้างแคชไฮเบอร์เนต
ฐานข้อมูลการแมปไฮเบอร์เนตเกี่ยวข้องกับกลยุทธ์การสร้างคีย์หลัก
ตัวอย่างของการสร้างคีย์หลักใน UUID:
ผู้ใช้ระดับสาธารณะ {สตริงส่วนตัว uid; สตริงส่วนตัว uname; วันเกิดส่วนตัว; สตริงสาธารณะ getuid () {return uid;} โมฆะสาธารณะ setuid (สตริง uid) {this.uid = uid;} สตริงสาธารณะ getUname () {return uname; setBirthday (วันเกิดวันที่) {this.birthday = วันเกิด;}}user.hbm.xml:
<? xml เวอร์ชัน = "1.0"?> <! Doctype hibernate-mapping สาธารณะ "-// hibernate/hibernate mapping dtd 3.0 // en" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" package = "com.lixue.bean"> <!-ชื่อของโหนดคลาสแสดงชื่อคลาสของเอนทิตีและตารางแสดงชื่อของเอนทิตีที่แมปไปยังตารางในฐานข้อมูล-> <class name = "user" table = "t_user"> <id name = "uid"> <! name = "วันเกิด"/> </class> </hibernate-mapping>
วิธีทดสอบ:
/ ***ทดสอบกลยุทธ์การสร้างคีย์หลัก UUID*/ โมฆะสาธารณะ TestSave1 () {/*เซสชันที่กำหนดและสิ่งต่าง ๆ*/ เซสชันเซสชัน = null; ธุรกรรมการทำธุรกรรม = null; ลอง { /*รับเซสชันและสิ่งต่าง ๆ* / เซสชัน = hibernateutils.getSession (); ธุรกรรม = session.beginTransaction (); /*สร้างผู้ใช้*/ ผู้ใช้ผู้ใช้ = ผู้ใช้ใหม่ (); user.setuname ("xi jinping"); user.setBirthday (วันที่ใหม่ ()); / *** เนื่องจากกลยุทธ์การสร้างคีย์หลักของผู้ใช้คือ UUID หลังจากการโทรบันทึกแล้วจะรวมถึงผู้ใช้ในการจัดการเซสชัน* คำสั่งแทรกจะไม่ได้รับการออก แต่ ID ได้ถูกสร้างขึ้นและสถานะการดำรงอยู่ INTENTENTEBASE ใน PersistNENCECONTEXT เป็นเท็จ*/ เซสชัน /** * การโทรผ่านฟลัชไฮเบอร์เนตจะทำความสะอาดแคช (แทรกวัตถุในคอลเลกชันชั่วคราวในเซสชัน-> การแทรกลงในฐานข้อมูลการล้างคอลเลกชันชั่วคราว) * ในเวลานี้ข้อมูลไม่สามารถมองเห็นได้ในฐานข้อมูล session.flush (); /** * ส่งสิ่งต่าง ๆ * โดยค่าเริ่มต้นการดำเนินการ commit จะทำการทำความสะอาดฟลัชฟลัช * ดังนั้นข้อมูลไม่สามารถย้อนกลับได้หลังจากโทร Flush โดยไม่ต้องแสดง * comment * transaction.Commit (); } catch (exception e) {e.printstacktrace (); ธุรกรรม Rollback (); } ในที่สุด {hibernateutils.closesession (เซสชัน); - เราสามารถดีบักโปรแกรมผ่านจุดพัก:
1. เนื่องจากอัตราด้านข้างของการสร้างคีย์หลักของผู้ใช้คือ UUID หลังจากเรียกใช้วิธีการบันทึก () วัตถุผู้ใช้สามารถรวมอยู่ในการจัดการเซสชันเท่านั้นและคำสั่งแทรกจะไม่ถูกออก แต่ ID ได้ถูกสร้างขึ้น (หมายเหตุ: สองสถานที่มีความสำคัญมาก StensheNceContext-> EntityEntries-> MAP-> Table-> องค์ประกอบอาร์เรย์บางอย่าง-> ค่าจัดเก็บวัตถุ ดังที่แสดงในภาพ:
2. หลังจากเรียกใช้วิธีการล้าง () ค่าชั่วคราวที่เก็บไว้ของ actionqueue ในเซสชันจะถูกล้างและจากนั้นค่าของ ExistIstIndatabase ใน PersistenceContext ถูกตั้งค่าเป็นจริงแสดงว่ามีข้อมูลที่สอดคล้องกันในฐานข้อมูลในเวลานี้ หลังจากเรียกเมธอด commit () มีข้อมูลในฐานข้อมูล
ตัวอย่างของการสร้างคีย์หลักในรูปแบบดั้งเดิม:
ผู้ใช้ระดับสาธารณะ 1 {ส่วนตัวจำนวนเต็ม uid; สตริงส่วนตัว uname; วันเกิดส่วนตัว; จำนวนเต็มสาธารณะ getuid () {return uid;} โมฆะสาธารณะ setuid (จำนวนเต็ม uid) {this.uid = uid;} public String getUname () {return uname; วันเกิด;} โมฆะสาธารณะ setBirthday (วันเกิดวันที่) {this.birthday = วันเกิด;}}user1.hbm.xml:
<? xml เวอร์ชัน = "1.0"?> <! Doctype hibernate-mapping สาธารณะ "-// hibernate/hibernate mapping dtd 3.0 // en" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" package = "com.lixue.bean"> <!-ชื่อโหนดคลาสแสดงชื่อคลาสของเอนทิตี (จำไว้ว่าให้แก้ไขชื่อคลาสเมื่อกำหนดไฟล์การแมปมิฉะนั้นจะเกิดข้อบกพร่อง) ตารางแสดงชื่อของเอนทิตีที่แมปเข้ากับตารางในฐานข้อมูล-> </id> <property name = "Uname"/> <property name = "วันเกิด"/> </class> </hibernate-mapping>
วิธีทดสอบ:
/ ***ทดสอบกลยุทธ์การสร้างคีย์หลักดั้งเดิม*/ โมฆะสาธารณะ TestSave2 () {/*เซสชันที่กำหนดและสิ่งต่าง ๆ*/ เซสชันเซสชัน = null; ธุรกรรมการทำธุรกรรม = null; ลอง { /*รับเซสชันและสิ่งต่าง ๆ* / เซสชัน = hibernateutils.getSession (); ธุรกรรม = session.beginTransaction (); /*สร้างผู้ใช้*/ user1 user = ผู้ใช้ใหม่ 1 (); user.setuname ("Li Keqiang"); user.setBirthday (วันที่ใหม่ ()); / *** เนื่องจากกลยุทธ์การสร้างคีย์หลักของ User1 นั้นเป็นแบบดั้งเดิมหลังจากการโทร Session.save () คำสั่งแทรกจะถูกดำเนินการและวัตถุคอลเลกชันชั่วคราวจะถูกล้าง* ส่งคืน ID ที่สร้างขึ้นโดยฐานข้อมูลรวมอยู่ในการจัดการเซสชันและปรับเปลี่ยนสถานะการอ่าน Transaction.Commit (); } catch (exception e) {e.printstacktrace (); ธุรกรรม Rollback (); } ในที่สุด {hibernateutils.closesession (เซสชัน); - ดีบักโปรแกรมผ่านจุดพัก:
1. เนื่องจากกลยุทธ์การสร้างคีย์หลักเป็นแบบดั้งเดิมหลังจากเรียกใช้วิธีการบันทึก () คำสั่งแทรกจะถูกดำเนินการและข้อมูลในวัตถุการรวบรวมชั่วคราวจะถูกล้างและ ID ที่สร้างโดยฐานข้อมูลจะถูกส่งคืน
2. รวมวัตถุเข้าสู่การจัดการเซสชันแก้ไขคุณสมบัติ ExistIsSindatabase ใน StensentNceContext เป็น TRUE (ระบุว่ามีข้อมูลที่สอดคล้องกันในฐานข้อมูล แต่ไม่สามารถมองเห็นได้เนื่องจากพื้นที่แยก)
ลองทดสอบวิธีการจำศีลอื่นซึ่งเป็น Evict () ซึ่งหมายถึงการขับไล่วัตถุออกจากเซสชัน
สำหรับโปรแกรมที่สร้างกลยุทธ์คีย์หลัก UUID นี่คือวิธีการทดสอบ:
/ ***ทดสอบกลยุทธ์การสร้างคีย์หลัก UUID*/ โมฆะสาธารณะ TestSave3 () {/*เซสชันที่กำหนดและสิ่งต่าง ๆ*/ เซสชันเซสชัน = null; ธุรกรรมการทำธุรกรรม = null; ลอง { /*รับเซสชันและสิ่งต่าง ๆ* / เซสชัน = hibernateutils.getSession (); ธุรกรรม = session.beginTransaction (); /*สร้างผู้ใช้*/ ผู้ใช้ผู้ใช้ = ผู้ใช้ใหม่ (); user.setuname ("Hu Jintao"); user.setBirthday (วันที่ใหม่ ()); /*** เนื่องจากกลยุทธ์การสร้างคีย์หลักของผู้ใช้คือ UUID หลังจากโทรบันทึกเพียงแค่รวมผู้ใช้เข้ากับการจัดการเซสชัน* จะไม่ออกคำสั่งแทรก แต่ ID ได้ถูกสร้างขึ้น สถานะ ExistIstIdateBase ในเซสชันเป็นเท็จ */ session.save (ผู้ใช้); /*Eviction วัตถุผู้ใช้จากเซสชันนั่นคือถูกขับออกจากคุณสมบัติ EntityEntries ของ PersistNceContext*/ session.evict (ผู้ใช้); /** * ไม่สามารถส่งได้สำเร็จเนื่องจากเมื่อ Hibernate ทำความสะอาดแคชวัตถุผู้ใช้จะถูกนำออกจากเซสชันแทรกคอลเลกชันชั่วคราวสำหรับการแทรก * หลังจากการดำเนินการการดำรงอยู่ intensIndatabase ในคุณสมบัติ Entityentries จะต้องได้รับการปรับปรุงให้เป็นจริง Transaction.Commit (); } catch (exception e) {e.printstacktrace (); ธุรกรรม Rollback (); } ในที่สุด {hibernateutils.closesession (เซสชัน); - การดีบักผ่านจุดพัก:
1. เนื่องจากมีการใช้กลยุทธ์การสร้างคีย์หลักของ UUID คำสั่งแทรกจะไม่ถูกส่งหลังจากเรียกวิธีการบันทึก () วัตถุนั้นรวมอยู่ในการจัดการเซสชัน ID ถูกสร้างขึ้นและไม่มีข้อมูลที่สอดคล้องกันในฐานข้อมูล (นั่นคือค่าแอตทริบิวต์ ExisIsDatabase เป็นเท็จ)
2. หลังจากเรียก Evict () ขับไล่วัตถุผู้ใช้ออกจากเซสชันนั่นคือถูกขับออกจากคุณสมบัติ Entityentries ของ PersistenceContext
3. เมื่อฉันเรียกเมธอด commit () อีกครั้งเราจะพบว่าข้อมูลของเราไม่สามารถบันทึกได้เนื่องจากในตอนแรกคุณสมบัติการดำรงอยู่ของเราเป็นเท็จนั่นคือไม่มีข้อมูลที่สอดคล้องกันในฐานข้อมูล จากนั้นเราเรียกว่า Evil () เพื่อลบคุณสมบัติของวัตถุทั้งหมดใน PersistenceContext (ยังรวมถึงคุณสมบัติการดำรงอยู่ INDATABASE) แต่ข้อมูลที่เก็บไว้ชั่วคราวใน ActionQueue ยังไม่ถูกลบ เมื่อเราเรียกเมธอด commit () เราจะเรียกเมธอด Flush () โดยปริยาย ฟังก์ชั่นของวิธีนี้ได้รับการกล่าวถึงก่อนหน้านี้ มันจะแทรกวัตถุชั่วคราวใน ActionQueue จากนั้นตั้งค่าคุณสมบัติคุณสมบัติ ExistIsSindatabase ใน PersistenceContext เป็น TRUE น่าเสียดายที่ไม่มีคุณสมบัติที่มีอยู่ใน ansterenceContext ดังนั้นข้อผิดพลาดจะเกิดขึ้นส่งผลให้ไม่สามารถบันทึกได้
ในการทำเช่นนี้เราปรับปรุงขั้นตอนข้างต้น:
/ ***ทดสอบกลยุทธ์การสร้างคีย์หลัก UUID*/ โมฆะสาธารณะ TestSave4 () {/*เซสชันที่กำหนดและสิ่งต่าง ๆ*/ เซสชันเซสชัน = null; ธุรกรรมการทำธุรกรรม = null; ลอง { /*รับเซสชันและสิ่งต่าง ๆ* / เซสชัน = hibernateutils.getSession (); ธุรกรรม = session.beginTransaction (); /*สร้างผู้ใช้*/ ผู้ใช้ผู้ใช้ = ผู้ใช้ใหม่ (); user.setuname ("Hu Jintao"); user.setBirthday (วันที่ใหม่ ()); /*** เนื่องจากกลยุทธ์การสร้างคีย์หลักของผู้ใช้คือ UUID หลังจากโทรบันทึกเพียงแค่รวมผู้ใช้เข้ากับการจัดการเซสชัน* จะไม่ออกคำสั่งแทรก แต่ ID ได้ถูกสร้างขึ้น สถานะการดำรงอยู่ INTERINETEBASE ใน PersistNENCECONTEXT เป็นเท็จ */ เซสชัน SAVE (ผู้ใช้); / ***หลังจากฟลัชไฮเบอร์เนตจะทำความสะอาดแคชบันทึกวัตถุผู้ใช้ไปยังฐานข้อมูลล้างวัตถุผู้ใช้ในการแทรกในเซสชัน*และตั้งสถานะของ ExistIsDatabase ใน StensheNcecontext เป็น true*/ session.flush (); / * ขับไล่วัตถุผู้ใช้จากเซสชันนั่นคือถูกไล่ออกจากคุณสมบัติ EntityEntries ของ PersistNceContext */ session.evict (ผู้ใช้); / *** สามารถส่งได้สำเร็จเนื่องจาก hibernate ไม่สามารถอยู่ในคอลเลกชันการแทรกเซสชันเมื่อทำความสะอาดแคช* วัตถุผู้ใช้ถูกพบ (ล้างเมื่อเรียกว่าฟลัช) ดังนั้นคำสั่งแทรกจะไม่ถูกออก } catch (exception e) {e.printstacktrace (); ธุรกรรม Rollback (); } ในที่สุด {hibernateutils.closesession (เซสชัน); - หมายเหตุ: หลังจากบันทึกแล้วเราเรียกวิธี Flush () จากนั้นเรียกใช้วิธี Evict () หลังจากโปรแกรมที่แก้ไขแล้ว
การดีบักผ่านจุดพัก:
1. เนื่องจากมันยังคงเป็นกลยุทธ์การสร้าง UUID หลังจากโทรบันทึกคำสั่งแทรกจะไม่ได้รับการออก แต่วัตถุนั้นรวมอยู่ในการจัดการเซสชัน คุณสมบัติ ExistIsSindatabase ใน StensentenceContext เป็นเท็จ
2. หลังจากโทรบันทึก () เราเรียกวิธีการล้าง () อีกครั้ง ฟังก์ชั่นของวิธีนี้คือการทำความสะอาดแคชนั่นคือออกคำสั่งแทรกแทรกวัตถุชั่วคราวในการแทรกในเซสชันลงในฐานข้อมูลจากนั้นล้างคอลเลกชันชั่วคราวและตั้งค่าคุณสมบัติ ExistIstIndatabase ใน PersistenceContext เป็น TRUE
3. หลังจากโทร Flush () วิธีการ Evict () เรียกว่า ฟังก์ชั่นของมันคือการล้างวัตถุผู้ใช้จากเซสชันนั่นคือเพื่อล้างคุณสมบัติ Entityentries ของ StensentenceContext
4. หลังจากเรียกเมธอด Evict () วิธีการ commit () จะเรียกเมธอด flush () โดยปริยายก่อน ฟังก์ชั่นของฟลัชคือการล้างแคชนั่นคือแทรกวัตถุในเซสชัน-> การแทรกคอลเลกชันชั่วคราวลงในฐานข้อมูล แต่เราได้เรียกวิธีการฟลัช () ก่อน (หมายเหตุ: หลังจากเรียกใช้วิธีนี้การรวบรวมชั่วคราวจะถูกล้าง) ดังนั้นคอลเลกชันชั่วคราวจึงไม่มีวัตถุเลย มันจะไม่อัปเดตสถานะ ExistIstIndatabase ใน StensentenceContext ส่งสำเร็จ
ลองพิจารณาใช้วิธี Evict () ในกลยุทธ์การสร้างคีย์หลักดั้งเดิม:
/ ***ทดสอบกลยุทธ์การสร้างคีย์หลักดั้งเดิม*/ โมฆะสาธารณะ TestSave5 () {/*เซสชันที่กำหนดและสิ่งต่าง ๆ*/ เซสชัน = null; ธุรกรรมการทำธุรกรรม = null; ลอง { /*รับเซสชันและสิ่งต่าง ๆ* / เซสชัน = hibernateutils.getSession (); ธุรกรรม = session.beginTransaction (); /*สร้างผู้ใช้*/ user1 user = ผู้ใช้ใหม่ 1 (); user.setuname ("Ma Ying-jeou"); user.setBirthday (วันที่ใหม่ ()); / *** เนื่องจากกลยุทธ์การสร้างคีย์หลักของ USER1 นั้นเป็นแบบดั้งเดิมหลังจากการโทร Session.save () คำสั่งแทรกจะถูกดำเนินการ* ส่งคืน ID ที่สร้างขึ้นโดยฐานข้อมูลซึ่งรวมอยู่ในการจัดการเซสชันปรับเปลี่ยนสถานะ InsedenceIndatabase ในเซสชันเป็นจริง /* ขับไล่วัตถุผู้ใช้จากเซสชันนั่นคือถูกไล่ออกจากคุณสมบัติ EntityEntries ของ PersistNceContext*/ session.evict (ผู้ใช้); / *** สามารถส่งได้สำเร็จเนื่องจาก hibernate อยู่ในคอลเลกชันการแทรกเซสชันเมื่อทำความสะอาดแคช* ไม่พบวัตถุผู้ใช้ดังนั้นคำสั่งแทรกจะไม่ได้รับการออกหรือสถานะของ ExisIsDatabase ในเซสชันจะไม่ได้รับการปรับปรุง*/ transaction.commit (); } catch (exception e) {e.printstacktrace (); ธุรกรรม Rollback (); } ในที่สุด {hibernateutils.closesession (เซสชัน); - ผ่านการดีบัก:
1. เนื่องจากกลยุทธ์การสร้างคีย์หลักเป็นแบบดั้งเดิมหลังจากเรียกใช้วิธีการบันทึกคำสั่งแทรกจะออกทันทีส่งคืน ID ที่สร้างขึ้นโดยฐานข้อมูลโดยรวมวัตถุเข้ากับการจัดการเซสชันการปรับเปลี่ยนคุณสมบัติการดำรงอยู่ของตาบ่า อย่างไรก็ตามเนื่องจากระดับการแยก MySQL เราไม่สามารถดูข้อมูลได้ก่อนที่จะกระทำ
2. หลังจากการโทรบันทึกวัตถุจะถูกเรียกและวัตถุจะถูกขับออกจากเซสชันนั่นคือมันถูกขับออกจากเอนทิตีเซ็นทรีใน PersistenceContext
3. หลังจากเรียกใช้วิธีการ Evict () วิธีการ commit () สามารถเรียกได้สำเร็จ การกระทำสามารถบันทึกได้สำเร็จเพราะก่อนที่จะเรียกใช้ commit () วิธีการล้าง () จะถูกเรียกโดยปริยายนั่นคือทำความสะอาดแคชและค้นหาวัตถุในคอลเลกชันชั่วคราวเพื่อแทรกลงในฐานข้อมูล อย่างไรก็ตามคุณจะพบว่าไม่มีข้อมูลในการรวบรวมชั่วคราวดังนั้นคำสั่งแทรกจะไม่ได้รับการออกและคุณสมบัติการดำรงอยู่ inIndatabase ใน PersistenceContext จะไม่ได้รับการอัปเดต
ผ่านกรณีข้างต้นเราจะเห็นว่าบางครั้งเราจำเป็นต้องเรียกวิธีการล้าง () เพื่อทำความสะอาดแคช นอกจากนี้เรายังพบปัญหาจากข้างต้นนั่นคือเมื่อเราบันทึก () ข้อมูลเราไม่สามารถดูข้อมูลก่อนที่จะส่งได้นั่นคือระดับการแยกของฐานข้อมูลมี จำกัด ทีนี้มาพูดถึงระดับความโดดเดี่ยวของ MySQL:
1. ตรวจสอบระดับการแยกปัจจุบันของฐานข้อมูล MySQL:
เลือก @@ tx_isolation;
หมายเหตุ: จากรูปเราจะเห็นว่าระดับการแยกเริ่มต้นของฐานข้อมูล MySQL สามารถทำซ้ำได้ซึ่งหมายความว่าจะไม่มีการอ่านที่ไม่สามารถทำซ้ำได้นั่นคือต้องส่งก่อนที่จะอ่านได้
2. ปรับเปลี่ยนระดับการแยกปัจจุบันของ MySQL (สมมติว่ามันไม่ได้ส่งไปอ่านนั่นคือสามารถอ่านได้โดยไม่ต้องกระทำ):
set transaction isolation level read uncommited;
ข้างต้นเป็นคำอธิบายโดยละเอียดทั้งหมดของรหัสระดับ Session_flush ของ Hibernate และการแยก ฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน เพื่อนที่สนใจสามารถอ้างถึงหัวข้ออื่น ๆ ที่เกี่ยวข้องในเว็บไซต์นี้ต่อไป หากมีข้อบกพร่องใด ๆ โปรดฝากข้อความไว้เพื่อชี้ให้เห็น ขอบคุณเพื่อนที่ให้การสนับสนุนเว็บไซต์นี้!