Hibernate學習之一級緩存
? 版權聲明:本文為博主原創文章,轉載請註明出處
Hibernate緩存:
- 緩存是為了降低應用程序對物理數據源訪問的頻次,從而提供應用程序的運行性能的一種策略
- Hibernate緩存是提升和優化Hibernate執行效率的重要手段
工作原理:
1. 應用程序讀取緩存數據
2. 緩存命中則直接返回數據
3. 緩存未命中則去數據庫中查詢數據,然後將數據放入緩存中並返回數據
一級緩存:
1. Hibernate一級緩存又稱為“Session緩存”、“會話級緩存”
2. 通過Session從數據庫查詢實體時會把實體從內存中取出來,下一查詢統一實體時不再從數據庫獲取,而是從內存中獲取
3. 一級緩存的聲明周期和Session相同;Session銷毀,它也銷毀
4. 一級緩存的數據可使用範圍在當前會話之內
API:
1. 一級緩存無法取消,用兩個方法管理
- evict():用於將對象從Session的一級緩存中清除
- clear():用於將一級緩存中的所有對象清除
2. 相關方法
- query.list()
- query.iterate()
實例:
1.項目結構
2.pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.struts</groupId> <artifactId>Hibernate-PrimaryBuffer</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <hibernate.version>5.1.7.Final</hibernate.version> </properties> <dependencies> <!-- Junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- Hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <!-- MySQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.42</version> </dependency> </dependencies> </project>
3.Student.java
package org.hibernate.model; import java.util.Date; /** * 學生實體類 * */ public class Student { private long id;// 學號 private String username;// 姓名 private Date birthday;// 生日 private String sex;// 性別 public Student() { } public Student(long id, String username, Date birthday, String sex) { this.id = id; this.username = username; this.birthday = birthday; this.sex = sex; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }
4.Student.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" > <hibernate-mapping> <class name="org.hibernate.model.Student" table="STUDENT"> <id name="id" type="java.lang.Long"> <column name="ID"/> <generator class="assigned"/> </id> <property name="username" type="java.lang.String"> <column name="USERNAME"/> </property> <property name="birthday" type="date"> <column name="BIRTHDAY"/> </property> <property name="sex" type="java.lang.String"> <column name="SEX"/> </property> </class> </hibernate-mapping>
5.hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <!-- 配置SessionFactory --> <session-factory> <!-- 配置數據庫連接信息 --> <property name="connection.username">root</property> <property name="connection.password">***</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url"> jdbc:mysql:///hibernate?useSSL=true&characterEncoding=UTF-8 </property> <!-- 常用設置 --> <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property><!-- 方言 --> <property name="show_sql">true</property><!-- 是否展示SQL --> <property name="format_sql">false</property><!-- 格式化SQL --> <property name="hbm2ddl.auto">update</property><!-- 自動創建表結構 --> <!-- 引入映射文件 --> <mapping resource="hbm/Student.hbm.xml"/> </session-factory> </hibernate-configuration>
6.TestPrimartBuffer.java
package org.hibernate.test; import java.util.Date; import java.util.Iterator; import java.util.List; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.model.Student; import org.junit.After; import org.junit.Before; import org.junit.Test; public class TestPrimaryBuffer { private SessionFactory sessionFactory; private Session session; private Transaction transaction; @Before public void before() { sessionFactory = new Configuration().configure().buildSessionFactory();// 創建會話工廠對象 session = sessionFactory.openSession();// 創建會話 transaction = session.beginTransaction();// 開始事務 } @After public void after() { transaction.commit();// 提交事務 session.close();// 關閉會話 sessionFactory.close();// 關閉會話工廠 } /** * 初始化數據庫 */ @Test public void init() { Student student = new Student(1, "張三", new Date(), "男"); session.save(student); student = new Student(2, "李四", new Date(), "男"); session.save(student); student = new Student(3, "王五", new Date(), "男"); session.save(student); } /** * 同一個session */ @Test public void testSameSession() { Student student = session.get(Student.class, 1L); System.out.println(student.getUsername()); student = session.get(Student.class, 1L); System.out.println(student.getUsername()); } /** * 不同session */ @Test public void testDiffSession() { Student student = session.get(Student.class, 1L); System.out.println(student.getUsername()); session = sessionFactory.openSession(); student = session.get(Student.class, 1L); System.out.println(student.getUsername()); } /** * Evict,同一個session */ @Test public void testEvict() { Student student = session.get(Student.class, 1L); System.out.println(student.getUsername()); session.evict(student); student = session.get(Student.class, 1L); System.out.println(student.getUsername()); } /** * Clear,同一個session */ @Test public void testClear() { Student student = session.get(Student.class, 1L); System.out.println(student.getUsername()); session.clear(); student = session.get(Student.class, 1L); System.out.println(student.getUsername()); } /** * Query */ @Test @SuppressWarnings("unchecked") public void testQuery() { Query query = session.createQuery("from Student"); List<Student> list = query.list(); for (Student s: list) { System.out.println(s.getUsername()); } System.out.println(); list = query.list(); for (Student s: list) { System.out.println(s.getUsername()); } } /** * Interate */ @Test @SuppressWarnings("unchecked") public void testIterate() { Query query = session.createQuery("from Student"); List<Student> list = query.list(); for (Student s: list) { System.out.println(s.getUsername()); } System.out.println(); Iterator<?> iterator = query.iterate(); while (iterator.hasNext()) { Student s = (Student) iterator.next(); System.out.println(s.getUsername()); } } /** * Interate2 */ @Test public void testIterate2() { Query query = session.createQuery("from Student"); Iterator<?> iterator = query.iterate(); while (iterator.hasNext()) { Student s = (Student) iterator.next(); System.out.println(s.getUsername()); } } }
7.效果預覽(首先執行init()方法進行數據庫表的初始化)
7.1 執行testSameSession()方法
說明:同一個Session中查詢同一對象使用緩存,執行一次查詢操作
7.2 執行testDiffSession()方法
說明:不同Session中查詢同一對象沒有使用緩存,執行多次查詢操作
7.3 執行testEvict()方法
說明:同一Session中,由於使用evict()方法從緩存中清除了Student對象,因此也需查詢多次
7.4 執行testClear()方法
說明:同一Session中,由於使用clear()方法清除了緩存中的所有對象,因此也需查詢多次
7.5 執行testQuery()方法
說明:在同一Session中查詢同一對象,依然執行了兩次SQL,說明query.list()方法不使用緩存
7.6 執行testIterate()方法
7.7 執行testIterate2()方法
說明:從7.6和7.7的結果可以得出,query.iterate()方法使用緩存,但是iterate()方法先從數據中查詢所有的id,然後通過id去緩存中查找;若查找失敗,則根據id去數據庫查詢詳細信息
8.總結:
1. 同一個session對象,多次查詢同一個對象,因為緩存只會執行一次查詢操作,查詢效率較快
2. 不同Session對象,多次查詢同一對象,不存在緩存會多次執行查詢操作,查詢效率較慢
3. query.list()雖然在同一個Session中,但是不會使用緩存
4. query.iterate()在同一個Session中會使用緩存。但是iterate()會先從數據庫中查詢所有的id,然後通過id去緩存中查詢對應對象;
若緩存中不存在該id對應的對象,則會根據id去數據庫中查詢
參考:http://www.imooc.com/video/9016
Hibernate學習之一級緩存