1. 前言

本章节我们讨论Hibernate一对多查询的处理。

在上一章节中(Hibernate(一)——入门),我们探讨了Hibernate执行最基本的增删改查操作。现在我们将情况复杂化:加入我们在查询用户信息的时候需要同时查询其登录日志,这样就涉及到一对多查询。那么一对多查询要怎么实现么?

2. jar包准备

在本节中,除了上一章节中用到的jar包,我还需要用log4j.jar来将Hibernate的查询语句输出到控制台。log4j.properties的配置如下:

 log4j.rootLogger=info,console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d %p [%c] - %m%n

log4j的使用方法可查阅:Mybatis之一级缓存(七)中,log4j的学习和使用部分。

3. 数据库准备

我们需要新建立日志表tbLog,并产生部分的测试数据。代码如下:

 CREATE TABLE tbLog (
logID VARCHAR(50),
userID VARCHAR(50),
loginDate DATETIME
)
 TRUNCATE TABLE tbUser
TRUNCATE TABLE tbLog DECLARE @userID1 VARCHAR(50)
DECLARE @userID2 VARCHAR(50)
SET @userID1 = NEWID();
SET @userID2 = NEWID(); INSERT INTO tbUser(userID, loginName, userName, passWord)
SELECT @userID1,'luych','卢艳超','' UNION ALL
SELECT @userID2,'guest','游客','' INSERT INTO tbLog(logID, userID, loginDate)
SELECT NEWID(), @userID1, '2016-04-01' UNION ALL
SELECT NEWID(), @userID1, '2016-04-02' UNION ALL
SELECT NEWID(), @userID1, '2016-04-05' UNION ALL
SELECT NEWID(), @userID1, '2016-04-08' UNION ALL SELECT NEWID(), @userID2, '2016-04-11' UNION ALL
SELECT NEWID(), @userID2, '2016-04-22' SELECT * FROM tbUser;
SELECT * FROM tbLog;

4. 准备JAVA对象

(1)建立与数据表tbLog相对应的JAVA对象,代码如下:

 package com.luych.hibernate.study.entity;

 import java.util.Date;

 import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table; @Entity
@Table(name="tbLog")
public class LogEntity { @Id
private String logID;
private String userID;
private Date loginDate; public String getLogID() {
return logID;
}
public void setLogID(String logID) {
this.logID = logID;
}
public String getUserID() {
return userID;
}
public void setUserID(String userID) {
this.userID = userID;
}
public Date getLoginDate() {
return loginDate;
}
public void setLoginDate(Date loginDate) {
this.loginDate = loginDate;
} }

当然,我们同时也要在Hibernate的xml中增加相应的配置

 <mapping class="com.luych.hibernate.study.entity.LogEntity"/>

(2)调整UserEntity对象,建立其与LogEntity的一对多关系。

 package com.luych.hibernate.study.entity;

 import java.text.SimpleDateFormat;
import java.util.Set; import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table; @Entity
@Table(name="tbUser")
public class UserEntity { @Id
private String userID;
private String loginName;
private String userName;
private String passWord;
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="userID")
private Set<LogEntity> logs; public String getUserID() {
return userID;
}
public void setUserID(String userID) {
this.userID = userID;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public Set<LogEntity> getLogs() {
return logs;
}
public void setLogs(Set<LogEntity> logs) {
this.logs = logs;
}
@Override
public String toString() {
String str = loginName+", "+userName+", "+passWord+", "+userID+" 登录日志:\n";
for (LogEntity log: logs) {
str = str+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(log.getLoginDate())+"\n";
}
return str;
}
}

其中,

    • @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配置文件

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 5.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 设置数据库驱动 -->
<property name="hibernate.connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<!-- 设置数据库URL -->
<property name="hibernate.connection.url">jdbc:sqlserver://192.168.9.23:14433;databaseName=tempdb</property>
<!-- 数据库用户名 -->
<property name="hibernate.connection.username">sa</property>
<!-- 数据库密码 -->
<property name="hibernate.connection.password">123@abcd</property>
<!-- 打印sql -->
<property name="show_sql">true</property>
<property name="format_sql">false</property>
<!-- beans -->
<mapping class="com.luych.hibernate.study.entity.UserEntity"/>
<mapping class="com.luych.hibernate.study.entity.LogEntity"/>
</session-factory>
</hibernate-configuration>

我们增加了针对show_sql和format_sql的配置,加上这两个配置后,Hibernate会输出执行的SQL脚本。

    • show_sql:true,输出SQL脚本。false,不输出。
    • format_sql:true,格式化SQL脚本。false,不格式化。

