Kata pengantar
Apa cache mybatis level 2?
Cache sekunder dibagikan oleh beberapa sqlsessions, dan ruang lingkupnya adalah namespace yang sama dari mapper.
Yaitu, dalam sqlsessions yang berbeda, di bawah namespace yang sama, pernyataan SQL yang sama, dan parameter dalam template SQL juga sama, dan cache akan terkena.
Setelah eksekusi pertama, data yang ditanya dalam database akan ditulis ke cache, dan data akan diambil dari cache tidak akan lagi ditanya dari database, sehingga meningkatkan efisiensi kueri.
MyBatis tidak mengaktifkan cache sekunder secara default, dan perlu untuk mengaktifkan cache sekunder dalam konfigurasi global (mybatis-config.xml).
Artikel ini menjelaskan metode menggunakan redis sebagai cache untuk diintegrasikan dengan springboot dan mybatis.
1. Ketergantungan pom
Gunakan paket integrasi Springboot Redis untuk memfasilitasi akses ke Redis. Jedis digunakan pada klien Redis.
Selain itu, baca dan tulis cache KV akan diserialisasi, sehingga paket serialisasi diperkenalkan.
<dependency> <GroupId> org.springframework.boot </groupid> <ArTifactId> Spring-boot-starter-redis </artifactid> </dependency> <dependency> <groupid> redis.clients </groupid> <ArTifactid> JEDIS </Artifactid> </Versi 2.8.8.0 <GroupId> com.alibaba </groupid> <ArTifactId> fastjson </artifactid> <version> 1.2.19 </version> </dependency>
Setelah ketergantungan selesai, langkah selanjutnya adalah menyesuaikan klien Redis.
2. Kacang yang digunakan oleh Redis Access
Tambahkan konfigurasi, konfigurasikan kacang jedisconnectionFactory, dan biarkan kemudian digunakan.
Secara umum, kacang redistemplate juga akan dihasilkan, tetapi tidak digunakan dalam skenario berikutnya.
@ConfigurationPublic kelas Recisconfig {@Value ("$ {spring.redis.host}") Private String Host; // Space terbatas, @Bean jedispoolconfig getredisconfig () {jedaispoolconfig config = new jedispoolconfig (); config.setmaxidle (maxidle); config.setmaxtotal (maxtotal); config.setmaxwaitmillis (maxwaitmillis); config.setminidle (minidle); return config; } @Bean (name = "jedaconnectionFactory") public jedisconnectionFactory getConnectionFactory () {jedisconnectionFactory factory = new jedisconnectionFactory (); Jedispoolconfig config = getredisconfig (); factory.setpoolconfig (config); factory.sethostname (host); factory.setport (port); factory.setDatabase (database); factory.setpassword (kata sandi); factory.setTimeout (timeout); Pabrik Kembali; } @Bean (name = "redistemplate") public redistemplate <?,?> Getredistemplate () {redistemplate <?,?> Template = new StrreDistemplate (getConnectionFactory ()); Template Kembalikan; }}Di sini, @Value digunakan untuk membaca konfigurasi terkait Redis, dan ada metode membaca konfigurasi yang lebih sederhana (@configurationproperties (awalan = ...)), yang dapat Anda coba.
Konfigurasi terkait redis adalah sebagai berikut
#redisspring.redis.host = 10.93.84.53spring.redis.port = 6379spring.redis.password = BigData123Spring.redis.database = 15spring.redis. timeout = 0spring.redis.pool.maxtotal = 8spring.redis.pool.maxwaitmillis = 1000spring.redis.pool.maxidle = 8spring.redis.pool.miniDle = 0
Arti konfigurasi klien Redis tidak akan dijelaskan di sini. Terkait pool umumnya terkait dengan kinerja, dan mereka perlu ditetapkan berdasarkan jumlah konkurensi pegangan, memori, dan sumber daya lainnya.
Klien Redis telah diatur, dan kami mulai mengkonfigurasi Redis sebagai cache untuk Mybatis.
3. Mybatis Cache
Langkah ini adalah langkah paling kritis. Metode implementasi adalah mengimplementasikan antarmuka org.apache.atisis.cache.cache dari mybatis.
Desain antarmuka ini menulis cache, baca cache, hancurkan cache, dan kontrol akses baca dan tulis kunci.
Kelas yang kami terapkan untuk mengimplementasikan antarmuka cache adalah mybatisrediscache.
Mybatisrediscache.java
kelas publik mybatisrediscache mengimplementasikan cache {private static jedisconnectionfactory jedisconnectionFactory; ID string final pribadi; Private Final ReadWritelock ReadWritelock = baru reentrantreadwritelock (); public mybatisrediscache (ID string akhir) {if (id == null) {lempar baru ilegalargumentException ("Cache instance memerlukan id"); } this.id = id; } @Override public void clear () {redisconnection connection = null; coba {connection = jEdisconnectionFactory.getConnection (); connection.flushdb (); connection.flushall (); } catch (jEdisconnectionException e) {e.printstacktrace (); } akhirnya {if (koneksi! = null) {connection.close (); }}} @Override Public String getId () {return this.id; } @Override Obyek publik getObject (tombol objek) {Object hasil = null; Koneksi Redisconnection = NULL; coba {connection = jEdisconnectionFactory.getConnection (); RedisSerializer <BOMPERTS> Serializer = JDKSerializationRedisSerializer baru (); result = serializer.deserialize (connection.get (serializer.serialize (key))); } catch (jEdisconnectionException e) {e.printstacktrace (); } akhirnya {if (koneksi! = null) {connection.close (); }} hasil pengembalian; } @Override public readwritelock getReadWritelock () {return this.readwritelock; } @Override public int getSize () {int result = 0; Koneksi Redisconnection = NULL; coba {connection = jEdisconnectionFactory.getConnection (); hasil = integer.valueof (connection.dbSize (). ToString ()); } catch (jEdisconnectionException e) {e.printstacktrace (); } akhirnya {if (koneksi! = null) {connection.close (); }} hasil pengembalian; } @Override public void putObject (tombol objek, nilai objek) {redisconnection connection = null; coba {connection = jEdisconnectionFactory.getConnection (); RedisSerializer <BOMPERTS> SERIalizer = JDKSerializationRedisSerializer baru (); connection.set (serializer.serialize (kunci), serializer.serialize (nilai)); } catch (jEdisconnectionException e) {e.printstacktrace (); } akhirnya {if (koneksi! = null) {connection.close (); }}} @Override Obyek publik RemoveObject (Kunci objek) {redisconnection connection = null; Hasil Objek = NULL; coba {connection = jEdisconnectionFactory.getConnection (); RedisSerializer <BOMPERTS> Serializer = JDKSerializationRedisSerializer baru (); result = connection.Expire (serializer.serialize (key), 0); } catch (jEdisconnectionException e) {e.printstacktrace (); } akhirnya {if (koneksi! = null) {connection.close (); }} hasil pengembalian; } public static void setJEdisconnectionFactory (jedisconnectionFactory jedisconnectionFactory) {mybatisreditcheache.jedisconnectionFactory = jedisconnectionFactory; }}Melihat:
Seperti yang Anda lihat, kelas ini bukan kelas yang dikelola oleh mesin virtual pegas, tetapi ada properti statis jedisconnectionFactory yang membutuhkan menyuntikkan kacang pegas, yaitu kacang yang dihasilkan dalam redisconfig.
Dalam kelas normal, Spring ContextAware umumnya digunakan untuk menggunakan springcontextAware introspektif springboot.
Metode lain digunakan di sini, injeksi statis. Metode ini diimplementasikan melalui Rediscachetransfer.
4. Injeksi statis
Rediscachetransfer.java
@ComponentPublic kelas Rediscachetransfer {@Autowired public void setJEdisconnectionFactory (jedaconnectionFactory jedisconnectionFactory) {mybatisreditche.setjEdisconnectionFactory (jedaconnectionFactory); }}Anda dapat melihat bahwa Rediscachetransfer adalah kacang springboot. Saat menginisialisasi wadah pada awal penciptaan, kacang jedisconnectionfactory akan disuntikkan ke dalam parameter lewat metode setJEdisconnectionFactory.
SetjEdisconnectionFactory menetapkan properti statis dari kelas mybatisreditcache dengan memanggil metode statis.
Ini menyuntikkan jedisconnectionFactory yang dikelola oleh wadah pegas ke dalam domain statis.
Pada titik ini, kode pada dasarnya telah selesai, dan berikut ini adalah beberapa konfigurasi. Yang utama adalah (1) sakelar global; (2) sakelar ruang lingkup namespace; (3) Serialisasi contoh model.
5. Saklar global cache level 2 mybatis
Seperti yang disebutkan sebelumnya, cache level 2 default tidak dihidupkan dan perlu diatur ke true. Ini adalah saklar untuk cache Level 2 global.
Konfigurasi Global Mybatis.
<? Xml Version = "1.0" encoding = "UTF-8"?> <! Doctype Configuration Public "-// mybatis.org//dtd config 3.0 // en" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <pamperser> <pamperser> <! atau nonaktifkan cache. -> <pengaturan name = "cacheenabled" value = "true"/> </settings> </ configuration>
Pemuatan konfigurasi global di DataSource bisa seperti ini.
bean.setmapperlocations (PathMatchingResourcEpatternResolver baru (). GetResources ("ClassPath: MyBatis-Mapper/*. Xml"));
Menentukan jalur penyimpanan mapper.xml. Di bawah jalur mybatis-mapper, semua sufiks dengan .xml akan dibaca.
bean.setConfiglocation (classpathResource baru ("mybatis-config.xml"));
Jalur penyimpanan mybatis-config.xml ditentukan dan ditempatkan langsung di direktori sumber daya.
@Bean(name = "moonlightSqlSessionFactory") @Primary public SqlSessionFactory moonlightSqlSessionFactory(@Qualifier("moonlightData") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource (DataSource); bean.setmapperlocations (PathMatchingResourcEpatternResolver baru (). GetResources ("ClassPath: MyBatis-Mapper/*. Xml")); bean.setConfiglocation (classpathResource baru ("mybatis-config.xml")); return bean.getObject (); }6. Konfigurasikan namespace lingkup mapper
Seperti yang disebutkan sebelumnya, ruang lingkup cache sekunder adalah mapper namespace, sehingga konfigurasi ini perlu ditulis dalam mapper.
<mapper namespace = "com.kangaroo.studio.moonlight.dao.mapper.moonlightmapper"> <cache type = "com.kangaroo.studio.moonlight.dao.cache.mybatisrediscache"/> <resultMap id = "geofencelist" type = "com.kangaroo.studio.moonlight.dao.model.geofence"> <sonstructor> <idarg kolom = "id" javatype = "java.lang.integer" jdbctype = "integer" /> <arg column = "nama" javatype = "java.string" "" "javatype =" java.string "" java.string "" java.string " javatype = "java.lang.integer" jdbctype = "integer" /> <arg kolom = "grup" javatype = "java.lang.string" jdbctype = "varchar" /<arg column = "geo" javatype = "java.lang.string" jdbctype = "geo" javatype = "java.lang.string" jdbctype = "geo" javatype = "java.lang.string" jdbctype = "geo" javatype = "java.lang.string" jdbctype = "" "" javatype = "java.lang.string" jdbctype = "javatype =" java.Lang javatype = "java.lang.string" jdbctype = "varchar" /> <arg column = "updateTime" javatype = "java.lang.string" jdbctype = "varchar" /> < /constructor> < /resultMap> <pilih id = "querygeofence" ParameterType = "com.kangaroo.studio.moonlight.dao.model.geofenceQueryparam" resultMap = "geofencelist"> pilih <incled refid = "base_column"/> dari geofence di mana 1 = 1 <if test = "type! = nol"> dan type = #{type} </if test = "<" concat ('%', #{name}, '%') </if> <if test = "grup! = null"> dan `grup` like concat ('%', #{grup}, '%') </if> <if test =" startTime! = null "dan endTime> = #{starttime} </if> <if> {if> <if> {if> {api ="> null "> </if> </ pilih> </mapper>Melihat:
Tag cache di bawah namespace adalah konfigurasi pemuatan cache, dan penggunaan cache secara resmi diimplementasikan oleh mybatisreditcache yang baru saja kami terapkan.
<cache type = "com.kangaroo.studio.moonlight.dao.cache.mybatisreditcache"/>
Hanya pertanyaan kueri yang diimplementasikan di sini. Anda dapat menghidupkan atau mematikan cache SQL ini di tag pilih. Gunakan nilai properti usecache = true/false.
7. Mapper dan model
Model Baca dan Tulis Cache perlu diserialisasi: hanya perlu mengimplementasikan antarmuka seriazable saat kelas dinyatakan.
Kelas publik Geofence mengimplementasikan serial yang dapat diseriali {// setter dan getter alah} kelas publik geofenceParam mengimplementasikan serializable {// setter dan getter dihilangkan}Mapper masih sama seperti sebelumnya. Saat menggunakan mapper.xml, Anda hanya perlu mendefinisikan fungsi abstrak.
@Mapperpublic interface moonlightmapper {list <teofence> querygeofence (geofencequeryparam geofencequeryparam);}Pada titik ini, semua kode dan konfigurasi selesai, mari kita uji di bawah ini.
8. Uj dengan itu
Posting antarmuka seperti itu diimplementasikan dalam pengontrol.
@RequestMapping(value = "/fence/query", method = RequestMethod.POST) @ResponseBody public ResponseEntity<Response> queryFence(@RequestBody GeoFenceQueryParam geoFenceQueryParam) { try { Integer pageNum = geoFenceQueryParam.getPageNum()!=null?geoFenceQueryParam.getPageNum():1; Integer PageSize = geofenceQueryparam.getPagesize ()! = Null? Geofencequeryparam.getPageSize (): 10; PageHelper.startpage (pagenum, halaman); Daftar <Geofence> Daftar = MoonlightMapper.QueryGeofence (GeofenceQueryParam); mengembalikan responEntity baru <> (respons baru (resultCode.success, "kueri kesuksesan geofence", daftar), httpstatus.ok); } catch (exception e) {logger.error ("query geofence gagal", e); Return New ResponseEntity <> (respons baru (resultCode.Exception, "Query geofence faging", null), httpstatus.internal_server_error); }Gunakan ikal untuk mengirim permintaan, perhatikan
1) -H -Tipe Konten: Metode Aplikasi/JSON
2) -D - Berikut ini adalah paket parameter dalam format JSON
Curl -h "tipe konten: aplikasi/json" -xpost http: //. . . /moonlight/pagar/kueri -d '{"name": "test", "group": "test", "type": 1, "starttime": "2017-12-06 00:00:00", "endtime": "2017-12-06 16:00:00", "pagenum": 1, "halaman": 8Diminta tiga kali, log dicetak sebagai berikut
Seperti yang Anda lihat, hanya pertama kali kueri Template SQL dieksekusi, dan cache dipukul.
Di lingkungan pengujian kami, karena jumlah data yang relatif kecil, optimalisasi cache kecepatan kueri tidak jelas. Saya tidak akan menjelaskan banyak hal di sini.