แคช
วันนี้เราจะพูดคุยเกี่ยวกับรัฐเอนทิตีและแคชไฮเบอร์เนตในไฮเบอร์เนต
1) ก่อนอื่นมาดูสถานะเอนทิตี:
สถานะของเอนทิตีหลักสามประเภท: ชั่วคราว, ถาวรและแยกออก
คุณอาจเข้าใจได้ด้วยการอ่านภาษาอังกฤษ
ชั่วคราว: หมายถึงข้อมูลที่ยังไม่สอดคล้องกับข้อมูลในฐานข้อมูล
ถาวร: หมายถึงข้อมูลที่สอดคล้องกับข้อมูลในฐานข้อมูลและการเปลี่ยนแปลงใด ๆ ในนั้นจะสะท้อนให้เห็นในฐานข้อมูล
Detached: หมายถึงข้อมูลที่สอดคล้องกับข้อมูลในฐานข้อมูล แต่เนื่องจากเซสชันถูกปิดการแก้ไขที่ทำจะไม่ส่งผลกระทบต่อบันทึกฐานข้อมูล
รหัสตรง:
ธุรกรรม tx = session.beginTransaction (); ผู้ใช้ผู้ใช้ = ผู้ใช้ใหม่ (); user.setName ("Shun"); // ผู้ใช้ที่นี่ไม่ได้ถูกบันทึกลงในฐานข้อมูลและไม่มีระเบียนที่สอดคล้องกันในตารางฐานข้อมูล เป็นเซสชันสถานะชั่วคราว SAVE (ผู้ใช้); tx.commit (); // หลังจากการกระทำผู้ใช้จะกลายเป็น state session.close (); // เนื่องจากเซสชันถูกปิดผู้ใช้จะถูกถอดออกในเวลานี้และการแก้ไขทั้งหมดจะไม่ถูกสะท้อนในฐานข้อมูล เซสชั่นเซสชัน 2 = sessionfactory.opensession (); tx = session2.beginTransaction (); user.setName ("shun123"); session2.saveorupdate (ผู้ใช้); tx.commit (); // เมื่อเราเรียก saveorupdate ผู้ใช้จะคงอยู่อีกครั้งและการแก้ไขทั้งหมดจะสะท้อนให้เห็นในฐานข้อมูล session2.close (); เราเห็นรหัส ก่อนอื่นเรากำหนดผู้ใช้วัตถุ ก่อนที่จะถูกบันทึกไว้เป็นสถานะชั่วคราวและไม่มีระเบียนที่สอดคล้องกันในฐานข้อมูล เมื่อเราบันทึกและส่งการดัดแปลงผู้ใช้จะกลายเป็นสถานะถาวรและมีระเบียนที่สอดคล้องกันในฐานข้อมูล เมื่อเราปิดเซสชันผู้ใช้จะถูกแยกออกและการเปลี่ยนแปลงของมันจะไม่ถูกสะท้อนในฐานข้อมูลเว้นแต่ว่าเราจะเรียกการอัปเดตที่สอดคล้องกันและวิธีการเพิ่มเติมเช่น saveorupdate และเราควรทำอย่างไรเมื่อเราต้องการให้มันเปลี่ยนจากสถานะถาวรไปสู่สถานะชั่วคราว? เพียงแค่ลบมันโดยตรง หลังจากการลบวัตถุจะไม่มีระเบียนที่สอดคล้องกันในฐานข้อมูลซึ่งจะกลายเป็นชั่วคราว
การเปลี่ยนแปลงของรัฐของไฮเบอร์เนตนั้นค่อนข้างง่าย เมื่อมันเป็นชั่วคราวไม่มีระเบียนที่สอดคล้องกันสำหรับฐานข้อมูลในขณะที่ถาวรและเดี่ยวมีระเบียนที่สอดคล้องกัน อย่างไรก็ตามความแตกต่างเพียงอย่างเดียวคือเดี่ยวเป็นสถานะที่มีอยู่หลังจากปิดเซสชันเท่านั้น แล้วความแตกต่างระหว่างชั่วคราวและเดี่ยวคืออะไร? เป็นเพียงคำถามว่ามีบันทึกตารางฐานข้อมูลที่สอดคล้องกันหรือไม่
2) หลังจากอ่านสถานะมาดูแคชของไฮเบอร์เนต
แคชมีสองประเภทสำหรับไฮเบอร์เนต: แคชระดับ 1 และแคชระดับ 2
แคชระดับ 1: แคชระดับ 1 ที่เรียกว่าเป็นแคชภายใน
แคชระดับ 2: มีแคชระดับแอปพลิเคชันซึ่งเรียกว่า SessionFactory Cache ใน Hibernate และอีกอันคือ Cache Distributed ซึ่งเป็นวิธีแคชที่ปลอดภัยที่สุด
มาดูโปรแกรมโดยตรง:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {การกำหนดค่า cfg = การกำหนดค่าใหม่ (). configure (); SessionFactory SessionFactory = cfg.buildsessionFactory (); เซสชัน = sessionfactory.opensession (); ผู้ใช้ผู้ใช้ = (ผู้ใช้) เซสชันการโหลด (user.class, ใหม่ยาว (29)); System.out.println (user.getName ()); ผู้ใช้ USER2 = (ผู้ใช้) เซสชันโหลด (user.class, ใหม่ยาว (29)); System.out.println (user2.getName ()); session.close (); - ดูผลลัพธ์:
Hibernate: เลือก user0_.user_id เป็น user1_0_0_, user0_.user_name เป็น user2_0_0_, user0_.age เป็น Age0_0_ จากผู้ใช้ user0_ โดยที่ user0_.user_id =? Shun123123 Shun123123
ในตัวอย่างที่เราใช้โหลดสองครั้ง แต่มีเพียงหนึ่งคำสั่ง SQL ในผลลัพธ์ซึ่งระบุว่ามันเป็นเพียงการสืบค้นเพียงครั้งเดียว
ทำไม นี่คือเหตุผลที่แคชไฮเบอร์เนตใช้งานได้ หลังจากการสืบค้นครั้งแรกเสร็จสิ้นไฮเบอร์เนตเอนทิตีที่พบในแคช ครั้งต่อไปที่คุณตรวจสอบแคชจะถูกตรวจสอบเพื่อดูว่ามีเอนทิตีใด ๆ ที่มี ID ที่เกี่ยวข้องหรือไม่ หากมีมันจะถูกนำออกโดยตรงมิฉะนั้นจะทำการสืบค้นฐานข้อมูล
มาแก้ไขรหัสเป็น:
ผู้ใช้ผู้ใช้ = (ผู้ใช้) เซสชันการโหลด (user.class, ใหม่ยาว (29)); System.out.println (user.getName ()); session.evict (ผู้ใช้); // ลบผู้ใช้จากผู้ใช้แคชผู้ใช้ 2 = (ผู้ใช้) session.load (user.class, ใหม่ยาว (29)); System.out.println (user2.getName ()); session.close ();
ดูผลลัพธ์:
Hibernate: เลือก user0_.user_id เป็น user1_0_0_, user0_.user_name เป็น user2_0_0_, user0_.age เป็น Age0_0_ จากผู้ใช้ user0_ โดยที่ user0_.user_id =? shun123123 ไฮเบอร์เนต: เลือก user0_.user_id เป็น user1_0_0_, user0_.user_name เป็น user2_0_0_, user0_.age เป็น AGE0_0_ จากผู้ใช้ user0_ โดยที่ user0_.user_id =? Shun123123
หลังจากที่เราลบผู้ใช้ออกจากแคชแบบสอบถามที่สองจะถูกดึงโดยตรงจากฐานข้อมูล
แคชระดับ 2 พูดคุย
มาดูคลาสเอนทิตีก่อน:
ผู้ใช้ระดับสาธารณะใช้ serializable {Public Long ID; ชื่อสตริงส่วนตัว; อายุ int ส่วนตัว; - ไฟล์การแมปถูกละเว้นทุกคนควรเขียน
มาดูไฟล์กำหนดค่าไฮเบอร์เนต:
<property name = "hibernate.cache.provider_class"> org.hibernate.cache.ehcacheprovider </คุณสมบัติ> <property name = "hibernate.cache.use_second_level_cache"> true </property> <property name = "hibernate.cache.
เราเห็นว่าใน Provider_Class เราระบุ ehcache ดังนั้นเราจึงต้องการ ehcache.xml ที่จะวางไว้ใน classpath:
<? xml version = "1.0" การเข้ารหัส = "utf-8"?> <ehcache> <diskstore path = "java.io.path"/> <defaultCache maxElementsInMemory = "10,000" Eternal = "false" timetoidleseconds = "120"
ถัดไปลองดูที่วิธีการทดสอบ:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {การกำหนดค่า cfg = การกำหนดค่าใหม่ (). configure (); SessionFactory SessionFactory = cfg.buildsessionFactory (); เซสชัน = sessionfactory.opensession (); Query Query = session.createquery ("จากผู้ใช้ผู้ใช้ที่ Name = 'Shun123'"); ตัววนซ้ำ iter = query.iterate (); ในขณะที่ (iter.hasnext ()) {system.out.println (((ผู้ใช้) iter.next ()). getName ()); } session.close (); เซสชั่นเซสชัน 2 = sessionfactory.opensession (); Query Query2 = session2.createquery ("จากผู้ใช้ผู้ใช้ที่ name = 'shun123'"); ตัววนซ้ำ iter2 = query2.iterate (); ในขณะที่ (iter2.hasnext ()) {system.out.println (((ผู้ใช้) iter2.next ()). getName ()); } session2.close (); - หลังจากทำงานแล้วคุณจะเห็น:
Hibernate: เลือก user0_.user_id เป็น col_0_0_ จากผู้ใช้ user0_ โดยที่ user0_.user_name = 'shun123' ไฮเบอร์เนต: เลือก user0_.user_id เป็น user1_0_0_, user0_.user_name เป็น user2_0_0_, user0_.age shun123 ไฮเบอร์เนต: เลือก user0_.user_id เป็น col_0_0_ จากผู้ใช้ user0_ โดยที่ user0_.user_name = 'shun123' shun123
เราจะเห็นได้ว่ามันทำเพียงหนึ่งประโยคของการค้นหาและ ID ไม่ได้ถูกเรียกร้องสำหรับการค้นหาในแบบสอบถามที่สองซึ่งส่วนใหญ่เป็นเพราะแคชรอง
มาวิเคราะห์รหัสในวิธีการทดสอบก่อน ในวิธีการทดสอบเราเปิดสองเซสชันและสร้างแบบสอบถามสองแบบแยกกันสำหรับการสืบค้นเดียวกัน อย่างไรก็ตามทั้งสองเซสชันสามารถแชร์แคชซึ่งเป็นแคชระดับที่สองแคชระดับเซสชัน factory ตราบใดที่เซสชันของเราถูกสร้างขึ้นโดย SessionFactory เดียวกันเราสามารถแชร์แคชรองเพื่อลดการโต้ตอบกับฐานข้อมูล
ลองมาดูความหมายในไฟล์กำหนดค่า:
<property name = "hibernate.cache.provider_class"> org.hibernate.cache.ehcacheprovider </คุณสมบัติ> <property name = "hibernate.cache.use_second_level_cache"> true </property> <property name = "hibernate.cache.
หากเราต้องการใช้แคชรองเราต้องกำหนดค่าก่อน:
<property name = "hibernate.cache.use_second_level_cache"> true </porement>
ดำเนินการแคชระดับที่สองของการเปิดบัญชีจากนั้นผ่าน:
<property name = "hibernate.cache.provider_class"> org.hibernate.cache.ehcacheprovider </property>
ระบุคลาสบทบัญญัติสำหรับแคชรอง โดยทั่วไปเราใช้ ehcache คนอื่น ๆ ของฉันไม่ได้ใช้ในเวลานั้นและไม่ชัดเจนมากดังนั้นฉันจะไม่พูดถึงพวกเขาในขณะนี้
เช่นเดียวกับตัวอย่างของเราตอนนี้เราจำเป็นต้องกำหนดค่าสองด้านบนซึ่งสามารถทำงานได้ตามปกติและใช้แคชทุติยภูมิ
แล้วประโยคที่สามคืออะไร?
<property name = "hibernate.cache.use_query_cache"> true </property>
การกำหนดค่านี้บ่งชี้ว่าเราจำเป็นต้องใช้แคชเมื่อสอบถาม หากเราต้องการใช้สิ่งนี้เราจะต้องโทรหา query.setCacheable (จริง) ล่วงหน้าเพื่อเปิดใช้งาน
มาดูรหัสด้วยกัน (เราจะไม่เปิดใช้งานแคชในตอนนี้):
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {การกำหนดค่า cfg = การกำหนดค่าใหม่ (). configure (); SessionFactory SessionFactory = cfg.buildsessionFactory (); เซสชัน = sessionfactory.opensession (); Query Query = session.createquery ("จากผู้ใช้ผู้ใช้ที่ Name = 'Shun123'"); รายการรายการ = query.list (); สำหรับ (int i = 0; i <list.size (); i ++) {system.out.println (((ผู้ใช้) list.get.get (i)). getName ()); } session.close (); เซสชั่นเซสชัน 2 = sessionfactory.opensession (); Query Query2 = session2.createquery ("จากผู้ใช้ผู้ใช้ที่ name = 'shun123'"); List List2 = query2.list (); สำหรับ (int i = 0; i <list2.size (); i ++) {system.out.println (((ผู้ใช้) list.get.get (i)). getName ()); } session2.close (); - ผลลัพธ์ผลลัพธ์ที่นี่คือ:
Hibernate: เลือก user0_.user_id เป็น user1_0_, user0_.user_name เป็น user2_0_, user0_.age เป็น Age0_ จากผู้ใช้ user0_ โดย user0_.user_name = 'shun123' shun123 hibernate: เลือก user0_.user_id AGE0_ จากผู้ใช้ USER0_ โดยที่ user0_.user_name = 'shun123' shun123
เราเห็นว่ามันไม่ได้ใช้แคชเพราะเราใช้รายการที่นี่และรายการเขียนเท่านั้นและไม่อ่านแคช ดังนั้นจะมีสองคิวรีที่นี่
แล้วมาแก้ไขกันเถอะ:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {การกำหนดค่า cfg = การกำหนดค่าใหม่ (). configure (); SessionFactory SessionFactory = cfg.buildsessionFactory (); เซสชัน = sessionfactory.opensession (); Query Query = session.createquery ("จากผู้ใช้ผู้ใช้ที่ Name = 'Shun123'"); <span style = "พื้นหลังสี: #ffffff;"> <span style = "สี: #ff0000;"> query.setCacheable (จริง); </span> </span> รายการรายการ = query.list (); สำหรับ (int i = 0; i <list.size (); i ++) {system.out.println (((ผู้ใช้) list.get.get (i)). getName ()); } session.close (); เซสชั่นเซสชัน 2 = sessionfactory.opensession (); Query Query2 = session2.createquery ("จากผู้ใช้ผู้ใช้ที่ name = 'shun123'"); <span style = "สี: #ff0000;"> query2.setCacheable (จริง); </span> list2 = query2.list (); สำหรับ (int i = 0; i <list2.size (); i ++) {system.out.println (((ผู้ใช้) list.get.get (i)). getName ()); } session2.close (); - ฉันเห็นรหัสสีแดงสองประโยค นี่คือสองรหัสที่เราเพิ่มเพื่อเปิดใช้งานแคชแบบสอบถาม ตอนนี้เราเห็นผลลัพธ์:
Hibernate: เลือก user0_.user_id เป็น user1_0_, user0_.user_name เป็น user2_0_, user0_.age เป็น Age0_ จากผู้ใช้ user0_ โดยที่ user0_.user_name = 'shun123' shun123 shun123
มีแบบสอบถามเหลือเพียงหนึ่งเดียวทำไม? เพียงแค่รหัสสีแดงสองรหัสเราเปิดแคชจำไว้ว่ามันจะต้องใช้สองครั้ง ตั้งค่าแคชแบบสอบถามทั้งสองให้แคช
เกณฑ์ยังเป็นวิธีที่คล้ายกัน เพื่อหลีกเลี่ยงรองเท้าเด็กบางคนที่ลืมวิธีการเขียนเกณฑ์ฉันจะใส่รหัสบางอย่าง:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {การกำหนดค่า cfg = การกำหนดค่าใหม่ (). configure (); SessionFactory SessionFactory = cfg.buildsessionFactory (); เซสชัน = sessionfactory.opensession (); เกณฑ์เกณฑ์ 1 = session.createCriteria (user.class); เกณฑ์ 1.SetCacheable (จริง); เกณฑ์ 1.add (ข้อ จำกัด eq ("ชื่อ", "shun123")); รายการรายการ = Criteria1.list (); สำหรับ (int i = 0; i <list.size (); i ++) {system.out.println (((ผู้ใช้) list.get.get (i)). getName ()); } session.close (); เซสชั่นเซสชัน 2 = sessionfactory.opensession (); เกณฑ์เกณฑ์ 2 = เซสชัน 2.CreateCriteria (user.class); Criteria2.setCacheable (จริง); Criteria2.add (ข้อ จำกัด eq ("ชื่อ", "shun123")); List List2 = Criteria2.list (); สำหรับ (int i = 0; i <list2.size (); i ++) {system.out.println (((ผู้ใช้) list.get.get (i)). getName ()); } session2.close (); - มาดูผลลัพธ์:
Hibernate: เลือก this_.user_id เป็น user1_0_0_, this_.user_name เป็น user2_0_0_, this_.age เป็น Age0_0_ จากผู้ใช้ this_ โดยที่ this_.user_name =? Shun123 Shun123