1. 前言
本章节我们讨论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的使用方法可查阅:中,log4j的学习和使用部分。
3. 数据库准备
我们需要新建立日志表tbLog,并产生部分的测试数据。代码如下:
1 CREATE TABLE tbLog (2 logID VARCHAR(50),3 userID VARCHAR(50),4 loginDate DATETIME5 )
1 tbUser 2 tbLog 3 4 @userID1 (50) 5 @userID2 (50) 6 @userID1 = NEWID(); 7 @userID2 = NEWID(); 8 9 tbUser(userID, loginName, userName, passWord) 10 @userID1,'luych','卢艳超','12333' 11 @userID2,'guest','游客','12333' 12 13 tbLog(logID, userID, loginDate) 14 NEWID(), @userID1, '2016-04-01' 15 NEWID(), @userID1, '2016-04-02' 16 NEWID(), @userID1, '2016-04-05' 17 NEWID(), @userID1, '2016-04-08' 18 19 NEWID(), @userID2, '2016-04-11' 20 NEWID(), @userID2, '2016-04-22' 21 22 * tbUser; 23 * 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
(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 Setlogs; 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 getLogs() { 51 return logs; 52 } 53 public void setLogs(Set 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属性。
- @OneToMany的cascade可取值为:
5. 调整Hibernate配置文件
1 2 56 7 8 22com.microsoft.sqlserver.jdbc.SQLServerDriver 9 10jdbc:sqlserver://192.168.9.23:14433;databaseName=tempdb 11 12sa 13 14123@abcd 15 16true 17false 18 1920 21
我们增加了针对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 ListuserList = 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 logs = new HashSet (); 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 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 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=1108
从打印结果中,我们可以看到,新增、编辑、删除用户信息的时候,Hibernate都帮我们完成登录日志的新增、删除、操作。查询的时候也如此。
但是需要提点的是:在Hibernate第一次查询中,我们看到它先查询了tbUser表,然后针对tbUser表的每一个记录都又查询了下tbLog表,这就是经典的N+1查询问题,所以效率嘛…
以上就是Hibernate中一对多的查询关联,其他关联情况将在后续的博文中讲解。