本例中,并没有将format_sql设置为true,是因为格式化的SQL在控制台中显示很占篇幅,不利于我们后面看测试结果,所以关闭了。

6. 测试运行结果

 package com.luych.hibernate.study.main;

 import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID; import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; import com.luych.hibernate.study.entity.LogEntity;
import com.luych.hibernate.study.entity.UserEntity; @SuppressWarnings("unchecked")
public class TestMain { private Session session; @Before
public void getSession(){
Configuration config = new Configuration().configure("hibernate-config.xml");
SessionFactory sessionFactory = config.buildSessionFactory();
session = sessionFactory.openSession();
} @After
public void freeSession(){
session.close();
} public void sel() {
Query query = session.createQuery("FROM UserEntity WHERE 1=1");
List<UserEntity> userList = query.list();
for (UserEntity userEntity : userList) {
System.out.println(userEntity.toString());
}
} public void add() {
session.beginTransaction();
String userID = UUID.randomUUID().toString();
UserEntity user = new UserEntity();
user.setLoginName("admin");
user.setUserName("系统管理员");
user.setPassWord("");
user.setUserID(userID);
LogEntity log1 = new LogEntity();
log1.setLogID(UUID.randomUUID().toString());
log1.setUserID(userID);
log1.setLoginDate(new Date());
LogEntity log2 = new LogEntity();
log2.setLogID(UUID.randomUUID().toString());
log2.setUserID(userID);
log2.setLoginDate(new Date());
Set<LogEntity> logs = new HashSet<LogEntity>();
logs.add(log1);
logs.add(log2);
user.setLogs(logs);
session.save(user);
session.getTransaction().commit();
} public void edt(){
session.beginTransaction();
Query query = session.createQuery("FROM UserEntity WHERE 1=1");
List<UserEntity> userList = query.list();
for (UserEntity userEntity : userList) {
userEntity.setPassWord("");
LogEntity log = new LogEntity();
log.setLogID(UUID.randomUUID().toString());
log.setUserID(userEntity.getUserID());
log.setLoginDate(new Date());
userEntity.getLogs().add(log);
session.update(userEntity);
}
session.getTransaction().commit();
} public void del(){
session.beginTransaction();
Query query = session.createQuery("FROM UserEntity WHERE 1=1");
List<UserEntity> userList = query.list();
for (UserEntity userEntity : userList) {
session.delete(userEntity);
}
session.getTransaction().commit();
} @Test
public void test(){
System.out.println("\n----------现有用户:");
sel();
System.out.println("\n----------开始增加用户:");
add();
System.out.println("\n----------增加用户后:");
sel();
System.out.println("\n----------开始修改用户:");
edt();
System.out.println("\n----------修改用户后:");
sel();
System.out.println("\n----------开始删除用户:");
del();
System.out.println("\n----------删除用户后:");
sel();
}
}

getSession和freeSession和上一章节中相同,不再赘述。

add方法,新建了一个用户并设定了两条登录日志,然后保存。edt方法,将所有用户的密码改为45666,并为所有的用户增加一条登录日志。del方法,删除所有的用户。sel方法,查询所有用户信息并输出到控制台。

右键,Run As JUnit Test后,控制台输出结果为:

 ----------现有用户:
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
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=?

 luych, 卢艳超, 12333, CB6172E3-8750-4718-BEF6-EE0917015FA9 登录日志:
2016-04-01 00:00:00
2016-04-08 00:00:00
2016-04-05 00:00:00
2016-04-02 00:00:00 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=?

 guest, 游客, 12333, 21539577-A3D1-4A1F-8D10-6ED0540A46A0 登录日志:
2016-04-11 00:00:00
2016-04-22 00:00:00 ----------开始增加用户:
Hibernate: select logentity_.logID, logentity_.loginDate as loginDat2_0_, logentity_.userID as userID3_0_
               from tbLog logentity_ where logentity_.logID=?
Hibernate: select logentity_.logID, logentity_.loginDate as loginDat2_0_, logentity_.userID as userID3_0_
               from tbLog logentity_ where logentity_.logID=?
Hibernate: insert into tbUser (loginName, passWord, userName, userID) values (?, ?, ?, ?)
Hibernate: insert into tbLog (loginDate, userID, logID) values (?, ?, ?)
Hibernate: insert into tbLog (loginDate, userID, logID) values (?, ?, ?)
Hibernate: update tbLog set userID=? where logID=?
Hibernate: update tbLog set userID=? where logID=? ----------增加用户后:
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

 luych, 卢艳超, 12333, CB6172E3-8750-4718-BEF6-EE0917015FA9 登录日志:
2016-04-01 00:00:00
2016-04-08 00:00:00
2016-04-05 00:00:00
2016-04-02 00:00:00 guest, 游客, 12333, 21539577-A3D1-4A1F-8D10-6ED0540A46A0 登录日志:
2016-04-11 00:00:00
2016-04-22 00:00:00 admin, 系统管理员, 12333, 99d5d264-9d02-4e45-a8c5-f710cc14107e 登录日志:
2016-04-26 17:06:00
2016-04-26 17:06:00 ----------开始修改用户:
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
Hibernate: select logentity_.logID, logentity_.loginDate as loginDat2_0_,
                      logentity_.userID as userID3_0_ 
               from tbLog logentity_ where logentity_.logID=?
Hibernate: select logentity_.logID, logentity_.loginDate as loginDat2_0_,
                      logentity_.userID as userID3_0_ 
               from tbLog logentity_ where logentity_.logID=?
Hibernate: select logentity_.logID, logentity_.loginDate as loginDat2_0_,
                      logentity_.userID as userID3_0_ 
               from tbLog logentity_ where logentity_.logID=?
Hibernate: insert into tbLog (loginDate, userID, logID) values (?, ?, ?)
Hibernate: insert into tbLog (loginDate, userID, logID) values (?, ?, ?)
Hibernate: insert into tbLog (loginDate, userID, logID) values (?, ?, ?)
Hibernate: update tbUser set loginName=?, passWord=?, userName=? where userID=?
Hibernate: update tbUser set loginName=?, passWord=?, userName=? where userID=?
Hibernate: update tbUser set loginName=?, passWord=?, userName=? where userID=?
Hibernate: update tbLog set userID=? where logID=?
Hibernate: update tbLog set userID=? where logID=?
Hibernate: update tbLog set userID=? where logID=? ----------修改用户后:
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

 luych, 卢艳超, 45666, CB6172E3-8750-4718-BEF6-EE0917015FA9 登录日志:
2016-04-01 00:00:00
2016-04-08 00:00:00
2016-04-05 00:00:00
2016-04-02 00:00:00
2016-04-26 17:06:00 guest, 游客, 45666, 21539577-A3D1-4A1F-8D10-6ED0540A46A0 登录日志:
2016-04-11 00:00:00
2016-04-22 00:00:00
2016-04-26 17:06:00 admin, 系统管理员, 45666, 99d5d264-9d02-4e45-a8c5-f710cc14107e 登录日志:
2016-04-26 17:06:00
2016-04-26 17:06:00
2016-04-26 17:06:00 ----------开始删除用户:
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
Hibernate: update tbLog set userID=null where userID=?
Hibernate: update tbLog set userID=null where userID=?
Hibernate: update tbLog set userID=null where userID=?
Hibernate: delete from tbLog where logID=?
Hibernate: delete from tbLog where logID=?
Hibernate: delete from tbLog where logID=?
Hibernate: delete from tbLog where logID=?
Hibernate: delete from tbLog where logID=?
Hibernate: delete from tbUser where userID=?
Hibernate: delete from tbLog where logID=?
Hibernate: delete from tbLog where logID=?
Hibernate: delete from tbLog where logID=?
Hibernate: delete from tbUser where userID=?
Hibernate: delete from tbLog where logID=?
Hibernate: delete from tbLog where logID=?
Hibernate: delete from tbLog where logID=?
Hibernate: delete from tbUser where userID=? ----------删除用户后:
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
 

从打印结果中,我们可以看到,新增、编辑、删除用户信息的时候,Hibernate都帮我们完成登录日志的新增、删除、操作。查询的时候也如此。

但是需要提点的是:在Hibernate第一次查询中,我们看到它先查询了tbUser表,然后针对tbUser表的每一个记录都又查询了下tbLog表,这就是经典的N+1查询问题,所以效率嘛…

