22-Java-Hibernate框架(二)
- 2020 年 4 月 22 日
- 筆記
- 語言__Java語言
Hibernate的了解、Hibernate的搭建、Hibernate的基本使用流程等內容請閱讀21-Java-Hibernate(一)
五、Hibernate的Query查詢介面(重中之重)
1.HQL語言了解:Hibernate Query Language(HQL),是hibernate的查詢語言,和SQL語句結構一樣,不同點注意點如下:
(1)HQL是面向對象查詢,SQL是面向結構查詢
(2)在HQL使用類名和屬性名,替代了原有的表名和欄位名
(3)在HQL語句中類型名和屬性名大小寫敏感
(4)如果需要select * 查詢所有欄位的值,在HQL語句中可以省略select *語句。例如:from User;
(5)如果需要join…on表連接,需要建立關聯映射關係使用,不支援on子句
(6)不要使用資料庫提供的字元串函數、日期函數和一些特有的函數。一些基礎的函數可以使用,例如:max(),min(),sum(),avg(),count()等。
(7)若只查詢字體類中某幾個欄位,返回的結果是泛型,值的集合
2.具體Query常用的相關介面看程式碼演示
1 package com.hibernatetest.test; 2 3 import java.util.List; 4 5 import org.hibernate.Query; 6 import org.hibernate.Session; 7 import com.hibernatetest.entity.User; 8 import HibernatenateUtils.hibernateUtils; 9 /* 10 * Query介面的常用方法: 11 * 1.setXXX():用於設置HQL語句中問號或變數的值 12 * 2.uniqueResult():得到單個對象(返回Object類型),在已知查詢結果中只有一個或零個才能用此函數,若有多個滿足條件的結果則報異常 13 * 3.executeUpdate():執行更新和刪除語句(返回int型作為操作成功的次數) 14 * 4.分頁查詢 15 * 5.list():獲取結果集(返回List類型) 16 * 6.iterate():獲取結果集(返回Iterator類型) 17 * */ 18 public class QueryTest { 19 public static void main(String[] args) { 20 //第一步:Query對象是通過Session獲取的,所以先要通過之前寫hibernate工具類獲取Session對象 21 Session session = hibernateUtils.getSession(); 22 23 //第二步:CreateQuery("HQL語句"):用於創建Query對象。 24 Query query = session.createQuery("from User where uname='zhangsan'"); 25 26 /*查詢參數設值setXXX(): (兩種方式) 27 * 1.問號設值 28 * Query query = session.createQuery("from User where uid between ? and ?"); 29 * query.setInteger(0,5);//給第一個問號處賦值5 30 * query.setInteger(1,10);//給第一個問號處賦值10 31 * 32 * 2.變數設值 33 * Query query = session.createQuery("from User where uname=:name"); 34 * query.setString(name,"zhangsan");//給name變數賦值 35 * 36 * 3.模糊查詢 37 * Query query = session.createQuery("from User where uname likt %?%");錯!!!!! 38 * Query query = session.createQuery("from User where uname like ?");對!!!! 39 * query.setString(0,"%" +"zhang"+ "%");//給name變數賦值 40 * 41 * 4.分頁查詢 42 * Query query = session.createQuery("from User where uname='zhangsan'"); 43 * query.setFirstResult(0);從滿足條件的數據中的第一條數據開始抓取 44 * query.setMaxResult(2);從滿足條件的數據中只抓取前兩條數據 45 * 46 * 5.獲取單個對象 47 * Query query = session.createQuery("select count(*) from User where uname='zhangsan'"); 48 * Object object = query.uniqueResult(); 49 * 50 * 6.構造查詢 51 * Query query = session.createQuery("select new User(5,"zhangsan") from User where uname='zhangsan'"); 52 * Object object = query.uniqueResult(); 53 * */ 54 55 /*資料庫更新和刪除操作executeUpdate() 56 * 1.刪除 57 * Query query = session.createQuery("delete from User where uid in(1,6)");//刪除id為1和6的數據,即使資料庫中沒有符合條件的數據也不會報錯 58 * int execute = query.executeUpdate();//返回成功操作的次數 59 * */ 60 61 //第三步:Query獲取結果集 62 //1.list()獲取 63 List<?> list = query.list(); 64 for(Object u:list){ 65 User user = (User)u; 66 System.out.println(user); 67 } 68 /*2.iterate()獲取 69 * Iterator<?> iterator = query.iterate(); 70 * while(iterator.hasNext()){ 71 * User user = (User)iterator.next(); 72 * System.out.println(user); 73 * } 74 * */ 75 /*面試要考:list()和iterate()獲取結果集的區別: 76 * list():一次把所有數據從資料庫中取出來 77 * iterate():先從資料庫中查詢滿足條件的id,如果快取中包含全部要查詢的id的數據,就無需再查資料庫,直接從快取中取數據,否則,根據id從資料庫中取 78 * */ 79 80 //第四步:記得將Session關閉 81 session.close(); 82 } 83 }
六、Hibernate的三個狀態
對象(持久化類的實例)處於session對象的管理中才能與資料庫發生聯繫。在Hibernate框架應用中,我們依據對象對象與session對象的關係不同情況,
把對象的狀態分為人的三種:瞬時狀態、遊離狀態、持久狀態。
Transient(瞬時狀態|臨時狀態):在new之後,save()之前,資料庫沒有應用的數據
如果對象未與session對象關聯過,我們稱該對象處於瞬時狀態
Persistent(持久狀態):在save()之後,在session關閉之前,資料庫有相對應的數據
如果對象與session關聯起來了,且該對象對應到資料庫記錄,則稱該對象處於持久狀態
三狀態結構圖:
三狀態轉換關係:
1.瞬時狀態轉換為持久狀態:
使用session的save()或saveOrUpdate()方法保存對象後,該對象的狀態由瞬時狀態轉換為持久狀態
使用session的get()或load()方法獲取對象後,該對象的狀態為持久狀態
2.持久狀態轉換為瞬時狀態
執行session對象的delete()方法後,對象由原來的持久狀態變為瞬時狀態,因此該對象沒有與任何的資料庫數據有關聯
3.持久狀態變為遊離狀態
執行session對象的evict()、clear()、close()方法,對象由原來的持久狀態變為遊離狀態。
4.遊離狀態變為持久狀態
重新獲取對象session對象,執行session對象的update()或saveOrUpdate方法,由遊離狀態轉換為持久狀態,該對象再次與session關聯
5.遊離狀態轉換為瞬時狀態
執行session的delete()方法,對象有遊離狀態變為瞬時狀態
對瞬時狀態或遊離狀態的對象不再被其他對象引用時,會被Java虛擬機按照垃圾回收機制處理
七、Hibernate根據實體自動構建生成表
第一步:在hibernate.cfg.xml中添加<property name=”hibernate.hbm2ddl.auto”>update</property>,設置自動生成表
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4 "//www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> 5 6 <hibernate-configuration> 7 8 <session-factory> 9 <!--hibernate 方言 區分身份 --> 10 <property name="dialect">org.hibernate.dialect.MySQLDialect</property> 11 <!-- 資料庫連接資訊 --> 12 <property name="connection.driver_class">com.mysql.jdbc.Driver</property> 13 <property name="connection.url">jdbc:mysql://127.0.0.1:3306/hibernatetest</property> 14 <property name="connection.username">root</property> 15 <property name="connection.password">root</property> 16 17 <!-- hibernate自動生成表 update:如果資料庫不存在這張表自動創建一張表,如果存在不創建--> 18 <property name="hibernate.hbm2ddl.auto">update</property> 19 <!-- hibernate在控制台顯示SQL語句 --> 20 <property name="show_sql">true</property> 21 <!-- hibernate格式化SQL,控制台看起來更整齊 --> 22 <property name="format_sql">true</property> 23 <!-- 設置自動提交 --> 24 <property name="connection.autocommit">true</property> 25 26 <!-- <property name="connection.characterEncoding">UTF-8</property> --> 27 <!--載入hibernate映射 --> 28 <mapping resource="com/hibernatetest/entity/Entity.hbm.xml" /> 29 </session-factory> 30 31 </hibernate-configuration>
第二步:編寫實體類
第三步:配置映射文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "//www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 4 <hibernate-mapping> 5 <!-- name:對應的實體類的許可權定名稱,table:對應資料庫表名稱 --> 6 <class name="com.hibernatetest.entity.Entity" table="hibernateEntity"> 7 <!-- id標籤用於配置主鍵屬性 8 name屬性:對應實體類中屬性名稱 9 type屬性:可以省略,如果省略默認實體類中屬性的對應類型 10 --> 11 <id name="userid" type="java.lang.Integer"> 12 <!-- column用於設置對應資料庫表中欄位名。不寫column標籤,資料庫中的欄位名則和Entity類中的屬性名一致 13 name:資料庫表中的欄位名 14 length:設置欄位長度 15 --> 16 <column name="userid"></column> 17 <!-- generator用於設置主鍵生成策略 18 native:資料庫本地生成策略,適用於多個資料庫 19 sequence:序列(Oracle使用) 20 imcrement:主要mysql資料庫使用,適用於所有資料庫,先查詢出最大的id,在此基礎上+1,有可能出現並發的問題 21 uuid:生成32位,不會重複的主鍵,可以達到真正的跨資料庫 22 foreign:通常在一對一關聯的時候使用 23 自增長:identity,適用於mysql,db2,sql server。 24 --> 25 <generator class="native"></generator> 26 </id> 27 28 <!-- property標籤用於配置其他屬性 29 name:對應實體類中屬性名稱 30 type:可以省略,如果省略默認實體類中屬性的對應類型 31 --> 32 <property name="username" type="java.lang.String"> 33 <column name="username" length="32"></column> 34 </property> 35 <property name="password" type="java.lang.String" > 36 <column name="password" length="32"></column> 37 </property> 38 39 </class> 40 41 </hibernate-mapping>
第四步:編寫測試類測試
控制台顯示hibernate在資料庫沒找到hibernateEntity表
於是它便會在資料庫自動生成一張表
八、Hibernate的關聯映射
實體與實體之間有一對一、多對一、多對多的關係,Hibernate也因此需要對錶與表之間進行關聯映射配置。
假設:有一張表為Entity,表中有userid,username,password三個欄位,另一張表Grade,表中有gradeid,userid,grade。
我現在通過userid查詢對應另一張表中的grade(此處可以理解為多對一)。步驟如下:
第一步:搭建Hibernate,配置hibernate.cfg.xml,此處由於我們有兩張表,所以需要載入兩個映射文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4 "//www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> 5 6 <hibernate-configuration> 7 8 <session-factory> 9 <!--hibernate 方言 區分身份 --> 10 <property name="dialect">org.hibernate.dialect.MySQLDialect</property> 11 <!-- 資料庫連接資訊 --> 12 <property name="connection.driver_class">com.mysql.jdbc.Driver</property> 13 <property name="connection.url">jdbc:mysql://127.0.0.1:3306/hibernatetest</property> 14 <property name="connection.username">root</property> 15 <property name="connection.password">root</property> 16 17 <!-- hibernate自動生成表 update:如果資料庫不存在這張表自動創建一張表,如果存在不創建--> 18 <property name="hibernate.hbm2ddl.auto">update</property> 19 <!-- hibernate在控制台顯示SQL語句 --> 20 <property name="show_sql">true</property> 21 <!-- hibernate格式化SQL,控制台看起來更整齊 --> 22 <property name="format_sql">true</property> 23 <!-- 設置自動提交 --> 24 <property name="connection.autocommit">true</property> 25 26 <!-- <property name="connection.characterEncoding">UTF-8</property> --> 27 28 <!--載入hibernate映射文件 --> 29 <mapping resource="com/hibernatetest/entity/Entity.hbm.xml" /> 30 <mapping resource="com/hibernate/grade/Grade.hbm.xml" /> 31 </session-factory> 32 33 </hibernate-configuration>
第二步:配置兩張表對應的映射文件
Entity.hbm.xml:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "//www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 4 <hibernate-mapping> 5 <!-- name:對應的實體類的許可權定名稱,table:對應資料庫表名稱 --> 6 <class name="com.hibernatetest.entity.Entity" table="hibernateEntity"> 7 <!-- id標籤用於配置主鍵屬性 8 name屬性:對應實體類中屬性名稱 9 type屬性:可以省略,如果省略默認實體類中屬性的對應類型 10 --> 11 <id name="userid" type="java.lang.Integer"> 12 <!-- column用於設置對應資料庫表中欄位名。不寫column標籤,資料庫中的欄位名則和Entity類中的屬性名一致 13 name:資料庫表中的欄位名 14 length:設置欄位長度 15 --> 16 <column name="userid"></column> 17 <!-- generator用於設置主鍵生成策略 18 native:資料庫本地生成策略,適用於多個資料庫 19 sequence:序列(Oracle使用) 20 imcrement:主要mysql資料庫使用,適用於所有資料庫,先查詢出最大的id,在此基礎上+1,有可能出現並發的問題 21 uuid:生成32位,不會重複的主鍵,可以達到真正的跨資料庫 22 foreign:通常在一對一關聯的時候使用 23 自增長:identity,適用於mysql,db2,sql server。 24 --> 25 <generator class="native"></generator> 26 </id> 27 28 <!-- property標籤用於配置其他屬性 29 name:對應實體類中屬性名稱 30 type:可以省略,如果省略默認實體類中屬性的對應類型 31 --> 32 <property name="username" type="java.lang.String"> 33 <column name="username" length="32"></column> 34 </property> 35 <property name="password" type="java.lang.String" > 36 <column name="password" length="32"></column> 37 </property> 38 </class> 39 40 </hibernate-mapping>
Grade.hbm.xml:(此處需要加入對grade表的多對一的映射關係)
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "//www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 4 <hibernate-mapping> 5 <!-- name:對應的實體類的許可權定名稱,table:對應資料庫表名稱 --> 6 <class name="com.hibernate.grade.Grade" table="hibernateGrade"> 7 <!-- id標籤用於配置主鍵屬性 8 name屬性:對應實體類中屬性名稱 9 type屬性:可以省略,如果省略默認實體類中屬性的對應類型 10 --> 11 <id name="gradeid" type="java.lang.Integer"> 12 <!-- column用於設置對應資料庫表中欄位名。不寫column標籤,資料庫中的欄位名則和Entity類中的屬性名一致 13 name:資料庫表中的欄位名 14 length:設置欄位長度 15 --> 16 <column name="gradeid"></column> 17 <!-- generator用於設置主鍵生成策略 18 native:資料庫本地生成策略,適用於多個資料庫 19 sequence:序列(Oracle使用) 20 imcrement:主要mysql資料庫使用,適用於所有資料庫,先查詢出最大的id,在此基礎上+1,有可能出現並發的問題 21 uuid:生成32位,不會重複的主鍵,可以達到真正的跨資料庫 22 foreign:通常在一對一關聯的時候使用 23 自增長:identity,適用於mysql,db2,sql server。 24 --> 25 <generator class="native"></generator> 26 </id> 27 28 <!-- property標籤用於配置其他屬性 29 name:對應實體類中屬性名稱 30 type:可以省略,如果省略默認實體類中屬性的對應類型 31 --> 32 33 <!-- 多對一映射關係 --> 34 <!-- name:當前Grade類的Entity屬性 35 column:Grade類的外鍵 36 fetch:有join和select.默認為select 37 select:查了當前表之後,再查外鍵所在的那張表 38 join:在多對一將原本需要兩條sql語句以left outer join(左外連接)方式用一條語句解決 39 cascade:級聯操作關聯表:慎用 40 save-update:在添加或操作的時候使用級聯操作關聯表 41 delete:在刪除的時候使用級聯操作關聯表 42 all:在所有操作的時候使用級聯操作關聯表 43 none:任何時候都不使用 44 --> 45 <many-to-one name="entity" column="userid" fetch="join"></many-to-one> 46 47 <property name="grade" type="java.lang.Double" > 48 <column name="grade"></column> 49 </property> 50 </class> 51 52 </hibernate-mapping>
第三步:編寫兩張表對應的實體類
Entity類:
1 package com.hibernatetest.entity; 2 3 public class Entity { 4 private Integer userid; 5 private String username; 6 private String password; 7 public Entity() { 8 super(); 9 // TODO Auto-generated constructor stub 10 } 11 public Entity(Integer userid, String username, String password) { 12 super(); 13 this.userid = userid; 14 this.username = username; 15 this.password = password; 16 } 17 public Integer getUserid() { 18 return userid; 19 } 20 public void setUserid(Integer userid) { 21 this.userid = userid; 22 } 23 public String getUsername() { 24 return username; 25 } 26 public void setUsername(String username) { 27 this.username = username; 28 } 29 public String getPassword() { 30 return password; 31 } 32 public void setPassword(String password) { 33 this.password = password; 34 } 35 @Override 36 public int hashCode() { 37 final int prime = 31; 38 int result = 1; 39 result = prime * result 40 + ((password == null) ? 0 : password.hashCode()); 41 result = prime * result + ((userid == null) ? 0 : userid.hashCode()); 42 result = prime * result 43 + ((username == null) ? 0 : username.hashCode()); 44 return result; 45 } 46 @Override 47 public boolean equals(Object obj) { 48 if (this == obj) 49 return true; 50 if (obj == null) 51 return false; 52 if (getClass() != obj.getClass()) 53 return false; 54 Entity other = (Entity) obj; 55 if (password == null) { 56 if (other.password != null) 57 return false; 58 } else if (!password.equals(other.password)) 59 return false; 60 if (userid == null) { 61 if (other.userid != null) 62 return false; 63 } else if (!userid.equals(other.userid)) 64 return false; 65 if (username == null) { 66 if (other.username != null) 67 return false; 68 } else if (!username.equals(other.username)) 69 return false; 70 return true; 71 } 72 @Override 73 public String toString() { 74 return "Entity [userid=" + userid + ", username=" + username 75 + ", password=" + password + "]"; 76 } 77 78 }
Grade類:
1 package com.hibernate.grade; 2 3 import com.hibernatetest.entity.Entity; 4 5 public class Grade { 6 private Integer gradeid; 7 private Entity entity; 8 private Double grade; 9 public Grade() { 10 super(); 11 // TODO Auto-generated constructor stub 12 } 13 public Grade(Integer gradeid, Entity entity, Double grade) { 14 super(); 15 this.gradeid = gradeid; 16 this.entity = entity; 17 this.grade = grade; 18 } 19 public Integer getGradeid() { 20 return gradeid; 21 } 22 public void setGradeid(Integer gradeid) { 23 this.gradeid = gradeid; 24 } 25 public Entity getEntity() { 26 return entity; 27 } 28 public void setEntity(Entity entity) { 29 this.entity = entity; 30 } 31 public Double getGrade() { 32 return grade; 33 } 34 public void setGrade(Double grade) { 35 this.grade = grade; 36 } 37 @Override 38 public int hashCode() { 39 final int prime = 31; 40 int result = 1; 41 result = prime * result + ((entity == null) ? 0 : entity.hashCode()); 42 result = prime * result + ((grade == null) ? 0 : grade.hashCode()); 43 result = prime * result + ((gradeid == null) ? 0 : gradeid.hashCode()); 44 return result; 45 } 46 @Override 47 public boolean equals(Object obj) { 48 if (this == obj) 49 return true; 50 if (obj == null) 51 return false; 52 if (getClass() != obj.getClass()) 53 return false; 54 Grade other = (Grade) obj; 55 if (entity == null) { 56 if (other.entity != null) 57 return false; 58 } else if (!entity.equals(other.entity)) 59 return false; 60 if (grade == null) { 61 if (other.grade != null) 62 return false; 63 } else if (!grade.equals(other.grade)) 64 return false; 65 if (gradeid == null) { 66 if (other.gradeid != null) 67 return false; 68 } else if (!gradeid.equals(other.gradeid)) 69 return false; 70 return true; 71 } 72 @Override 73 public String toString() { 74 return "Grade [gradeid=" + gradeid + ", entity=" + entity + ", grade=" 75 + grade + "]"; 76 } 77 78 }
第四步:編寫HibernateUtils工具類和測試類
測試類:
1 package Hibernatetest; 4 5 import org.hibernate.Query; 6 import org.hibernate.Session; 7 import org.hibernate.Transaction; 8 9 import com.hibernate.grade.Grade; 10 import com.hibernatetest.entity.Entity; 11 12 import HibernatenateUtils.hibernateUtils; 13 14 public class annotationtest { 15 16 public void test(){ 17 18 } 19 public static void main(String[] args) { 20 Session session = hibernateUtils.getSession(); 21 22 //先製造兩條記錄在資料庫中 23 Transaction transaction = session.beginTransaction(); 24 Entity user1 = new Entity(null,"zhangsan","1111"); 25 Grade grade1 = new Grade(null,user1,Double.valueOf(85)); 26 session.save(user1); 27 session.save(grade1); 28 transaction.commit(); 29 30 transaction = session.beginTransaction(); 31 Entity user2 = new Entity(null,"lisi","2222"); 32 Grade grade2 = new Grade(null,user2,Double.valueOf(100)); 33 session.save(user2); 34 session.save(grade2); 35 transaction.commit(); 36 37 //查詢測試 38 Grade grade = session.get(Grade.class,3); 39 System.out.println(grade); 40 session.close(); 41 } 42 }
運行結果: