อย่าเขียนโซลูชันการแคชของคุณ
อีกวิธีในการเพิ่มความเร็วในการทำงานกับฐานข้อมูลคือการแคชวัตถุที่เราร้องขอก่อนหน้านี้
สำคัญ! อย่าเขียนโซลูชันการแคชของคุณเอง งานนี้มีข้อผิดพลาดมากมายที่คุณไม่เคยคาดฝันมาก่อน
ปัญหา 1 - ล้างแคช บางครั้งเหตุการณ์เกิดขึ้นเมื่อจำเป็นต้องลบวัตถุออกจากแคชหรืออัปเดตในแคช วิธีเดียวที่จะทำเช่นนี้ได้คือการส่งคำขอทั้งหมดไปยังฐานข้อมูลผ่านแคชเอ็นจิ้น มิฉะนั้น แต่ละครั้งคุณจะต้องบอกแคชอย่างชัดเจนว่าควรลบหรืออัปเดตออบเจ็กต์ใดในนั้น
ปัญหา 2 - ขาดหน่วยความจำ การแคชดูเหมือนจะเป็นความคิดที่ดีจนกว่าคุณจะพบว่าวัตถุในหน่วยความจำใช้พื้นที่มาก คุณต้องมีหน่วยความจำเพิ่มเติมหลายสิบกิกะไบต์เพื่อให้แคชแอปพลิเคชันเซิร์ฟเวอร์ทำงานได้อย่างมีประสิทธิภาพ
และเนื่องจากมีหน่วยความจำไม่เพียงพออยู่เสมอ จึงจำเป็นต้องมีกลยุทธ์ที่มีประสิทธิภาพสำหรับการลบวัตถุออกจากแคช สิ่งนี้ค่อนข้างคล้ายกับตัวรวบรวมขยะใน Java และอย่างที่คุณจำได้ เป็นเวลาหลายทศวรรษที่ผู้ที่มีความคิดที่ดีที่สุดได้คิดค้นวิธีต่างๆ ในการทำเครื่องหมายบนวัตถุจากรุ่นสู่รุ่น ฯลฯ
ปัญหา 3 - กลยุทธ์ที่แตกต่างกัน ตามที่แสดงในทางปฏิบัติ กลยุทธ์ต่างๆ สำหรับการจัดเก็บและอัปเดตในแคชมีผลกับวัตถุต่างๆ ระบบแคชที่มีประสิทธิภาพไม่สามารถทำเพียงกลยุทธ์เดียวสำหรับอ็อบเจ็กต์ทั้งหมด
ปัญหาที่ 4 - การจัดเก็บอย่างมีประสิทธิภาพของ . คุณไม่สามารถเก็บวัตถุไว้ในแคชได้ วัตถุมักมีการอ้างอิงถึงวัตถุอื่นมากเกินไป เป็นต้น ในอัตรานี้ คุณไม่จำเป็นต้องมีตัวเก็บขยะ
ดังนั้น แทนที่จะจัดเก็บออบเจกต์เอง บางครั้งการเก็บค่าของฟิลด์ดั้งเดิมก็มีประสิทธิภาพมากกว่ามาก และระบบสำหรับการสร้างอ็อบเจกต์ตามพวกมันอย่างรวดเร็ว
ดังนั้น คุณจะได้รับ DBMS เสมือนทั้งหมดในหน่วยความจำ ซึ่งควรทำงานได้อย่างรวดเร็วและใช้หน่วยความจำน้อย
การแคชฐานข้อมูล
นอกเหนือจากการแคชโดยตรงในโปรแกรม Java แล้ว การแคชมักถูกจัดระเบียบโดยตรงในฐานข้อมูล
มีสี่แนวทางใหญ่:
วิธีแรกคือการทำให้ฐานข้อมูลเป็นปกติ เซิร์ฟเวอร์ SQL เก็บข้อมูลไว้ในหน่วยความจำแตกต่างจากที่เก็บไว้ในตาราง
เมื่อข้อมูลถูกเก็บไว้ในดิสก์ในตาราง บ่อยครั้งที่นักพัฒนาพยายามหลีกเลี่ยงการทำซ้ำข้อมูลให้มากที่สุด - กระบวนการนี้เรียกว่าการปรับฐานข้อมูลให้เป็นมาตรฐาน ดังนั้นเพื่อเพิ่มความเร็วในการทำงานกับข้อมูลในหน่วยความจำ กระบวนการย้อนกลับจะดำเนินการ - การทำให้เป็นมาตรฐานของฐานข้อมูล ตารางที่เกี่ยวข้องจำนวนมากสามารถจัดเก็บในรูปแบบรวม - ในรูปแบบของตารางขนาดใหญ่ ฯลฯ
วิธีที่สองคือการแคชแบบสอบถาม และผลการสอบถาม.
DBMS เห็นว่าบ่อยครั้งมากที่คำขอเดียวกันหรือคล้ายคลึงกันมาถึง จากนั้นเพียงเริ่มแคชคำขอเหล่านี้และการตอบกลับ แต่ในขณะเดียวกัน คุณต้องแน่ใจว่าแถวที่มีการเปลี่ยนแปลงในฐานข้อมูลถูกลบออกจากแคชในเวลาที่เหมาะสม
วิธีการนี้อาจมีประสิทธิภาพมากกับมนุษย์ที่สามารถวิเคราะห์การสืบค้นและช่วยให้ DBMS หาวิธีที่ดีที่สุดในการแคช
วิธีที่สามคือฐานข้อมูลในหน่วยความจำ
อีกแนวทางหนึ่งที่ใช้กันทั่วไป ฐานข้อมูลอื่นอยู่ระหว่างเซิร์ฟเวอร์และ DBMS ซึ่งเก็บข้อมูลทั้งหมดไว้ในหน่วยความจำเท่านั้น เรียกอีกอย่างว่า In-Memory-DB หากคุณมีเซิร์ฟเวอร์หลายตัวที่เข้าถึงฐานข้อมูลเดียวกัน การใช้ In-Memory-DB คุณจะสามารถจัดระเบียบการแคชตามประเภทของเซิร์ฟเวอร์เฉพาะได้
ตัวอย่าง:
![](https://cdn.codegym.cc/images/article/a2a92dd6-07b2-46e4-880c-7f2673af154b/1024.jpeg)
แนวทางที่ 4 - คลัสเตอร์ฐานข้อมูล ฐานแบบอ่านอย่างเดียวหลายฐาน
อีกวิธีหนึ่งคือการใช้คลัสเตอร์: DBMS ประเภทเดียวกันหลายตัวมีข้อมูลที่เหมือนกัน ในเวลาเดียวกัน คุณสามารถอ่านข้อมูลจากฐานข้อมูลทั้งหมด และเขียนไปยังฐานข้อมูลเดียวเท่านั้น ซึ่งจะซิงโครไนซ์กับฐานข้อมูลที่เหลือ
นี่เป็นวิธีแก้ปัญหาที่ดีมากเพราะง่ายต่อการกำหนดค่าและใช้งานได้จริง โดยปกติแล้ว สำหรับการร้องขอหนึ่งครั้งไปยังฐานข้อมูลเพื่อเปลี่ยนแปลงข้อมูล จะมีคำขอ 10-100 รายการสำหรับการอ่านข้อมูล
ประเภทของการแคชในไฮเบอร์เนต
Hibernate รองรับการแคชสามระดับ:
- การแคชในระดับเซสชัน (เซสชัน)
- การแคชที่ระดับ SessionFactory
- คำขอแคช (และผลลัพธ์)
คุณสามารถลองแสดงระบบนี้ในรูปแบบของตัวเลข:
![](https://cdn.codegym.cc/images/article/938d3cbc-b006-4c2d-9bdc-b2311e5de4a5/1024.jpeg)
การแคชประเภทที่ง่ายที่สุด (เรียกอีกอย่างว่าแคชระดับแรก ) ถูกนำมาใช้ที่ระดับเซสชันไฮเบอร์เนต ไฮเบอร์เนตจะใช้แคชนี้ตามค่าเริ่มต้นเสมอและไม่สามารถปิดใช้งานได้
ลองพิจารณาตัวอย่างต่อไปนี้ทันที:
Employee director1 = session.get(Employee.class, 4);
Employee director2 = session.get(Employee.class, 4);
assertTrue(director1 == director2);
อาจดูเหมือนว่าจะมีการเรียกใช้แบบสอบถามสองรายการในฐานข้อมูลที่นี่ แต่ก็ไม่เป็นเช่นนั้น หลังจากการร้องขอครั้งแรกไปยังฐานข้อมูล วัตถุพนักงานจะถูกแคช และหากคุณสอบถามออบเจกต์อีกครั้งในเซสชันเดียวกัน Hibernate จะส่งคืนออบเจกต์ Java เดิม
วัตถุเดียวกันหมายความว่าแม้การอ้างอิงวัตถุจะเหมือนกัน มันเป็นวัตถุเดียวกันจริงๆ
เมธอด save() , update() , saveOrUpdate() , load() , get () , list() , iterate()และscroll()จะใช้แคชระดับแรกเสมอ จริงๆแล้วไม่มีอะไรจะเพิ่มเติม
แคชระดับที่สอง
ถ้าแคชระดับแรกถูกผูกไว้กับวัตถุเซสชัน ดังนั้นแคชระดับที่สองจะถูกผูกไว้กับวัตถุเซสชันโรงงานเซสชัน. ซึ่งหมายความว่าการมองเห็นวัตถุในแคชนี้กว้างกว่าแคชระดับแรกมาก
ตัวอย่าง:
Session session = factory.openSession();
Employee director1 = session.get(Employee.class, 4);
session.close();
Session session = factory.openSession();
Employee director2 = session.get(Employee.class, 4);
session.close();
assertTrue(director1 != director2);
assertTrue(director1.equals(director2));
ในตัวอย่างนี้ แบบสอบถามสองรายการจะถูกสร้างไปยังฐานข้อมูล Hibernate จะส่งคืนวัตถุที่เหมือนกัน แต่จะไม่ใช่วัตถุเดียวกัน - พวกมันจะมีการอ้างอิงที่แตกต่างกัน
การแคชระดับ ที่ สอง ถูกปิดใช้งานตามค่าเริ่มต้น ดังนั้นเราจึงมีแบบสอบถามสองรายการไปยังฐานข้อมูลแทนที่จะเป็นหนึ่งรายการ
หากต้องการเปิดใช้งาน คุณต้องเขียนบรรทัดต่อไปนี้ในไฟล์ hibernate.cfg.xml:
<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletEhCacheProvider"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
หลังจากเปิดใช้งานการแคชระดับที่สอง พฤติกรรมการไฮเบอร์เนตจะเปลี่ยนไปเล็กน้อย:
Session session = factory.openSession();
Employee director1 = session.get(Employee.class, 4);
session.close();
Session session = factory.openSession();
Employee director2 = session.get(Employee.class, 4);
session.close();
assertTrue(director1 == director2);
หลังจากการจัดการเหล่านี้ทั้งหมดเท่านั้นที่จะเปิดใช้งานแคชระดับสอง และในตัวอย่างด้านบน จะมีการเรียกใช้แบบสอบถามไปยังฐานข้อมูลเพียงรายการเดียว