อย่าเขียนโซลูชันการแคชของคุณ

อีกวิธีในการเพิ่มความเร็วในการทำงานกับฐานข้อมูลคือการแคชวัตถุที่เราร้องขอก่อนหน้านี้

สำคัญ! อย่าเขียนโซลูชันการแคชของคุณเอง งานนี้มีข้อผิดพลาดมากมายที่คุณไม่เคยคาดฝันมาก่อน

ปัญหา 1 - ล้างแคช บางครั้งเหตุการณ์เกิดขึ้นเมื่อจำเป็นต้องลบวัตถุออกจากแคชหรืออัปเดตในแคช วิธีเดียวที่จะทำเช่นนี้ได้คือการส่งคำขอทั้งหมดไปยังฐานข้อมูลผ่านแคชเอ็นจิ้น มิฉะนั้น แต่ละครั้งคุณจะต้องบอกแคชอย่างชัดเจนว่าควรลบหรืออัปเดตออบเจ็กต์ใดในนั้น

ปัญหา 2 - ขาดหน่วยความจำ การแคชดูเหมือนจะเป็นความคิดที่ดีจนกว่าคุณจะพบว่าวัตถุในหน่วยความจำใช้พื้นที่มาก คุณต้องมีหน่วยความจำเพิ่มเติมหลายสิบกิกะไบต์เพื่อให้แคชแอปพลิเคชันเซิร์ฟเวอร์ทำงานได้อย่างมีประสิทธิภาพ

และเนื่องจากมีหน่วยความจำไม่เพียงพออยู่เสมอ จึงจำเป็นต้องมีกลยุทธ์ที่มีประสิทธิภาพสำหรับการลบวัตถุออกจากแคช สิ่งนี้ค่อนข้างคล้ายกับตัวรวบรวมขยะใน Java และอย่างที่คุณจำได้ เป็นเวลาหลายทศวรรษที่ผู้ที่มีความคิดที่ดีที่สุดได้คิดค้นวิธีต่างๆ ในการทำเครื่องหมายบนวัตถุจากรุ่นสู่รุ่น ฯลฯ

ปัญหา 3 - กลยุทธ์ที่แตกต่างกัน ตามที่แสดงในทางปฏิบัติ กลยุทธ์ต่างๆ สำหรับการจัดเก็บและอัปเดตในแคชมีผลกับวัตถุต่างๆ ระบบแคชที่มีประสิทธิภาพไม่สามารถทำเพียงกลยุทธ์เดียวสำหรับอ็อบเจ็กต์ทั้งหมด

ปัญหาที่ 4 - การจัดเก็บอย่างมีประสิทธิภาพของ . คุณไม่สามารถเก็บวัตถุไว้ในแคชได้ วัตถุมักมีการอ้างอิงถึงวัตถุอื่นมากเกินไป เป็นต้น ในอัตรานี้ คุณไม่จำเป็นต้องมีตัวเก็บขยะ

ดังนั้น แทนที่จะจัดเก็บออบเจกต์เอง บางครั้งการเก็บค่าของฟิลด์ดั้งเดิมก็มีประสิทธิภาพมากกว่ามาก และระบบสำหรับการสร้างอ็อบเจกต์ตามพวกมันอย่างรวดเร็ว

ดังนั้น คุณจะได้รับ DBMS เสมือนทั้งหมดในหน่วยความจำ ซึ่งควรทำงานได้อย่างรวดเร็วและใช้หน่วยความจำน้อย

การแคชฐานข้อมูล

นอกเหนือจากการแคชโดยตรงในโปรแกรม Java แล้ว การแคชมักถูกจัดระเบียบโดยตรงในฐานข้อมูล

มีสี่แนวทางใหญ่:

วิธีแรกคือการทำให้ฐานข้อมูลเป็นปกติ เซิร์ฟเวอร์ SQL เก็บข้อมูลไว้ในหน่วยความจำแตกต่างจากที่เก็บไว้ในตาราง

เมื่อข้อมูลถูกเก็บไว้ในดิสก์ในตาราง บ่อยครั้งที่นักพัฒนาพยายามหลีกเลี่ยงการทำซ้ำข้อมูลให้มากที่สุด - กระบวนการนี้เรียกว่าการปรับฐานข้อมูลให้เป็นมาตรฐาน ดังนั้นเพื่อเพิ่มความเร็วในการทำงานกับข้อมูลในหน่วยความจำ กระบวนการย้อนกลับจะดำเนินการ - การทำให้เป็นมาตรฐานของฐานข้อมูล ตารางที่เกี่ยวข้องจำนวนมากสามารถจัดเก็บในรูปแบบรวม - ในรูปแบบของตารางขนาดใหญ่ ฯลฯ

วิธีที่สองคือการแคชแบบสอบถาม และผลการสอบถาม.

DBMS เห็นว่าบ่อยครั้งมากที่คำขอเดียวกันหรือคล้ายคลึงกันมาถึง จากนั้นเพียงเริ่มแคชคำขอเหล่านี้และการตอบกลับ แต่ในขณะเดียวกัน คุณต้องแน่ใจว่าแถวที่มีการเปลี่ยนแปลงในฐานข้อมูลถูกลบออกจากแคชในเวลาที่เหมาะสม

วิธีการนี้อาจมีประสิทธิภาพมากกับมนุษย์ที่สามารถวิเคราะห์การสืบค้นและช่วยให้ DBMS หาวิธีที่ดีที่สุดในการแคช

วิธีที่สามคือฐานข้อมูลในหน่วยความจำ

อีกแนวทางหนึ่งที่ใช้กันทั่วไป ฐานข้อมูลอื่นอยู่ระหว่างเซิร์ฟเวอร์และ DBMS ซึ่งเก็บข้อมูลทั้งหมดไว้ในหน่วยความจำเท่านั้น เรียกอีกอย่างว่า In-Memory-DB หากคุณมีเซิร์ฟเวอร์หลายตัวที่เข้าถึงฐานข้อมูลเดียวกัน การใช้ In-Memory-DB คุณจะสามารถจัดระเบียบการแคชตามประเภทของเซิร์ฟเวอร์เฉพาะได้

ตัวอย่าง:

แนวทางที่ 4 - คลัสเตอร์ฐานข้อมูล ฐานแบบอ่านอย่างเดียวหลายฐาน

อีกวิธีหนึ่งคือการใช้คลัสเตอร์: DBMS ประเภทเดียวกันหลายตัวมีข้อมูลที่เหมือนกัน ในเวลาเดียวกัน คุณสามารถอ่านข้อมูลจากฐานข้อมูลทั้งหมด และเขียนไปยังฐานข้อมูลเดียวเท่านั้น ซึ่งจะซิงโครไนซ์กับฐานข้อมูลที่เหลือ

นี่เป็นวิธีแก้ปัญหาที่ดีมากเพราะง่ายต่อการกำหนดค่าและใช้งานได้จริง โดยปกติแล้ว สำหรับการร้องขอหนึ่งครั้งไปยังฐานข้อมูลเพื่อเปลี่ยนแปลงข้อมูล จะมีคำขอ 10-100 รายการสำหรับการอ่านข้อมูล

ประเภทของการแคชในไฮเบอร์เนต

Hibernate รองรับการแคชสามระดับ:

  • การแคชในระดับเซสชัน (เซสชัน)
  • การแคชที่ระดับ SessionFactory
  • คำขอแคช (และผลลัพธ์)

คุณสามารถลองแสดงระบบนี้ในรูปแบบของตัวเลข:

การแคชประเภทที่ง่ายที่สุด (เรียกอีกอย่างว่าแคชระดับแรก ) ถูกนำมาใช้ที่ระดับเซสชันไฮเบอร์เนต ไฮเบอร์เนตจะใช้แคชนี้ตามค่าเริ่มต้นเสมอและไม่สามารถปิดใช้งานได้

ลองพิจารณาตัวอย่างต่อไปนี้ทันที:

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);

หลังจากการจัดการเหล่านี้ทั้งหมดเท่านั้นที่จะเปิดใช้งานแคชระดับสอง และในตัวอย่างด้านบน จะมีการเรียกใช้แบบสอบถามไปยังฐานข้อมูลเพียงรายการเดียว