Heim > Java > javaLernprogramm > Hauptteil

Detaillierte Erläuterung des MyBatis-Abfragecaches in Java

怪我咯
Freigeben: 2017-06-30 10:57:30
Original
1445 Leute haben es durchsucht

Die Verwendung des Abfragecaches dient hauptsächlich der Verbesserung der Abfragezugriffsgeschwindigkeit. In diesem Artikel wird hauptsächlich der MyBatis-Abfragecache vorgestellt. Freunde, die ihn benötigen, können sich auf die Verwendung des

Abfragecaches beziehen, hauptsächlich um die Abfragezugriffsgeschwindigkeit zu verbessern. Vereinfachen Sie den wiederholten Abfragevorgang des Benutzers für dieselben Daten, anstatt jedes Mal die Ergebnisdaten aus der Datenbankabfrage abzurufen, und verbessern Sie so die Zugriffsgeschwindigkeit.

Der Abfrage-Caching-Mechanismus von MyBatis kann je nach Umfang des Cache-Bereichs (Lebenszyklus) in zwei Typen unterteilt werden: Cache der ersten Ebene und Cache der zweiten Ebene

1. Abfrage-Cache der ersten Ebene

Der MyBatis-Cache der ersten Ebene ist ein lokaler HashMap-Cache, der auf dem org.apache.ibatis.cache.impl.PerpetualCache basiert Klasse und ihr Gültigkeitsbereich ist Sqlsession. Führen Sie dieselbe SQL-Anweisung zweimal in derselben SQL-Sitzung aus. Nach der ersten Ausführung werden die Abfrageergebnisse in den Cache geschrieben. Beim zweiten Mal werden die Daten direkt aus dem Cache abgerufen, ohne die Datenbank abzufragen, wodurch die Abfrageeffizienz verbessert wird.

Wenn eine SQL-Sitzung endet, ist der Cache der ersten Ebene in der SQL-Sitzung nicht mehr vorhanden. Der First-Level-Cache von MyBatis ist standardmäßig aktiviert und kann nicht deaktiviert werden.

1. Nachweis der Existenz des First-Level-Cache

Testklasse:

//证明一级缓存的存在
@Test
public void test01(){
 //第一次查询
 Student student = dao.selectStudentById(2);
 System.out.println(student);
 //第二次查询
 Student student2 = dao.selectStudentById(2);
 System.out.println(student2);  
}
Nach dem Login kopieren

Mapper :

<mapper namespace="com.hcx.dao.IStudentDao">  
  <select id=selectStudentById resultType="com.hcx.beans.Student">
   select * from student where id=#{id}
  </select>
</mapper>
Nach dem Login kopieren


Konsole:

Nach der Ausführung wurde festgestellt, dass nur eine Abfrage aus der Datenbank ausgeführt wurde und das zweite Ergebnis direkt ausgegeben wurde von. Beachten Sie, dass beim zweiten Mal aus dem Sqlsession-Cache gelesen wird.

2. Die Grundlage für das Lesen von Daten aus dem Cache ist die SQL-ID

Der Cache der ersten Ebene speichert denselben SQL-Code Zuordnungs-ID Die Abfrageergebnisse und nicht die Abfrageergebnisse derselben SQL-Anweisung. Da der interne Abfragecache von MyBatis unabhängig davon, ob es sich um eine Abfrage der ersten oder zweiten Ebene handelt, die unterste Ebene mithilfe einer Hashmap implementiert wird: Der Schlüssel ist der id-bezogene Inhalt von SQL und der Wert ist das Ergebnis der Abfrage aus der Datenbank.

Mapper:


<mapper namespace="com.hcx.dao.IStudentDao">
  <select id=selectStudentById resultType="com.hcx.beans.Student">
   select * from student where id=#{id}
  </select>
  <select id="selectStudnetById2" resultType="com.hcx.beans.Student">
   select id,name,age,score,birthday from student where id=#{id}
  </select>
</mapper>
Nach dem Login kopieren

Dao-Schnittstelle:

