Hibernate(二)——一对多查询

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">[email protected]</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中一对多的查询关联,其他关联情况将在后续的博文中讲解。

时间: 2024-11-09 15:44:13

Hibernate(二)——一对多查询的相关文章

Hibernate的一对多查询及去掉重复的对象distinct

问:sql 中 select * from A left join B on A.id=B.id where A.id=? 如果在Hibernate 中 用HQL 怎么表达呢 ? 答:from A left join A.b b where A.id=? 其中b是在实体类A的hibernate配置文件中映射的对象B <hibernate-mapping package="com.XXXX.entities">    <class name="A"

Hibernate HQL一对多 在一方的查询

首先说一句:是版本的问题! 在多对多或者多对一,从一中查找多中查询某些语句时容易出现 我写的hql为: from Department as d where d.employees.name='Tom'; 运行时出现异常:org.hibernate.QueryException: illegal attempt to dereference collection 是因为:在上面的HQL语句中,Department的关联实体employees是一个集合,而不直接是一个Employee实体. 在Hi

Hibernate-ORM:11.Hibernate中的关联查询

------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客将讲述Hibernate中的关联查询,及其级联(cascade)操作,以及指定哪一方维护关联关系的(inverse) 一,讲述目录如下: 1.单向一对多:(增加一个区县及其它以下的对应街道) 2.单项一对多:(查询一个区县,以及它下面所有的对应街道) 3.单项多对一:(查询一个指定的街道,并同时展示出其对应的区县) 4.双向一对多(多对一):(值得注意:toString()套路不对容易引发错误Err

Hibernate 关于执行sql查询语句(转)

原文  http://www.yshjava.cn/post/543.html 主题 SQLHibernate Hibernate对原生SQL查询的支持和控制是通过SQLQuery接口实现的.通过Session接口,我们能够很方便的创建一个SQLQuery(SQLQuery是一个接口,在Hibernate4.2.2之前,默认返回的是SQLQuery的实现类--SQLQueryImpl对象,在下文中出现的SQLQuery如非注明,都是指该子类)对象来进行原生SQL查询: session.creat

hibernate使用Query进行查询

本文主要探讨hibernate的简单查询,主要是使用Query进行的查询. 1.首先看下annotation的API中关于查询的描述 2.3. 映射查询 2.3.1. 映射EJBQL/HQL查询 使用注解还可以映射EJBQL/HQL查询. @NamedQuery 和@NamedQueries是可使用在类和包上的注解. 但是它们的定义在session factory/entity manager factory范围中是都可见的. 命名式查询通过它的名字和实际的查询字符串来定义. javax.per

【Hibernate步步为营】--hql查询之实体对象查询

上篇文章简单介绍了hql它作为Hibernate的查询语言,封装了基本上SQL的所有查询操作,HQL能够实现对数据库文件的增删改查,该篇文章着重讨论HQL实体对象的查询方法. 一.实体对象查询 实体对象查询是hql查询的基础,作为一种对象查询语言,在查询操作时和sql不同,查询字符串中的内容要使用类名和类的属性名来代替.这种查询方法相对简单,只要有SQL功底,使用hql是很简单的,但是有一些问题需要注意,就是查询获取数据不是目的,需要考虑的是如何编写出高效的查询语句,这才是讨论的重点. 1.1

Hibernate 的原生 SQL 查询

Hibernate除了支持HQL查询外,还支持原生SQL查询.         对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQuery()获取这个接口.该接口是Query接口的子接口.         执行SQL查询步骤如下:         1.获取Hibernate Session对象         2.编写SQL语句         3.通过Session的createSQLQuery方法创建查询对象         4.调用SQ

hibernate使用原生SQL查询返回结果集的处理

今天没事的时候,看到公司框架里有一个用原生SQL写的函数,说实在以前自己也干过这事,但好久都没有用,都忘得差不多了,现在基本都是用的hql语句来查询结果.hibernate中使用createSQLQuery拉来来实现SQL语句的查询,具体用法:session.createSQLQuery(sql),对于用SQL返回的结果集是一个什么样的结果集都毫无记忆.自己查了下,才知道,原来是返回一个Object类型数组的list集合,而其中Object类型的数组里的值则与sql语句中的查询项相对应,如果是s

Hibernate关联操作、查询操作、高级特性、并发处理机制

本文所需的数据库初始文件,Hibernate常用操作的完整示例代码(包含所有Hibernate操作所需jar文件)提供下载学习:http://download.csdn.net/detail/daijin888888/9551724 1.Hibernate关联映射 1)什么是关联映射? 如果表之间具有关联关系,Hibernate允许我们在hbm.xml中描述他们的关联关系,然后在我们操作其中一张表时,自动的根据这种关系操作到另外的关系表,那么这种关联关系的设置,我们称之为关联映射. 2)关联映射