Jangan sekali-kali menulis penyelesaian caching anda

Satu lagi cara untuk mempercepatkan kerja dengan pangkalan data adalah dengan cache objek yang telah kami minta sebelum ini.

Penting! Jangan sekali-kali menulis penyelesaian caching anda sendiri. Tugas ini mempunyai begitu banyak perangkap yang tidak pernah anda impikan.

Isu 1 - siram cache . Kadangkala peristiwa berlaku apabila objek perlu dialih keluar daripada cache atau dikemas kini dalam cache. Satu-satunya cara untuk melakukan ini dengan cekap adalah dengan menghantar semua permintaan ke pangkalan data melalui enjin cache. Jika tidak, setiap kali anda perlu memberitahu cache secara eksplisit objek mana yang harus dipadamkan atau dikemas kini.

Masalah 2 - kekurangan ingatan . Caching kelihatan seperti idea yang bagus sehingga anda mendapati objek dalam ingatan mengambil banyak ruang. Anda memerlukan tambahan berpuluh-puluh gigabait memori untuk cache aplikasi pelayan berfungsi dengan berkesan.

Dan kerana sentiasa terdapat kekurangan memori, strategi yang berkesan untuk memadam objek daripada cache diperlukan. Ini agak serupa dengan pemungut sampah di Jawa. Dan seperti yang anda ingat, selama beberapa dekad, minda terbaik telah mencipta pelbagai cara untuk menandakan objek mengikut generasi, dsb.

Masalah 3 - strategi berbeza . Seperti yang ditunjukkan oleh amalan, strategi yang berbeza untuk menyimpan dan mengemas kini dalam cache adalah berkesan untuk objek yang berbeza. Sistem caching yang cekap tidak boleh melakukan hanya satu strategi untuk semua objek.

Masalah 4 - Penyimpanan yang cekap bagi . Anda tidak boleh menyimpan objek dalam cache sahaja. Objek terlalu kerap mengandungi rujukan kepada objek lain dan sebagainya. Pada kadar ini, anda tidak memerlukan pengumpul sampah: ia tidak akan mempunyai apa-apa untuk dialih keluar.

Oleh itu, daripada menyimpan objek itu sendiri, kadangkala lebih cekap untuk menyimpan nilai medan primitif mereka. Dan sistem untuk membina objek dengan cepat berdasarkannya.

Akibatnya, anda akan mendapat keseluruhan DBMS maya dalam ingatan, yang sepatutnya berfungsi dengan cepat dan menggunakan sedikit memori.

Cache pangkalan data

Selain daripada caching secara langsung dalam program Java, caching selalunya dianjurkan secara langsung dalam pangkalan data.

Terdapat empat pendekatan besar:

Pendekatan pertama ialah menyahnormalkan pangkalan data . Pelayan SQL menyimpan data dalam memori secara berbeza daripada cara ia disimpan dalam jadual.

Apabila data disimpan pada cakera dalam jadual, selalunya pembangun cuba mengelakkan pertindihan data sebanyak mungkin - proses ini dipanggil normalisasi pangkalan data. Jadi, untuk mempercepatkan kerja dengan data dalam ingatan, proses terbalik dilakukan - denormalisasi pangkalan data. Sekumpulan jadual yang berkaitan sudah boleh disimpan dalam bentuk gabungan - dalam bentuk jadual besar, dsb.

Pendekatan kedua ialah query caching . Dan hasil pertanyaan.

DBMS melihat bahawa selalunya permintaan yang sama atau serupa datang kepadanya. Kemudian ia hanya mula menyimpan cache permintaan ini dan respons mereka. Tetapi pada masa yang sama, anda perlu memastikan bahawa baris yang telah berubah dalam pangkalan data dialih keluar dari cache tepat pada masanya.

Pendekatan ini boleh menjadi sangat berkesan dengan manusia yang boleh menganalisis pertanyaan dan membantu DBMS memikirkan cara terbaik untuk menyimpannya.

Pendekatan ketiga ialah pangkalan data dalam memori .

Satu lagi pendekatan yang biasa digunakan. Pangkalan data lain diletakkan di antara pelayan dan DBMS, yang menyimpan semua datanya hanya dalam ingatan. Ia juga dipanggil In-Memory-DB. Jika anda mempunyai banyak pelayan berbeza yang mengakses pangkalan data yang sama, kemudian menggunakan In-Memory-DB anda boleh mengatur caching berdasarkan jenis pelayan tertentu.

Contoh:

Pendekatan 4 - kluster pangkalan data . Beberapa asas baca sahaja.

Penyelesaian lain ialah menggunakan kluster: beberapa DBMS daripada jenis yang sama mengandungi data yang sama. Pada masa yang sama, anda boleh membaca data daripada semua pangkalan data, dan menulis kepada satu sahaja. Yang kemudiannya disegerakkan dengan pangkalan data yang lain.

Ini adalah penyelesaian yang sangat baik kerana ia mudah untuk dikonfigurasikan dan berfungsi dalam amalan. Biasanya, untuk satu permintaan kepada pangkalan data untuk menukar data, 10-100 permintaan untuk membaca data datang kepadanya.

Jenis caching dalam Hibernate

Hibernate menyokong tiga tahap caching:

  • Caching pada peringkat sesi (Sesi)
  • Caching pada peringkat SessionFactory
  • Permintaan caching (dan keputusannya)

Anda boleh cuba mewakili sistem ini dalam bentuk angka sedemikian:

Jenis caching yang paling mudah (juga dipanggil cache tahap pertama ) dilaksanakan pada tahap sesi Hibernate. Hibernate sentiasa menggunakan cache ini secara lalai dan tidak boleh dilumpuhkan .

Mari segera pertimbangkan contoh berikut:

Employee director1 = session.get(Employee.class, 4);
Employee director2 = session.get(Employee.class, 4);

assertTrue(director1 == director2);

Nampaknya dua pertanyaan kepada pangkalan data akan dilaksanakan di sini, tetapi ini tidak begitu. Selepas permintaan pertama kepada pangkalan data, objek Pekerja akan dicache. Dan jika anda menanyakan objek sekali lagi dalam sesi yang sama, Hibernate akan mengembalikan objek Java yang sama.

Objek yang sama bermakna walaupun rujukan objek akan sama. Ia benar-benar objek yang sama.

Kaedah save() , update() , saveOrUpdate() , load() , get() , list() , iterate() dan scroll() akan sentiasa menggunakan cache tahap pertama. Sebenarnya, tiada apa yang perlu ditambah.

Caching tahap kedua

Jika cache tahap pertama terikat pada objek sesi, maka cache tahap kedua terikat pada objek sesi.SessionFactory. Ini bermakna keterlihatan objek dalam cache ini jauh lebih luas daripada cache tahap pertama.

Contoh:

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

Dalam contoh ini, dua pertanyaan akan dibuat ke pangkalan data. Hibernate akan mengembalikan objek yang sama, tetapi ia tidak akan menjadi objek yang sama - mereka akan mempunyai rujukan yang berbeza.

Caching tahap kedua dilumpuhkan secara lalai . Oleh itu, kami mempunyai dua pertanyaan kepada pangkalan data dan bukannya satu.

Untuk mendayakannya, anda perlu menulis baris berikut dalam fail 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"/>

Selepas mendayakan caching peringkat kedua, tingkah laku Hibernate akan berubah sedikit:

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

Hanya selepas semua manipulasi ini, cache peringkat kedua akan didayakan, dan dalam contoh di atas, hanya satu pertanyaan kepada pangkalan data akan dilaksanakan.