public interface IStudentDao {  
 Student selectStudentById(int id);
 Student selectStudentById2(int id); 
}
Nach dem Login kopieren

Testklasse:

//证明从一级缓存中读取数据的依据:
//MyBatis:sql的id+sql语句
//hibernate:查询结果对象的id
@Test
public void test02(){
 Student student = dao.selectStudentById(2);
 System.out.println(student);

 Student student2 = dao.selectStudentById2(2);
 System.out.println(student2);  
}
Nach dem Login kopieren

Konsole:

Überprüfen Sie die Konsole und stellen Sie fest, dass die Ergebnisse der zweiten Abfrage genau mit denen der ersten übereinstimmen, die zweite Abfrage jedoch keine Daten aus dem Cache liest, sondern direkt aus der Datenbank. Dies liegt daran, dass die Grundlage für das Lesen von Daten aus dem Cache die Zuordnungs-ID der Abfrage-SQL und nicht das Abfrageergebnis ist.

3. Die Auswirkungen von Ergänzungen, Löschungen und Änderungen auf den Abfragecache der ersten Ebene

Ergänzungen, Löschungen und Änderungen, Unabhängig davon, ob Sqlsession.commit( ), den Abfragecache der ersten Ebene löscht, sodass die Abfrage erneut aus der Datenbank ausgewählt werden kann.

Testklasse:

@Test
public void test03(){
 Student student = dao.selectStudentById(2);
 System.out.println(student);
 //增删改操作都会清空一级缓存,无论是否提交
 dao.insertStudent(new Student("赵六",26,96.6));
 Student student2 = dao.selectStudentById(2);
 System.out.println(student2);  
}
Nach dem Login kopieren

Konsole:


2. Eingebaute Sekundärseite Level-Abfrage-Cache

Der Umfang des MyBatis-Abfrage-Cache ist entsprechend dem Namespace des Zuordnungsdatei-Mappers unterteilt. Die Mapper-Abfragedaten desselben Namespace werden im selben Cache-Bereich gespeichert. Daten in verschiedenen Namespaces stören sich nicht gegenseitig.

Sowohl der First-Level-Cache als auch der Second-Level-Cache werden je nach Namespace getrennt gespeichert. Der Unterschied zwischen dem Cache der ersten und der zweiten Ebene besteht jedoch darin, dass nach dem Schließen der SQL-Sitzung die Daten in der SQL-Sitzung nicht mehr vorhanden sind, dh der Cache der ersten Ebene ist nicht mehr vorhanden. Der Lebenszyklus des Second-Level-Cache wird mit der gesamten Anwendung synchronisiert, unabhängig davon, ob die SQL-Sitzung geschlossen ist.

Der Zweck der Verwendung des Second-Level-Cache besteht nicht darin, Daten zu teilen, da MyBatis Daten aus dem Cache basierend auf der SQL-ID und nicht auf dem abgefragten Objekt liest. Daher sind die Daten im Cache der zweiten Ebene nicht für die gemeinsame Nutzung mehrerer Abfragen vorgesehen (solange das Objekt in den Abfrageergebnissen aller Abfragen vorhanden ist, wird es direkt aus dem Cache gelesen. Dies ist die gemeinsame Nutzung von Daten. Das Der Cache im Ruhezustand dient der gemeinsamen Nutzung, MyBatis jedoch nicht), sondern dient dazu, die Speicherzeit der Abfrageergebnisse zu verlängern und die Systemleistung zu verbessern.

1. Cache-Nutzung der zweiten Ebene

Die Verwendung des Caches der zweiten Ebene erfordert nur zwei Schritte:

Serialisierte Entitäten

Hinzufügen der -Tag in der Mapper-Zuordnungsdatei

1. Die Entitätsserialisierung

erfordert, dass die am Abfrageergebnis beteiligte Entitätsklasse java.io implementiert. Serialisierbare Schnittstelle. Wenn die Entitätsklasse eine übergeordnete Klasse oder Domänenattribute hat, müssen die übergeordnete Klasse und die Domänenattributklasse auch die Serialisierungsschnittstelle implementieren.