以上就是Hibernate中一对多的查询关联,其他关联情况将在后续的博文中讲解。

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

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

    问:sql 中 select * from A left join B on A.id=B.id where A.id=? 如果在Hibernate 中 用HQL 怎么表达呢 ?答:from A le ...

  2. hibernate一对多查询

    一对多查询 1,同时添加老师和学生案例 在进行具有关联关系的对象同时添加时 首先绑定对像间的关系 ---将多方关联一方 ---将一方关联多方 然后全部添加 备注: 1,保存老师对象时, 由于设置了学生 ...

  3. Hibernate框架之Criteria查询 和注解(重点☆☆☆☆☆,难点☆☆☆)

    写好一篇博客,不是容易的事.原因是:你要给自己以后看的时候,还能看懂,最重要的是当别人看到你的博客文章的时候,也一样很清楚的明白你自己写的东西.其实这也是一种成就感!! 对于每一个知识点,要有必要的解 ...

  4. Hibernate(二)

    性能分析 抓取策略 研究对象 研究怎么样提取集合的,该策略应该作用与set元素上 研究从一的一方加载多的一方 案例 查询cid为1的班级的所有的学生 明:通过一条sql语句:左外链接,把classes ...

  5. Hibernate-ORM:15.Hibernate中的Criteria查询

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客讲师Hibernate中的Criteria查询! 一,Criteria简介: 刚接触Hibernate ...

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

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客将讲述Hibernate中的关联查询,及其级联(cascade)操作,以及指定哪一方维护关联关系的(i ...

  7. Hibernate框架之Criteria查询

    首先给大家说说Hibernate检索方式 Hibernate提供了5种检索对象的方式 1.导航对象图检索方式:根据已经加载的对象导航到其他对象 2.OID检索方式:按照对象的OID来检索对象 3.HQ ...

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

    今天没事的时候,看到公司框架里有一个用原生SQL写的函数,说实在以前自己也干过这事,但好久都没有用,都忘得差不多了,现在基本都是用的hql语句来查询结果.hibernate中使用createSQLQu ...

  9. Mybatis一对多查询得不到多方结果

    一对多查询:一个年级对应多个学生,现在要查询年级(带学生)信息. 查询结果: [main] INFO com.java1234.service.GradeTest - 查询年级(带学生)[main] ...

随机推荐

  1. Day7 - A - Visible Lattice Points POJ - 3090

    A lattice point (x, y) in the first quadrant (x and y are integers greater than or equal to 0), othe ...

  2. 京东首页如何实现pc端和移动端加载不同的html的?

    进入www.jd.com后代码判断是手机的话就跳转m.jd.com let ua = window.navigator.userAgent.toLocaleLowerCase() let murl = ...

  3. 反射①:如何获取class对象六种方法

    获取class对象的六种方法 了解:class类——是Java反射机制的入口,封装了一个类或接口的运行信息,通过调用Class类的方法可以获取这些信息,其特点如下: 1.该类在java.lang包中: ...

  4. C#获取屏幕分辨率率

    C#获取屏幕的分辨率   在C#中获取当前屏幕的分辨率的方法 1:rectangle类. 命名空间为:system.Drawing. system.Drawing.Rectangle rec=Scre ...

  5. URL短网址系统的算法设计及实践

    在通常情况下,URL是由系统生成的,通常包括URI路径,多个查询参数,可以对参数进行加密和解密.当人们要分享某个URL,比如短信,邮件,社交媒体,这就需要短URL. 而短网址,顾名思义就是在长度上比较 ...

  6. P1429 平面最近点对(加强版)(分治)

    P1429 平面最近点对(加强版) 主要思路: 分治,将点按横坐标为第1关键字升序排列,纵坐标为第2关键字升序排列,进入左半边和右半边进行分治. 设d为左右半边的最小点对值.然后以mid这个点为中心, ...

  7. S7-300 实训3 异步电机正反转控制

    含有视频 方便以后查阅 参考书籍 跟我动手学 S7-300/400 PLC 第2版  廖常初 主编 实训3 异步电动机 正反转控制 步骤1 步骤2 在 cycle execution 前方 右击 插入 ...

  8. 洛谷 P2049 魔术棋子(vector)

    题目传送门 解题思路: 用一个vector维护每一个点都可以乘出哪些数来,然后将(n,m)的所有数从小到大输出即可. 要用一个bool ff[j][k]来维护当前这个点(i,j)里面有没有被放过k,以 ...

  9. 【STM32H7教程】第52章 STM32H7的LTDC应用之点阵字体和字符编码(重要)

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第52章       STM32H7的LTDC应用之点阵字体和 ...

  10. Python 中使用动态创建类属性的机制实现接口之后的依赖

    我们在自动化测试中经常会需要关联用例处理,需要动态类属性: 推荐使用第二种方法: 创建:setattr() 获取:getattr() 两种,如何创建 类属性 loan_id # 第一种,创建 # 类名 ...