非本人總結的筆記,抄點筆記復習復習。感謝傳智博客及黑馬程序猿
記筆記啊記筆記
Hibernate的查詢操作
Hibernate的查詢方式概述
(1)導航對象圖檢索方式
? 根據已經加載的對象導航到其他對象
以用戶和訂單為例:查詢出一個用戶,查詢這個用戶的所有訂單,直接得到用戶的訂單集合
(2)OID檢索方式
? 按照對象的OID來檢索對象
User user = (User) session.get(User.class, 2);
(3)HQL檢索方式
? 使用面向對象的HQL查詢語言
(4)QBC檢索方式
? 使用QBC(Query By Criterial)API來檢索對象,這種API封裝了基于字符串形式的查詢語言,提供了更加面向對象的查詢語言。
(5)本地SQL檢索方式
? 使用本地數據庫的SQL查詢語句
導航對象圖檢索方式
查詢出一個用戶,查詢這個用戶的所有訂單,直接得到用戶的訂單集合
Customer customer = (Customer) session.get(Customer.class, 1);
Set<Orders> sets = customer.getSetOrders();
System.out.println(sets);
☆HQL檢索方式(查詢數據庫數據--重點)
HQL VS SQL
HQL查詢語句(操作實體類)
? 是面向對象的,Hibernate負責解析HQL語句,然后根據對象-關系映射文件中的映射信息,把HQL查詢語句翻譯成相應的SQL語句。HQL查詢語句中的主體是域對象中的類及類的屬性。
SQL查詢語句
? 是關系數據庫綁定在一起的,SQL查詢語句中主體是數據庫表及表的字段
HQL語句創建Query對象
調用session里面的方法 createQuery(“HQL語句”)
package cn.itcast.hibernate.test;
import java.util.Arrays;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.itcast.entity.User;
import cn.itcast.utils.HibernateUtils;
/**
* 實現hibernate的crud的操作
*/
public class TestDemo2 {
//hql查詢
@Test
public void testHQL() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSession();
tx = session.beginTransaction();
//創建query對象
Query query = session.createQuery("from User");
//調用query里面list方法返回list集合
List<User> list = query.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
}catch(Exception e) {
tx.rollback();
}finally {
session.close();
}
}
}
簡單查詢
查詢表中所有記錄
//使用Session創建Query對象
Query query = session.createQuery("from Customer");
//調用query里面的list方法
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
hql支持方法鏈編程
別名查詢
//使用Session創建Query對象
//c.cid 不是表字段名稱,而是實體類屬性名稱
Query query = session.createQuery("from Customer c where c.cid = 1");
排序查詢
asc 升序 desc降序
//對Customer表里面的數據,按照cid進行升序排序
Query query = session.createQuery("from Customer c order by c.cid asc");
Query query = session.createQuery("from Customer c order by c.cid desc");
分頁查詢
查詢表里的幾條數據
select * from orders limit 0, 3;
0:記錄開始位置
3:獲取記錄數
開始位置 = (當前頁 - 1) * 每頁記錄數
//查詢orders表里面的前四條記錄數
Query query = session.createQuery("from orders");
//設置開始位置
query.setFirstResult(0);
//設置獲取幾條記錄
query.setMaxResults(4);
唯一對象查詢
根據對象查詢這條記錄。
比如根據cid查詢記錄,調用get方法實現,返回一條記錄,應該是對象形式,使用對象接收數據
Query query = session.createQuery("from Customer c where c.cid = 2");
//使用對象接收返回數據
Customer customer = query.uniqueResult();
條件查詢
第一種方式:根據參數位置傳遞參數值
Query query = session.createQuery("from Customer c where c.cid = ? and c.cname = ?");
//設置參數
//setParameter設置參數
//第一個參數:?位置,從0開始
//第二個參數:參數值
query.setParameter(0, 1);
query.setParameter(1, "楊過");
第二種方式:根據參數的名稱傳遞參數值
Query query = session.createQuery("from Customer c where c.cid = :ccid and c.cname = :ccname");
//setParameter設置參數
//第一個參數:后面的名稱
//第二個參數:值
query.setParameter("ccid", 2);
query.setParameter("ccname", "郭靖");
代碼實現
package cn.itcast.hibernate.test;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.itcast.onetomany.Customer;
import cn.itcast.onetomany.Orders;
import cn.itcast.utils.HibernateUtils;
/**
* 演示hql操作
*/
public class HibernateHQLDemo1 {
//6.(2)根據參數名稱傳遞參數值
@Test
public void testSelect7() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
//查詢cid=2并且cname=尹志平的記錄
Query query =
session.createQuery("from Customer c where c.cid=:ccid and c.cname=:ccname");
//設置參數值
//setParameter有兩個參數
//第一個參數 冒號:后面的名稱
//第二個參數 表里具體的值
query.setParameter("ccid", 2);
query.setParameter("ccname", "尹志平");
List<Customer> list = query.list();
System.out.println(list);
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//6.(1)根據參數的位置傳遞參數值
@Test
public void testSelect6() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
//查詢cid=1 并且cname=楊過的記錄
Query query =
session.createQuery("from Customer c where c.cid=? and c.cname=?");
//設置參數值
//類型通用setParameter兩個參數
//******第一個參數:?位置,開始位置從 0 開始
//第二個參數:具體的參數值 表里數據值
query.setParameter(0, 1);
query.setParameter(1, "楊過");
List<Customer> list = query.list();
System.out.println(list);
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//5.唯一對象查詢
@Test
public void testSelect5() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
//查詢cid=2的記錄
Query query = session.createQuery("from Customer c where c.cid=2");
//使用對象接收返回數據
Customer c = (Customer) query.uniqueResult();
System.out.println(c);
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//4.分頁查詢
@Test
public void testSelect4() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
//查詢orders表里面前四條記錄
Query query = session.createQuery("from Orders");
//設置開始位置
query.setFirstResult(4);
//設置獲取幾條記錄
query.setMaxResults(4);
List<Orders> list = query.list();
for (Orders orders : list) {
System.out.println(orders);
}
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//3.排序查詢
@Test
public void testSelect3() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
//對customer表里面的數據,按照cid進行升序排列
//Query query = session.createQuery("from Customer c order by c.cid asc");
//對customer表里面的數據,按照cid進行降序排列
Query query = session.createQuery("from Customer c order by c.cid desc");
//調用query里面list方法
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//2.演示別名查詢
@Test
public void testSelect2() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
//使用session創建query對象 c是別名
//c.cid : 不是表字段名稱,而是實體類屬性名稱
//建議實體類屬性名稱與表字段名一致
Query query = session.createQuery("from Customer c where c.cid=1");
//調用query里面list方法
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//1.簡單查詢
//查詢customer表里面的所有數據
@Test
public void testSelect1() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
//使用session創建query對象 from后面是實體類名稱
Query query = session.createQuery("from Customer");
//方法鏈編程
List<Customer> list1 = session.createQuery("from Customer").list();
//調用query里面list方法
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
}
QBC查詢方式(會用)
簡單查詢
Criteria criteria = session.createCriteria(Customer.class);
//調用criteria的list方法
List<Customer> list = criteria.list();
排序查詢
//升序
Criteria criteria = session.createCriteria(Customer.class);
criteria.addOrder(Order.asc("cid"));
//Order類里面的方法asc,asc里面參數是實體類屬性名稱
//降序
criteria.addOrder(Order.desc("cid"));
分頁查詢
Criteria criteria = session.createCriteria(Customer.class);
//設置開始位置
criteria.setFirstResult(0);
//設置查詢記錄數
criteria.setMaxResults(3);
條件查詢
Criteria criteria = session.createCriteria(Customer.class);
//設置條件
criteria.add(Restrictions.gt("price", 3));
本地sql查詢
SQLQuery sqlQuery = session.createSQLQuery("select * from customer");
List<Object[]> list = sqlQuery.list();
for(Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
☆HQL的多表查詢
多表查詢
內連接:兩個表關聯的數據
范例:Select * from A inner joinB on A.id=B.id;Select * from A,B whereA.id=B.id
左外連接:左邊表所有的數據,右邊表查關聯數據
范例:Select * from A left outer join B on A.id=B.id
右外連接:右邊表所有的數據,左邊表查關聯數據
范例:Select * from A right outer join B on A.id=B.id
Hibernate中使用HQL多表操作
內連接:inner join
迫切內連接:inner join fetch
左外連接:left outer join
迫切左外連接:left outer join fetch
右外連接 : right outer join
內連接
查詢兩個表關聯數據,返回是list集合數組
Query query = session.createQuery("from Customer c inner join c.setOrders");
List<Object[]> list = query.list();
for(Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
返回list集合,每部分是數組的形式
迫切內連接
Query query = session.createQuery("from Customer c inner join fetch c.setOrders");
List<Customer> list = query.list();
返回list集合每部分是對象形式
左外連接
左邊所有和關聯數據,返回是list集合數組
Query query = session.createQuery("from Customer c left outer join c.setOrders");
List<Object[]> list = query.list();
返回list集合中,每部分是數組形式
迫切左外連接
左邊所有和關聯數據,返回是list集合對象
Query query = session.createQuery("from Customer c left outer join fetch c.setOrders");
List<Customer> list = query.list();
返回list集合中,每部分是對象形式
右外連接
右邊所有和關聯數據,返回是list集合數組
Query query = session.createQuery("from Customer c right outer join c.setOrders");
List<Cusomter[]> list = query.list();
HQL的投影查詢和聚合函數
投影查詢
查詢一部分數據,字段下所有
第一個操作
Query query = session.createQuery("select cname from Customer");
List<Object> list = query.list();
第二個操作
Query query = session.createQuery("select cname, title from Customer");
List<Object[]> list = session.list();
for(Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
聚合函數
Query query = session.createQuery("select count(*) from Customer");
Object obj = session.uniqueResult();
Long count = (Long) obj;
int sum = count.intValue();
代碼實現
package cn.itcast.hibernate.test;
import java.util.Arrays;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.junit.Test;
import cn.itcast.onetomany.Customer;
import cn.itcast.onetomany.Orders;
import cn.itcast.utils.HibernateUtils;
/**
* 演示hql多表查詢操作
*/
public class HibernateManyTable {
//6.(2)聚集函數使用
@Test
public void testSQL8() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
//count函數
// count記錄 sum 求和 avg平均數 min最小值 max最大值
Query query = session.createQuery("select count(*) from Customer");
Object obj = query.uniqueResult();
//可以獲取不同類型
//變成long類型
Long count = (Long) obj;
//變成int類型
int sum = count.intValue();
System.out.println(sum);
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//6.(1)投影查詢
//查詢customer表里面所有cname和address的值
@Test
public void testSQL7() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
//可以查詢一個字段也可以查詢多個字段,多個字段逗號隔開
Query query = session.createQuery("select cname,address from Customer");
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//投影查詢
//查詢customer表里面所有cname的值
@Test
public void testSQL6() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
Query query = session.createQuery("select cname from Customer");
List<Object> list = query.list();
System.out.println(list);
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//5.右外連接查詢
@Test
public void testSQL5() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
Query query = session.createQuery("from Customer c right outer join c.setOrders");
List<Object[]> list = query.list();
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//4.迫切左外連接查詢
@Test
public void testSQL4() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
Query query = session.createQuery("from Customer c left outer join fetch c.setOrders");
//加入fetch 返回list集合每部分結構是對象
List list = query.list();
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//3.左外連接查詢
@Test
public void testSQL3() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
Query query = session.createQuery("from Customer c left outer join c.setOrders");
//返回list集合每部分結構是數組
List<Object[]> list = query.list();
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//2.迫切內連接查詢
@Test
public void testSQL2() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
//只是在代碼中加入fetch
Query query = session.createQuery("from Customer c inner join fetch c.setOrders");
List<Customer> list = query.list();
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
//1.內連接查詢
@Test
public void testSQL1() {
Session session = null;
Transaction tx = null;
try {
//獲取到session
session = HibernateUtils.getSession();
//開啟事務
tx = session.beginTransaction();
//from Customer c inner join c.setOrders
//Customer表與orders表關聯部分 后面是寫的Customer表的set集合名稱
Query query = session.createQuery("from Customer c inner join c.setOrders");
//返回list集合每部分是數組
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
//提交事務
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
}
}
Hibernate的檢索策略
概念
Hibernate的檢索策略分為兩部分
立即檢索
調用方法的時候馬上發送語句查詢數據庫 get
延遲檢索
調用方法的時候不會馬上發送語句查詢數據庫,得到返回對象中的值時候才會查詢數據庫 load
Hibernate中延遲檢索分為兩部分
類級別延遲
如果根據oid查詢對象,使用get方法立即查詢,但是load方法不會馬上查詢數據
Customer customer = (Customer) session.load(Customer.class, 1);//不會發送語句
System.out.println(customer.getCid());//不發送語句
System.out.println(customer.getCname());//發送語句
讓load方法執行之后,也會立刻發送語句查詢數據庫,實現和ge相同的效果,class標簽上面,屬性lazy默認值是true
<class name="cn.xxx.Customer" table="Customer" lazy="false">
</class>
關聯級別延遲
比如查詢出一個用戶,再查詢這個用戶的所有的訂單
以用戶和訂單為例,演示關聯級別的延遲
在用戶那一端,有set標簽
在訂單那一端,有many-to-one標簽
在set標簽配置--關聯級別延遲
在set標簽上面有兩個屬性fetch和lazy
fetch的取值:控制sql語句的生成格式
值 | 說明 |
---|---|
select | 默認發送查詢語句 |
join | 連接查詢,發送的是一條迫切左外連接,配置了join,lazy就失效了 |
subselect | 子查詢,發送一條子查詢查詢其關聯對象,(必須使用list方法進行測試) |
lazy的取值:查找關聯對象的時候是否采用延遲
取值 | 說明 |
---|---|
true | 默認延遲 |
false | 不延遲 |
extra | 極其懶惰 |
fetch和lazy的值使用不同的組合實現不同的優化方式
默認值fetch是select,lazy是true
第一種情況:fetch值是join,lazy值是true、false、extra
如果fetch值是join,lazy無論值是什么,做的都是左外連接操作
<set name="setOrders" cascade="save-update" fetch="join" lazy="true"></set>
第二種情況:fetch值是select,lazy值是true、false、extra
<set name="setOrders" cascade="save-update" fetch="select" lazy="true"></set>
要進行延遲
Customer customer = (Customer) session.get(Customer.class, 1);
Set<Orders> sets = customer.getSetOrders();
System.out.println(sets.size());
獲取到set集合的時候,不會馬上發送sql語句,而得到集合的內容時候才會發送sql語句
<set name="setOrders" cascade="save-update" fetch="select" lazy="false"></set>
一次性把所有的查詢操作都執行,不進行延遲
<set name="setOrders" cascade="save-update" fetch="select" lazy="extra"></set>
把需要的數據返回,不需要的不給
第三種情況:fetch值是subselect,lazy值是true、false、extra
<set name="setOrders" cascade="save-update" fetch="subselect" lazy="true"></set>
進行延遲
<set name="setOrders" cascade="save-update" fetch="subselect" lazy="false"></set>
不進行延遲
<set name="setOrders" cascade="save-update" fetch="subselect" lazy="extra"></set>
極其延遲
在many-to-one配置--關聯級別延遲
有兩個屬性fetch和lazy
fetch有兩個值join、select
lazy常用兩個值false、proxy
默認值fetch是select、lazy是proxy
第一種情況:fetch值是join,lazy值是false和proxy
做左外連接操作
第二種情況:fetch值是select,lazy值是false和proxy
一次性把所有數據都查出來
和對端配置有關聯,配置是否要延遲
<class name="cn.xx.Customer" table="Customer" lazy="false"></class>
Hibernate的事物
概念
- Hibernate事務默認不是自動提交的
- 事務四個特性:原子性、一致性、隔離性、持久性
- 不考慮事務隔離性產生三個都問題
- 臟讀:一個事務讀到另一個事物沒有提交的數據
- 不可重復讀:一個事務讀到另一個事務update操作
- 虛讀:一個事務讀到另一個事務insert操作
- 解決都問題:設置隔離級別
- mysql默認隔離級別:repeatable read
- 不考慮事務隔離性產生一類問題,寫問題(丟失更新)
Hibernate配置事務隔離級別
在Hibernate核心配置文件中配置
hibernate.connection.isolation = 4
name屬性值 | 數字值 |
---|---|
Readuncommitted isolation | 1 |
Readcommitted isolation | 2 |
Repeatableread isolation | 4 |
?Serializable isolation | 8 |
<!-- 配置事務隔離級別 -->
<property name="hibernate.connection.isolation">4</property>
丟失更新
什么是丟失更新
如果不考慮事務隔離性,產生一類寫問題,這類寫的問題成為丟失更新
有兩個事務同時對一個記錄進行操作
第一種情況:
第一個事務修改了內容之后提交了,第二個事務回滾操作。一個事務回滾了另一個事務內容
第二種情況:
第一個事務修改內容提交了,第二個事務修改內容,也提交了。一個事務覆蓋另一個事務內容
解決丟失更新
第一種方式:使用悲觀鎖
一個事務在操作事務的時候,對這條記錄加鎖,其他事務不能操作這條記錄了,只有當前事務提交之后,其他事務才可以操作,效率低下。
第二種方式:使用樂觀鎖
使用版本號控制,有兩個事務同時操作同一條記錄。在記錄里面添加版本號信息,默認是0。
如果a事務,修改數據,提交事務,提交之前把記錄的版本號修改為1,完成提交
如果b事務,修改數據,提交事務之前,比較當前數據的版本號和數據庫里面的最新的版本號是否一致,如果不相同不更新數據庫
Hibernate解決丟失更新
實現步驟:
第一步:
在實體類中添加屬性,作為版本號的屬性
public class Customer {
private Integer cid;
private String cname;
private String address;
private Integer version;
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
}
第二步:
在實體類的映射文件中配置
<id name="cid" column="CID">
<generator class="native"></generator>
</id>
<!-- 版本號 -->
<version name="version"></version>
version標簽要在id標簽下面