public class Student implements Serializable{
 private Integer id;
 private String name;
 private int age;
 private double score;
}
Nach dem Login kopieren

2. Fügen Sie das -Tag in der Mapper-Zuordnungsdatei hinzu.

Fügen Sie das -Tag hinzu Datei Sub-tag

<mapper namespace="com.hcx.dao.IStudentDao">
 <cache/>
  <select id=selectStudentById resultType="com.hcx.beans.Student">
   select * from student where id=#{id}
  </select>
</mapper>
Nach dem Login kopieren

3. Cache-Konfiguration der zweiten Ebene

Fügen Sie einige verwandte Attributeinstellungen zum

<cache eviction="IFIO" flushInterval="10800000"
  readOnly="true" size="512"/>
Nach dem Login kopieren

eviction:逐出策略。当二级缓存中的对象达到最大值时,就需要通过逐出策略将缓存中的对象移出缓存。默认为LRU。常用的策略有FIFO和LRU

flushInterval:刷新缓存的时间间隔,单位毫秒。这里的刷新缓存即清空缓存。一般不指定,即当执行增删改时刷新缓存。

readOnly:设置缓存中数据是否只读。只读的缓存会给所有调用者返回缓存对象的相同实例,因此这些对象不能被修改,这提供了很重要的性能优势。但读写的缓存会返回缓存对象的拷贝。这会慢一些,但是安全,因此默认是false。
size:二级缓存中可以存放的最多对象个数。默认为1024个。

2.二级缓存的存在性证明

对于映射文件中的同一个查询,肯定是同一个namespace中的查询。在一次查询后,将Sqlsession关闭,再进行一次相同查询,发现并没有到DB中进行select查询,说明二级缓存是存在的。

//证明二级缓存的存在
@Test
public void test01(){
 //第一次查询
 Student student = dao.selectStudentById(2);
 System.out.println(student);
 sqlSession.close();
 sqlSession = MyBatisUtils.getSqlSession();
 dao = sqlSession.getMapper(IStudentDao.class);
 //第二次查询
 Student student2 = dao.selectStudentById(2);
 System.out.println(student2);  
}
Nach dem Login kopieren


查看控制台:

Cache Hit Ratio表示缓存命中率。开启二级缓存后,每执行一次查询,系统都会计算一次二级缓存的命中率。第一次查询也是先从缓存中查询,只不过缓存中一定是没有的。所以会再从DB中查询。由于二级缓存中不存在该数据,所以命中率为0.但第二次查询是从二级缓存中读取的,所以这一次的命中率为1/2=0.5。当然,若有第三次查询,则命中率为1/3=0.66

3.增删改对二级缓存的影响

增删改操作,无论是否进行提交sqlSession.commit(),均会清空一级、二级缓存,使查询再次从DB中select。

测试类:

@Testpublic void test02(){
 //第一次查询
 Student student = dao.selectStudentById(2);
 System.out.println(student);
 sqlSession.close();
 sqlSession = MyBatisUtils.getSqlSession();
 dao = sqlSession.getMapper(IStudentDao.class);
 //插入
 dao.insertStudent(new Student("",0,0));
 //第二次查询
 Student student2 = dao.selectStudentById(2);
 System.out.println(student2);  
}
Nach dem Login kopieren

控制台:

注意,在第二次查询时的缓存命中率为0.5,但还是从DB中查询了。说明在缓存中与该查询相对应的key是存在的,但其value被清空。而value被清空的原因是前面执行了对DB的增删改操作,所以不会从缓存中直接将null值返回,而是从DB中进行查询。

说明:

二级缓存的清空,实质上是对所查找key对应的value置为null,而非将对,即entry对象删除。

从DB中进行select查询的条件是:缓存中根本不存在这个key或者缓存中存在该key所对应的entry对象,但value为null。

设置增删改操作不刷新二级缓存:

若要使某个增、删或改操作不清空二级缓存,则需要在其中添加属性flushCache="false",默认为true。

