1. 程式人生 > >hibernate筆記(四)

hibernate筆記(四)

元素 有用 tro getc 如何 cond 屬性 war factor

目標:

一、hibernate查詢

二、hibernate對連接池的支持

三、二級緩存

一、hibernate查詢

1. 查詢概述

1) Get/load主鍵查詢

2) 對象導航查詢

3) HQL查詢, Hibernate Query language hibernate 提供的面向對象的查詢語言。

4) Criteria 查詢, 完全面向對象的查詢(Query By Criteria ,QBC

5) SQLQuery, 本地SQL查詢

缺點:不能跨數據庫平臺: 如果改了數據庫,sql語句有可能要改

使用場景: 對於復雜sqlhql實現不了的情況,可以使用本地

sql查詢。

HQL查詢

public class App {

private static SessionFactory sf;

static {

sf = new Configuration()

.configure()

.addClass(Dept.class)

.addClass(Employee.class) // 測試時候使用

.buildSessionFactory();

}

/*

* 1) Get/load主鍵查詢

2) 對象導航查詢

3) HQL查詢, Hibernate Query language hibernate 提供的面向對象的查詢語言。

4) Criteria 查詢, 完全面向對象的查詢(Query By Criteria ,QBC

5) SQLQuery, 本地SQL查詢

*/

@Test

public void all() {

Session session = sf.openSession();

session.beginTransaction();

//1) 主鍵查詢

// Dept dept = (Dept) session.get(Dept.class, 12);

// Dept dept = (Dept) session.load(Dept.class, 12);

//2) 對象導航查詢

// Dept

dept = (Dept) session.get(Dept.class, 12);

// System.out.println(dept.getDeptName());

// System.out.println(dept.getEmps());

// 3) HQL查詢

// 註意:使用hql查詢的時候 auto-import="true" 要設置true

// 如果是false,寫hql的時候,要指定類的全名

// Query q = session.createQuery("from Dept");

// System.out.println(q.list());

// a. 查詢全部列

// Query q = session.createQuery("from Dept"); //OK

// Query q = session.createQuery("select * from Dept"); //NOK, 錯誤,不支持*

// Query q = session.createQuery("select d from Dept d"); // OK

// System.out.println(q.list());

// b. 查詢指定的列 【返回對象數據Object[]

// Query q = session.createQuery("select d.deptId,d.deptName from Dept d");

// System.out.println(q.list());

// c. 查詢指定的列, 自動封裝為對象 【必須要提供帶參數構造器】

// Query q = session.createQuery("select new Dept(d.deptId,d.deptName) from Dept d");

// System.out.println(q.list());

// d. 條件查詢: 一個條件/多個條件and or/between and/模糊查詢

// 條件查詢: 占位符

// Query q = session.createQuery("from Dept d where deptName=?");

// q.setString(0, "財務部");

// q.setParameter(0, "財務部");

// System.out.println(q.list());

// 條件查詢: 命名參數

// Query q = session.createQuery("from Dept d where deptId=:myId or deptName=:name");

// q.setParameter("myId", 12);

// q.setParameter("name", "財務部");

// System.out.println(q.list());

// 範圍

// Query q = session.createQuery("from Dept d where deptId between ? and ?");

// q.setParameter(0, 1);

// q.setParameter(1, 20);

// System.out.println(q.list());

// 模糊

// Query q = session.createQuery("from Dept d where deptName like ?");

// q.setString(0, "%%");

// System.out.println(q.list());

// e. 聚合函數統計

// Query q = session.createQuery("select count(*) from Dept");

// Long num = (Long) q.uniqueResult();

// System.out.println(num);

// f. 分組查詢

//-- 統計t_employee表中,每個部門的人數

//數據庫寫法:SELECT dept_id,COUNT(*) FROM t_employee GROUP BY dept_id;

// HQL寫法

// Query q = session.createQuery("select e.dept, count(*) from Employee e group by e.dept");

// System.out.println(q.list());

session.getTransaction().commit();

session.close();

}

// g. 連接查詢

@Test

public void join() {

Session session = sf.openSession();

session.beginTransaction();

//1) 內連接 【映射已經配置好了關系,關聯的時候,直接寫對象的屬性即可】

// Query q = session.createQuery("from Dept d inner join d.emps");

//2) 左外連接

// Query q = session.createQuery("from Dept d left join d.emps");

//3) 右外連接

Query q = session.createQuery("from Employee e right join e.dept");

q.list();

session.getTransaction().commit();

session.close();

}

// g. 連接查詢 - 迫切連接

@Test

public void fetch() {

Session session = sf.openSession();

session.beginTransaction();

//1) 迫切內連接 【使用fetch, 會把右表的數據,填充到左表對象中!】

// Query q = session.createQuery("from Dept d inner join fetch d.emps");

// q.list();

//2) 迫切左外連接

Query q = session.createQuery("from Dept d left join fetch d.emps");

q.list();

session.getTransaction().commit();

session.close();

}

// HQL查詢優化

@Test

public void hql_other() {

Session session = sf.openSession();

session.beginTransaction();

// HQL寫死

// Query q = session.createQuery("from Dept d where deptId < 10 ");

// HQL 放到映射文件中

Query q = session.getNamedQuery("getAllDept");

q.setParameter(0, 10);

System.out.println(q.list());

session.getTransaction().commit();

session.close();

}

}

Criteria 查詢

//4) Criteria 查詢,

@Test

public void criteria() {

Session session = sf.openSession();

session.beginTransaction();

Criteria criteria = session.createCriteria(Employee.class);

// 構建條件

criteria.add(Restrictions.eq("empId", 12));

// criteria.add(Restrictions.idEq(12)); // 主鍵查詢

System.out.println(criteria.list());

session.getTransaction().commit();

session.close();

}

SQLQuery, 本地SQL查詢

// 5) SQLQuery, 本地SQL查詢

// 不能跨數據庫平臺: 如果該了數據庫,sql語句有肯能要改。

@Test

public void sql() {

Session session = sf.openSession();

session.beginTransaction();

SQLQuery q = session.createSQLQuery("SELECT * FROM t_Dept limit 5;")

.addEntity(Dept.class); // 也可以自動封裝

System.out.println(q.list());

session.getTransaction().commit();

session.close();

}

2. 分頁查詢

分頁SQL

先查詢總記錄數,再分頁查詢。

// 分頁查詢

@Test

public void all() {

Session session = sf.openSession();

session.beginTransaction();

Query q = session.createQuery("from Employee");

// 總記錄數

ScrollableResults scroll = q.scroll(); // 得到滾動的結果集

scroll.last(); // 滾動到最後一行

int totalCount = scroll.getRowNumber() + 1;// 得到滾到的記錄數,即總記錄數

// 設置分頁參數

q.setFirstResult(0);

q.setMaxResults(3);

// 查詢

System.out.println(q.list());

System.out.println("總記錄數:" + totalCount);

session.getTransaction().commit();

session.close();

}

二、hibernate對連接池的支持

連接池,

作用: 管理連接;提升連接的利用效率!

常用的連接池: C3P0連接池

Hibernate 自帶的也有一個連接池,且對C3P0連接池也有支持!

Hbm 自帶連接池:

只維護一個連接,比較簡陋。

可以查看hibernate.properties文件查看連接池詳細配置:

#################################

### Hibernate Connection Pool ###

#################################

hibernate.connection.pool_size 1 【Hbm 自帶連接池: 只有一個連接

###########################

### C3P0 Connection Pool### 【HbmC3P0連接池支持】

###########################

#hibernate.c3p0.max_size 2 最大連接數

#hibernate.c3p0.min_size 2 最小連接數

#hibernate.c3p0.timeout 5000 超時時間

#hibernate.c3p0.max_statements 100 最大執行的命令的個數

#hibernate.c3p0.idle_test_period 3000 空閑測試時間

#hibernate.c3p0.acquire_increment 2 連接不夠用的時候, 每次增加的連接數

#hibernate.c3p0.validate false

HbmC3P0連接池支持, 核心類】

告訴hib使用的是哪一個連接池技術。

#hibernate.connection.provider_class org.hibernate.connection.C3P0ConnectionProvider

Hibernate.cfg.xml 中增加連接池相關配置:

<!-- 【連接池配置】 -->

<!-- 配置連接驅動管理類 -->

<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>

<!-- 配置連接池參數信息 -->

<property name="hibernate.c3p0.min_size">2</property>

<property name="hibernate.c3p0.max_size">4</property>

<property name="hibernate.c3p0.timeout">5000</property>

<property name="hibernate.c3p0.max_statements">10</property>

<property name="hibernate.c3p0.idle_test_period">30000</property>

<property name="hibernate.c3p0.acquire_increment">2</property>

三、二級緩存

Hibernate提供的緩存

有一級緩存、二級緩存。 目的是為了減少對數據庫的訪問次數,提升程序執行效率!

一級緩存:

基於Session的緩存,緩存內容只在當前session有效,session關閉,緩存內容失效!

特點:

作用範圍較小! 緩存的事件短。

緩存效果不明顯。

概述

二級緩存:

Hibernate提供了基於應用程序級別的緩存, 可以跨多個session,即不同的session都可以訪問緩存數據。 這個換存也叫二級緩存。

Hibernate提供的二級緩存有默認的實現,且是一種可插配的緩存框架!如果用戶想用二級緩存,只需要在hibernate.cfg.xml中配置即可; 不想用,直接移除,不影響代碼。

如果用戶覺得hibernate提供的框架框架不好用,自己可以換其他的緩存框架或自己實現緩存框架都可以。

使用二級緩存

查看hibernate.properties配置文件,二級緩存如何配置?

##########################

### Second-level Cache ###

##########################

#hibernate.cache.use_second_level_cache false【二級緩存默認不開啟,需要手動開啟】

#hibernate.cache.use_query_cache true 【開啟查詢緩存】

## choose a cache implementation 【二級緩存框架的實現】

#hibernate.cache.provider_class org.hibernate.cache.EhCacheProvider

#hibernate.cache.provider_class org.hibernate.cache.EmptyCacheProvider

hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider 默認實現

#hibernate.cache.provider_class org.hibernate.cache.TreeCacheProvider

#hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider

#hibernate.cache.provider_class org.hibernate.cache.SwarmCacheProvider

二級緩存,使用步驟

1) 開啟二級緩存

2)指定緩存框架

3)指定那些類加入二級緩存

4)測試

測試二級緩存!

緩存策略

<class-cache usage="read-only"/> 放入二級緩存的對象,只讀;

<class-cache usage="nonstrict-read-write"/> 非嚴格的讀寫

<class-cache usage="read-write"/> 讀寫; 放入二級緩存的對象可以讀、寫;

<class-cache usage="transactional"/> (基於事務的策略)

集合緩存

<!-- 集合緩存[集合緩存的元素對象,也加加入二級緩存] -->

<collection-cache

usage="read-write" collection="cn.itcast.b_second_cache.Dept.emps"/>

查詢緩存

list() 默認情況只會放入緩存,不會從一級緩存中取!

使用查詢緩存,可以讓list()查詢從二級緩存中取!

完整案例:

Hibernate.cfg.xml

<!--****************** 【二級緩存配置】****************** -->

<!-- a. 開啟二級緩存 -->

<property name="hibernate.cache.use_second_level_cache">true</property>

<!-- b. 指定使用哪一個緩存框架(默認提供的) -->

<property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>

<!-- 開啟查詢緩存 -->

<property name="hibernate.cache.use_query_cache">true</property>

<!-- c. 指定哪一些類,需要加入二級緩存 -->

<class-cache usage="read-write" class="cn.itcast.b_second_cache.Dept"/>

<class-cache usage="read-only" class="cn.itcast.b_second_cache.Employee"/>

<!-- 集合緩存[集合緩存的元素對象,也加加入二級緩存] -->

<collection-cache usage="read-write" collection="cn.itcast.b_second_cache.Dept.emps"/>

App 測試類

public class App {

private static SessionFactory sf;

static {

sf = new Configuration()

.configure()

.addClass(Dept.class)

.addClass(Employee.class) // 測試時候使用

.buildSessionFactory();

}

// 1. 測試二級緩存的使用

// 沒有/有用 二級緩存

@Test

public void testCache() {

Session session1 = sf.openSession();

session1.beginTransaction();

// a. 查詢一次

Dept dept = (Dept) session1.get(Dept.class, 10);

dept.getEmps().size();// 集合

session1.getTransaction().commit();

session1.close();

System.out.println("------");

// 第二個session

Session session2 = sf.openSession();

session2.beginTransaction();

// a. 查詢一次

dept = (Dept) session2.get(Dept.class, 10); // 二級緩存配置好; 這裏不查詢數據庫

dept.getEmps().size();

session2.getTransaction().commit();

session2.close();

}

@Test

public void listCache() {

Session session1 = sf.openSession();

session1.beginTransaction();

// HQL查詢 【setCacheable 指定從二級緩存找,或者是放入二級緩存】

Query q = session1.createQuery("from Dept").setCacheable(true);

System.out.println(q.list());

session1.getTransaction().commit();

session1.close();

Session session2 = sf.openSession();

session2.beginTransaction();

q = session2.createQuery("from Dept").setCacheable(true);

System.out.println(q.list()); // 不查詢數據庫: 需要開啟查詢緩存

session2.getTransaction().commit();

session2.close();

}

}

四、項目中session的管理方式

Session的創建方式:

@Test

public void testSession() throws Exception {

//openSession: 創建Session, 每次都會創建一個新的session

Session session1 = sf.openSession();

Session session2 = sf.openSession();

System.out.println(session1 == session2);

session1.close();

session2.close();

//getCurrentSession 創建或者獲取session

// 線程的方式創建session

// 一定要配置:<property name="hibernate.current_session_context_class">thread</property>

Session session3 = sf.getCurrentSession();// 創建session,綁定到線程

Session session4 = sf.getCurrentSession();// 從當前訪問線程獲取session

System.out.println(session3 == session4);

// 關閉 【以線程方式創建的session,可以不用關閉; 線程結束session自動關閉】

//session3.close();

//session4.close(); 報錯,因為同一個session已經關閉了!

}

hibernate筆記(四)