1. 前言
本章節我們討論Hibernate一對多查詢的處理。
在上一章節中(Hibernate(一)——入門),我們探討了Hibernate執行最基本的增刪改查操作。現在我們將情況復雜化:加入我們在查詢用戶信息的時候需要同時查詢其登錄日志,這樣就涉及到一對多查詢。那么一對多查詢要怎么實現么?
2. jar包准備
在本節中,除了上一章節中用到的jar包,我還需要用log4j.jar來將Hibernate的查詢語句輸出到控制台。log4j.properties的配置如下:
1 log4j.rootLogger=info,console 2 log4j.appender.console=org.apache.log4j.ConsoleAppender 3 log4j.appender.console.layout=org.apache.log4j.PatternLayout 4 log4j.appender.console.layout.ConversionPattern=%d %p [%c] - %m%n
log4j的使用方法可查閱:Mybatis之一級緩存(七)中,log4j的學習和使用部分。
3. 數據庫准備
我們需要新建立日志表tbLog,並產生部分的測試數據。代碼如下:
1 CREATE TABLE tbLog ( 2 logID VARCHAR(50), 3 userID VARCHAR(50), 4 loginDate DATETIME 5 )
1 TRUNCATE TABLE tbUser 2 TRUNCATE TABLE tbLog 3 4 DECLARE @userID1 VARCHAR(50) 5 DECLARE @userID2 VARCHAR(50) 6 SET @userID1 = NEWID(); 7 SET @userID2 = NEWID(); 8 9 INSERT INTO tbUser(userID, loginName, userName, passWord) 10 SELECT @userID1,'luych','盧艷超','12333' UNION ALL 11 SELECT @userID2,'guest','游客','12333' 12 13 INSERT INTO tbLog(logID, userID, loginDate) 14 SELECT NEWID(), @userID1, '2016-04-01' UNION ALL 15 SELECT NEWID(), @userID1, '2016-04-02' UNION ALL 16 SELECT NEWID(), @userID1, '2016-04-05' UNION ALL 17 SELECT NEWID(), @userID1, '2016-04-08' UNION ALL 18 19 SELECT NEWID(), @userID2, '2016-04-11' UNION ALL 20 SELECT NEWID(), @userID2, '2016-04-22' 21 22 SELECT * FROM tbUser; 23 SELECT * FROM tbLog;
4. 准備JAVA對象
(1)建立與數據表tbLog相對應的JAVA對象,代碼如下:
1 package com.luych.hibernate.study.entity; 2 3 import java.util.Date; 4 5 import javax.persistence.Entity; 6 import javax.persistence.Id; 7 import javax.persistence.Table; 8 9 10 @Entity 11 @Table(name="tbLog") 12 public class LogEntity { 13 14 @Id 15 private String logID; 16 private String userID; 17 private Date loginDate; 18 19 public String getLogID() { 20 return logID; 21 } 22 public void setLogID(String logID) { 23 this.logID = logID; 24 } 25 public String getUserID() { 26 return userID; 27 } 28 public void setUserID(String userID) { 29 this.userID = userID; 30 } 31 public Date getLoginDate() { 32 return loginDate; 33 } 34 public void setLoginDate(Date loginDate) { 35 this.loginDate = loginDate; 36 } 37 38 39 40 }
當然,我們同時也要在Hibernate的xml中增加相應的配置
1 <mapping class="com.luych.hibernate.study.entity.LogEntity"/>
(2)調整UserEntity對象,建立其與LogEntity的一對多關系。
1 package com.luych.hibernate.study.entity; 2 3 import java.text.SimpleDateFormat; 4 import java.util.Set; 5 6 import javax.persistence.CascadeType; 7 import javax.persistence.Entity; 8 import javax.persistence.Id; 9 import javax.persistence.JoinColumn; 10 import javax.persistence.OneToMany; 11 import javax.persistence.Table; 12 13 @Entity 14 @Table(name="tbUser") 15 public class UserEntity { 16 17 @Id 18 private String userID; 19 private String loginName; 20 private String userName; 21 private String passWord; 22 @OneToMany(cascade=CascadeType.ALL) 23 @JoinColumn(name="userID") 24 private Set<LogEntity> logs; 25 26 public String getUserID() { 27 return userID; 28 } 29 public void setUserID(String userID) { 30 this.userID = userID; 31 } 32 public String getLoginName() { 33 return loginName; 34 } 35 public void setLoginName(String loginName) { 36 this.loginName = loginName; 37 } 38 public String getUserName() { 39 return userName; 40 } 41 public void setUserName(String userName) { 42 this.userName = userName; 43 } 44 public String getPassWord() { 45 return passWord; 46 } 47 public void setPassWord(String passWord) { 48 this.passWord = passWord; 49 } 50 public Set<LogEntity> getLogs() { 51 return logs; 52 } 53 public void setLogs(Set<LogEntity> logs) { 54 this.logs = logs; 55 } 56 @Override 57 public String toString() { 58 String str = loginName+", "+userName+", "+passWord+", "+userID+" 登錄日志:\n"; 59 for (LogEntity log: logs) { 60 str = str+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(log.getLoginDate())+"\n"; 61 } 62 return str; 63 } 64 } 65
其中,
- @OneToMany的cascade可取值為:
CascadeType.PERSIST:級聯新建,本例中即生成User的時候同時生成Log。
CascadeType.REMOVE : 級聯刪除,本例中即刪除User的時候同時刪除Log。
CascadeType.REFRESH:級聯刷新,本例中即查詢User的時候同時查詢Log。
CascadeType.MERGE :級聯更新,本例中即修改User的時候同時修改Log。
CascadeType.ALL :以上全部四項,即上面四個全都執行。
- @JoinColumn的name取值為:LogEntity中的userID屬性。
5. 調整Hibernate配置文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 5.0//EN" 4 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 5 <hibernate-configuration> 6 <session-factory> 7 <!-- 設置數據庫驅動 --> 8 <property name="hibernate.connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property> 9 <!-- 設置數據庫URL --> 10 <property name="hibernate.connection.url">jdbc:sqlserver://192.168.9.23:14433;databaseName=tempdb</property> 11 <!-- 數據庫用戶名 --> 12 <property name="hibernate.connection.username">sa</property> 13 <!-- 數據庫密碼 --> 14 <property name="hibernate.connection.password">123@abcd</property> 15 <!-- 打印sql --> 16 <property name="show_sql">true</property> 17 <property name="format_sql">false</property> 18 <!-- beans --> 19 <mapping class="com.luych.hibernate.study.entity.UserEntity"/> 20 <mapping class="com.luych.hibernate.study.entity.LogEntity"/> 21 </session-factory> 22 </hibernate-configuration>
我們增加了針對show_sql和format_sql的配置,加上這兩個配置后,Hibernate會輸出執行的SQL腳本。
- show_sql:true,輸出SQL腳本。false,不輸出。
- format_sql:true,格式化SQL腳本。false,不格式化。
本例中,並沒有將format_sql設置為true,是因為格式化的SQL在控制台中顯示很占篇幅,不利於我們后面看測試結果,所以關閉了。
6. 測試運行結果
1 package com.luych.hibernate.study.main; 2 3 import java.util.Date; 4 import java.util.HashSet; 5 import java.util.List; 6 import java.util.Set; 7 import java.util.UUID; 8 9 import org.hibernate.Query; 10 import org.hibernate.Session; 11 import org.hibernate.SessionFactory; 12 import org.hibernate.cfg.Configuration; 13 import org.junit.After; 14 import org.junit.Before; 15 import org.junit.Test; 16 17 import com.luych.hibernate.study.entity.LogEntity; 18 import com.luych.hibernate.study.entity.UserEntity; 19 20 @SuppressWarnings("unchecked") 21 public class TestMain { 22 23 private Session session; 24 25 @Before 26 public void getSession(){ 27 Configuration config = new Configuration().configure("hibernate-config.xml"); 28 SessionFactory sessionFactory = config.buildSessionFactory(); 29 session = sessionFactory.openSession(); 30 } 31 32 @After 33 public void freeSession(){ 34 session.close(); 35 } 36 37 public void sel() { 38 Query query = session.createQuery("FROM UserEntity WHERE 1=1"); 39 List<UserEntity> userList = query.list(); 40 for (UserEntity userEntity : userList) { 41 System.out.println(userEntity.toString()); 42 } 43 } 44 45 public void add() { 46 session.beginTransaction(); 47 String userID = UUID.randomUUID().toString(); 48 UserEntity user = new UserEntity(); 49 user.setLoginName("admin"); 50 user.setUserName("系統管理員"); 51 user.setPassWord("12333"); 52 user.setUserID(userID); 53 LogEntity log1 = new LogEntity(); 54 log1.setLogID(UUID.randomUUID().toString()); 55 log1.setUserID(userID); 56 log1.setLoginDate(new Date()); 57 LogEntity log2 = new LogEntity(); 58 log2.setLogID(UUID.randomUUID().toString()); 59 log2.setUserID(userID); 60 log2.setLoginDate(new Date()); 61 Set<LogEntity> logs = new HashSet<LogEntity>(); 62 logs.add(log1); 63 logs.add(log2); 64 user.setLogs(logs); 65 session.save(user); 66 session.getTransaction().commit(); 67 } 68 69 public void edt(){ 70 session.beginTransaction(); 71 Query query = session.createQuery("FROM UserEntity WHERE 1=1"); 72 List<UserEntity> userList = query.list(); 73 for (UserEntity userEntity : userList) { 74 userEntity.setPassWord("45666"); 75 LogEntity log = new LogEntity(); 76 log.setLogID(UUID.randomUUID().toString()); 77 log.setUserID(userEntity.getUserID()); 78 log.setLoginDate(new Date()); 79 userEntity.getLogs().add(log); 80 session.update(userEntity); 81 } 82 session.getTransaction().commit(); 83 } 84 85 public void del(){ 86 session.beginTransaction(); 87 Query query = session.createQuery("FROM UserEntity WHERE 1=1"); 88 List<UserEntity> userList = query.list(); 89 for (UserEntity userEntity : userList) { 90 session.delete(userEntity); 91 } 92 session.getTransaction().commit(); 93 } 94 95 @Test 96 public void test(){ 97 System.out.println("\n----------現有用戶:"); 98 sel(); 99 System.out.println("\n----------開始增加用戶:"); 100 add(); 101 System.out.println("\n----------增加用戶后:"); 102 sel(); 103 System.out.println("\n----------開始修改用戶:"); 104 edt(); 105 System.out.println("\n----------修改用戶后:"); 106 sel(); 107 System.out.println("\n----------開始刪除用戶:"); 108 del(); 109 System.out.println("\n----------刪除用戶后:"); 110 sel(); 111 } 112 }
getSession和freeSession和上一章節中相同,不再贅述。
add方法,新建了一個用戶並設定了兩條登錄日志,然后保存。edt方法,將所有用戶的密碼改為45666,並為所有的用戶增加一條登錄日志。del方法,刪除所有的用戶。sel方法,查詢所有用戶信息並輸出到控制台。
右鍵,Run As JUnit Test后,控制台輸出結果為:
1 2 ----------現有用戶: 3 Hibernate: select userentity0_.userID as userID1_1_, userentity0_.loginName as loginNam2_1_,
userentity0_.passWord as passWord3_1_, userentity0_.userName as userName4_1_
from tbUser userentity0_ where 1=1
4 Hibernate: select logs0_.userID as userID3_0_0_, logs0_.logID as logID1_0_0_,
logs0_.logID as logID1_0_1_, logs0_.loginDate as loginDat2_0_1_, logs0_.userID as userID3_0_1_
from tbLog logs0_ where logs0_.userID=? 5 6 luych, 盧艷超, 12333, CB6172E3-8750-4718-BEF6-EE0917015FA9 登錄日志: 7 2016-04-01 00:00:00 8 2016-04-08 00:00:00 9 2016-04-05 00:00:00 10 2016-04-02 00:00:00 11 12 Hibernate: select logs0_.userID as userID3_0_0_, logs0_.logID as logID1_0_0_,
logs0_.logID as logID1_0_1_, logs0_.loginDate as loginDat2_0_1_, logs0_.userID as userID3_0_1_
from tbLog logs0_ where logs0_.userID=? 13 14 guest, 游客, 12333, 21539577-A3D1-4A1F-8D10-6ED0540A46A0 登錄日志: 15 2016-04-11 00:00:00 16 2016-04-22 00:00:00 17 18 19 ----------開始增加用戶: 20 Hibernate: select logentity_.logID, logentity_.loginDate as loginDat2_0_, logentity_.userID as userID3_0_
from tbLog logentity_ where logentity_.logID=?
21 Hibernate: select logentity_.logID, logentity_.loginDate as loginDat2_0_, logentity_.userID as userID3_0_
from tbLog logentity_ where logentity_.logID=? 22 Hibernate: insert into tbUser (loginName, passWord, userName, userID) values (?, ?, ?, ?) 23 Hibernate: insert into tbLog (loginDate, userID, logID) values (?, ?, ?) 24 Hibernate: insert into tbLog (loginDate, userID, logID) values (?, ?, ?) 25 Hibernate: update tbLog set userID=? where logID=? 26 Hibernate: update tbLog set userID=? where logID=? 27 28 ----------增加用戶后: 29 Hibernate: select userentity0_.userID as userID1_1_, userentity0_.loginName as loginNam2_1_,
userentity0_.passWord as passWord3_1_, userentity0_.userName as userName4_1_
from tbUser userentity0_ where 1=1 30 31 luych, 盧艷超, 12333, CB6172E3-8750-4718-BEF6-EE0917015FA9 登錄日志: 32 2016-04-01 00:00:00 33 2016-04-08 00:00:00 34 2016-04-05 00:00:00 35 2016-04-02 00:00:00 36 37 38 guest, 游客, 12333, 21539577-A3D1-4A1F-8D10-6ED0540A46A0 登錄日志: 39 2016-04-11 00:00:00 40 2016-04-22 00:00:00 41 42 43 admin, 系統管理員, 12333, 99d5d264-9d02-4e45-a8c5-f710cc14107e 登錄日志: 44 2016-04-26 17:06:00 45 2016-04-26 17:06:00 46 47 48 ----------開始修改用戶: 49 Hibernate: select userentity0_.userID as userID1_1_, userentity0_.loginName as loginNam2_1_,
userentity0_.passWord as passWord3_1_, userentity0_.userName as userName4_1_
from tbUser userentity0_ where 1=1
50 Hibernate: select logentity_.logID, logentity_.loginDate as loginDat2_0_,
logentity_.userID as userID3_0_
from tbLog logentity_ where logentity_.logID=?
51 Hibernate: select logentity_.logID, logentity_.loginDate as loginDat2_0_,
logentity_.userID as userID3_0_
from tbLog logentity_ where logentity_.logID=?
52 Hibernate: select logentity_.logID, logentity_.loginDate as loginDat2_0_,
logentity_.userID as userID3_0_
from tbLog logentity_ where logentity_.logID=? 53 Hibernate: insert into tbLog (loginDate, userID, logID) values (?, ?, ?) 54 Hibernate: insert into tbLog (loginDate, userID, logID) values (?, ?, ?) 55 Hibernate: insert into tbLog (loginDate, userID, logID) values (?, ?, ?) 56 Hibernate: update tbUser set loginName=?, passWord=?, userName=? where userID=? 57 Hibernate: update tbUser set loginName=?, passWord=?, userName=? where userID=? 58 Hibernate: update tbUser set loginName=?, passWord=?, userName=? where userID=? 59 Hibernate: update tbLog set userID=? where logID=? 60 Hibernate: update tbLog set userID=? where logID=? 61 Hibernate: update tbLog set userID=? where logID=? 62 63 ----------修改用戶后: 64 Hibernate: select userentity0_.userID as userID1_1_, userentity0_.loginName as loginNam2_1_,
userentity0_.passWord as passWord3_1_, userentity0_.userName as userName4_1_
from tbUser userentity0_ where 1=1 65 66 luych, 盧艷超, 45666, CB6172E3-8750-4718-BEF6-EE0917015FA9 登錄日志: 67 2016-04-01 00:00:00 68 2016-04-08 00:00:00 69 2016-04-05 00:00:00 70 2016-04-02 00:00:00 71 2016-04-26 17:06:00 72 73 74 guest, 游客, 45666, 21539577-A3D1-4A1F-8D10-6ED0540A46A0 登錄日志: 75 2016-04-11 00:00:00 76 2016-04-22 00:00:00 77 2016-04-26 17:06:00 78 79 80 admin, 系統管理員, 45666, 99d5d264-9d02-4e45-a8c5-f710cc14107e 登錄日志: 81 2016-04-26 17:06:00 82 2016-04-26 17:06:00 83 2016-04-26 17:06:00 84 85 86 ----------開始刪除用戶: 87 Hibernate: select userentity0_.userID as userID1_1_, userentity0_.loginName as loginNam2_1_,
userentity0_.passWord as passWord3_1_, userentity0_.userName as userName4_1_
from tbUser userentity0_ where 1=1 88 Hibernate: update tbLog set userID=null where userID=? 89 Hibernate: update tbLog set userID=null where userID=? 90 Hibernate: update tbLog set userID=null where userID=? 91 Hibernate: delete from tbLog where logID=? 92 Hibernate: delete from tbLog where logID=? 93 Hibernate: delete from tbLog where logID=? 94 Hibernate: delete from tbLog where logID=? 95 Hibernate: delete from tbLog where logID=? 96 Hibernate: delete from tbUser where userID=? 97 Hibernate: delete from tbLog where logID=? 98 Hibernate: delete from tbLog where logID=? 99 Hibernate: delete from tbLog where logID=? 100 Hibernate: delete from tbUser where userID=? 101 Hibernate: delete from tbLog where logID=? 102 Hibernate: delete from tbLog where logID=? 103 Hibernate: delete from tbLog where logID=? 104 Hibernate: delete from tbUser where userID=? 105 106 ----------刪除用戶后: 107 Hibernate: select userentity0_.userID as userID1_1_, userentity0_.loginName as loginNam2_1_,
userentity0_.passWord as passWord3_1_, userentity0_.userName as userName4_1_
from tbUser userentity0_ where 1=1
108
從打印結果中,我們可以看到,新增、編輯、刪除用戶信息的時候,Hibernate都幫我們完成登錄日志的新增、刪除、操作。查詢的時候也如此。
但是需要提點的是:在Hibernate第一次查詢中,我們看到它先查詢了tbUser表,然后針對tbUser表的每一個記錄都又查詢了下tbLog表,這就是經典的N+1查詢問題,所以效率嘛…
以上就是Hibernate中一對多的查詢關聯,其他關聯情況將在后續的博文中講解。