<insert id="insertStudent" flushCache="false">
  insert into student(name,age,score) values(#{name},#{age},#{score})
 </insert>
Nach dem Login kopieren

4.二级缓存的关闭

二级缓存默认为开启状态。若要将其关闭,则需要进行相关设置。
根据关闭的范围大小,可以分为全局关闭和局部关闭

1.全局关闭(在配置文件中设置)

全局关闭是指整个应用的二级缓存全部关闭,所有查询均不使用二级缓存。全局开关设置在主配置文件的全局设置中,该属性为cacheEnabled,设置为false,则关闭;设置为true,则开启,默认值为true。即二级缓存默认是开启的。

<!-- 关闭二级缓存 -->
<settings>
 <setting name="cacheEnabled" value="false"/>
</settings>
Nach dem Login kopieren

2.局部关闭(在映射文件的每个select中设置)

局部关闭指整个应用的二级缓存是开启的,但只是针对某个标签的二级缓存。

在该要关闭二级缓存的查询的二级缓存默认是开启的。

<!--useCache="false"对当前sql的二级缓存的局部关闭 -->
 <select id=selectStudentById useCache="false" resultType="com.hcx.beans.Student">
  select * from student where id=#{id}
 </select>
Nach dem Login kopieren

5.二级缓存的使用原则

1.只能在一个命名空间下使用二级缓存

由于二级缓存中的数据是基于namespace的,即不同namespace中的数据互不干扰。在多个namespace中若均存在对同一个表的操作,那么这多个namespace中的数据可能就会出现不一致现象。

2.在单表上使用二级缓存

如果一个表与其它表有关联关系,那么久非常有可能存在多个namespace对同一数据的操作。而不同namespace中的数据互补干扰,所以就有可能出现多个namespace中的数据不一致现象。

3.查询多于修改时使用二级缓存

在查询操作远远多于增删改操作的情况下可以使用二级缓存。因为任何增删改操作都将刷新二级缓存,对二级缓存的频繁刷新将降低系统性能。

三、ehcache二级查询缓存

MyBatis允许使用第三方缓存产品。ehCache就是其中一种。

注意:使用ehcache二级缓存,实体类无需实现序列化接口。

1.导入jar包

2.添加ehcache.xml

解压ehcache的核心jar包ehcache-core-2.6.8.jar,将其中的一个配置文件ehcache-failsafe.xml直接放到项目的src目录下,并更名为ehcache.xml

(1)标签

指定一个文件目录,当内存空间不够,需要将二级缓存中数据写到硬盘上时,会写到这个指定目录中。其值一般为java.io.tmpdir,表示当前系统的默认文件临时目录。

当前文件系统的默认文件临时目录,可以通过System.property()方法查看:

@Test
public void test(){
 String path = System.getProperty("java.io.tmpdir");
 System.out.println(path);
}
Nach dem Login kopieren

(2)标签

3.启用ehcache缓存机制

在映射文件的mapper中的中通过type指定缓存机制为Ehcache缓存。默认为MyBatis内置的二级缓存org.apache.ibatis.cache.impl.PerpetualCache。

<mapper namespace="com.hcx.dao.IStudentDao">
 <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
  <select id=selectStudentById resultType="com.hcx.beans.Student">
   select * from student where id=#{id}
  </select>
</mapper>
Nach dem Login kopieren

4.ehcache在不同mapper中的个性化设置

在ehcache.xml中设置的属性值,会对该项目中所有使用ehcache缓存机制的缓存区域起作用。一个项目中可以有多个mapper,不同的mapper有不同的缓存区域。对于不同缓存区域也可进行专门针对于当前区域的个性设置,可通过指定不同mapper的属性值来设置。

属性值的优先级高于ehcache.xml中的属性值。

<mapper namespace="com.hcx.dao.IStudentDao">
 <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
   <property name="maxElementsInMemory" value="5000"/>
   <property name="timeToIdleSeconds" value="240"/>
 </cache>
</mapper>
Nach dem Login kopieren

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des MyBatis-Abfragecaches in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!