hibernate课程安排
第一天:hibernate入门和基本操作
第二天:hibernate概念和api使用
第三天:hibernate配置一对多和多对多
第四天:hibernate查询操作
第一天内容简介:
1、web内容回顾
(1)javaee三层结构
(2)mvc思想
2、hibernate概述
3、hibernate框架入门案例
4、hibernate配置文件
5、hibernate最基本的api使用
web内容回顾:
javaEE有三层结构
1、web层:struts2框架
2、service层:spring框架
3、dao层:hibernate框架
(1)对数据库进行crud操作
MVC思想
1、m:model,模型
2、v:view,视图
3、c:controller,控制器
Hibernate概述
什么是框架
1、写一个程序,使用框架之后,帮我们实现一部分的功能,使用框架的好处在于少写一部分代码实现功能。
什么是hibernate框架(重点)
1、Hibernate的意思是冬眠,应用在JavaEE三层结构的dao层框架
2、在dao层里面做对数据库crud操作,Hibernate底层代码就是jdbc,Hibernate对jdbc进行封装,使用Hibernate好处,不需要写复杂的jdbc代码了,不需要写sql语句实现。
3、Hibernate开源轻量级框架
4、Hibernate版本:
Hibernate3.x
Hibernate4.x
Hibernate5.x
lib:hibernate相关jar包
什么是ORM思想
1、Hibernate使用ORM思想对数据库进行CRUD操作
2、在Web阶段学习javabean,更正确的叫法——实体类
3、ORM:Object Relational Mapping,对象关系映射
文字描述:
(1)让实体类与数据库表一一对应的关系
让实体类首先与数据库表对应
让实体类属性和表里面的字段对应
(2)不需要直接操作数据库表,而操作表对应实体类对象
画图描述:
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//创建连接
Connection conn = DriverManager.getConnection(url,username,password);
//对sql进行预编译操作
String sql = "select * from user";
PreparedStatement psmt = conn.preparedStatement(sql);
//执行sql 查询sql
ResultSet rs = pstm.executeQuery();
//遍历结果集
......
//释放资源
......
public class User{
private int uid;
private String username;
private String password;
//setter getter
}
create table t_user(
uid int,
username varchar(100),
password varchar(100)
);
让实体类User与表t_user一一对应
让类和表对应,让类属性和表字段对应。使用配置文件方式完成这种对应关系。不需要操作表,而操作表对应的实体类对象就可以了。hibernate封装的对象session。
//创建实体类对象
User user = new User();
user.setUsername("lucy");
session.save(user);
Hibernate的入门
搭建一个Hibernate环境
第一步:导入Hibernate的Jar包
注意,required文件夹下的jar包必须添加,jpa文件夹下的jar包也必须添加
(1)因为使用hibernate时候,会有一些日志信息输出,hibernate本身没有日志输出的jar包,导入其他日志的jar包,不要忘记还有mysql驱动的jar包。
log4j-x.x.x.jar
mysql-connector-java-x.x.x-bin.jar
slf4j-api-x.x.x.jar
slf4j-log4j12-x.x.x.jar
第二步 创建实体类
(1)使用hibernate时候,不需要自己手动创建表,hibernate帮助创建表
第三步 配置实体类和数据库表一一对应关系(映射关系)
使用配置文件来实现映射关系
(1)使用xml格式的配置文件
映射配置文件名称和位置没有固定要求
建议:在实体类所在包里面创建,实体类名称.hbm.xml
(2)配置文件是xml格式,在配置文件中首先引入xml约束
学过的约束dtd、schema,在hibernate中引入的约束dtd约束
(3)配置映射关系
<hibernate-mapping>
<!-- 1 配置类和表对应
class标签
name属性:实体类全路径
table属性:数据库表名称
-->
<class name="cn.itcast.entity.User" table="t_user">
<!-- 2 配置实体类id和表id对应
hibernate要求实体类有一个属性值唯一值
hibernate要求表有字段作为唯一值
-->
<!-- id标签
name属性:实体类里面id属性名称
column属性:生成的表字段名称
-->
<id name="uid" column="uid">
<!-- 设置数据库表id增长策略
native:生成表id值就是主键自动增长
-->
<generator class="native"></generator>
</id>
<!-- 配置其他属性和表字段对应
name属性:实体类属性名称
colume属性:生成表字段名称
-->
<property name="username" column="username"></property>
<property name="password" column="password"></property>
<property name="address" column="address"></property>
</class>
</hibernate-mapping>
第四步 创建hibernate核心的配置文件
(1)核心配置文件的格式xml,但是核心配置文件的名称和位置是固定的。
位置:必须在src下
名称:必须hibernate.cfg.xml
(2)引入dtd约束
(3)hibernate操作过程中,只会加载核心配置文件,其他配置文件不会加载
第一部分 配置数据库的信息
第二部分 配置Hibernate的信息
第三部分 把映射文件放到核心的配置文件中
<hibernate-configuration>
<session-factory>
<!-- 第一部分 配置数据库信息 必须要有-->
<property name="hibernate.connection.driver.class">com.mysql.cj.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">ljh_5098_CHD</property>
<!-- 第二部分 配置hibernate信息 可选的 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<!-- hibernate帮创建表,需要配置之后
update:如果已经有表,更新,如果没有,创建
-->
<property name="hdm2ddl.auto">update</property>
<!-- 配置数据库方言
在mysql里面实现分页 关键词limit,只能使用mysql里面
在oracle数据库中,实现分页rownum
让hibernate框架识别不同数据库特有的语句
-->
<property name="hibernate.dialect"></property>
<!-- 第三部分 把映射文件放到核心的配置文件中 必须的 -->
<mapping resource="cn/itcast/entity/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
实现添加操作
第一步 加载hibernate核心配置文件
第二步 创建SessionFactory对象
第三步 使用SessionFactory创建session对象
第四步 开启事务
第五步 写具体逻辑crud操作
第六步 提交事务
第七步 关闭资源
看到的效果:
(1)是否生成表(2)是否添加记录
public class HibernateDemo {
public static void main(String[] argv){
//第一步 加载hibernate核心配置文件
//到src下面找到hibernate.cfg.xml
//在hibernate里面封装对象
Configuration cfg = new Configuration();
cfg.configure();
//第二步 创建SessionFactory对象
//读取hibernate核心配置文件内容,创建SessionFactory
//在该过程之中,根据映射关系创建表
SessionFactory sessionFactory=cfg.buildSessionFactory();
//第三步 使用SessionFactory创建session对象
//类似于连接
Session session = sessionFactory.openSession();
//第四步 开启事务
Transaction tx = session.beginTransaction();
//第五步 写具体逻辑crud操作
//添加功能
User user = new User();
user.setUsername("LJH");
user.setPassword("5098");
user.setAddress("China");
//调用session
session.save(user);
//第六步 提交事务
tx.commit();
//第七步 关闭资源
session.close();
sessionFactory.close();
}
}
hibernate配置文件详解
hibernate映射配置文件
1、映射配置文件名称和位置没有固定要求
2、映射配置文件中,标签name属性值写实体类相关内容
(1)class标签name属性值实体类全路径
(2)id标签和property标签name属性值 实体类属性名称
3、id标签和property标签,column属性可以省略
(1)不写值和name属性值一样
4、property还有一个type属性,设置生成表字段的类型,缺省时会自动对应属性。
hibernate核心配置文件
1、配置写的位置要求
<hibernate-configuration>
<session-factory>
</session-factory>
</hibernate-configuration>
2、配置三部分要素
(1)数据库部分是必须的
(2)hibernate部分是可选的
(3)映射文件是必须的
3、核心配置文件名称和位置是固定的
(1)位置:src下
(2)名称:hibernate.cfg.xml
hibernate核心api
Configuration
1、代码
Configuration cfg = new Configuration();
cfg.configure();
(1)到src下面找到名称为hibernate.cfg.xml配置文件,创建对象,把配置文件放到对象里面(加载核心配置文件)
(2)还有其他几种配置方法,一般不使用
SessionFactory(重点)
1、使用Configuration对象可以创建SessionFactory对象
(1)创建sessionFactory过程中做事情
根据核心配置文件中,有数据库配置,有映射文件部分,到数据库中根据映射关系建表,但必须指定update。
2、创建sessionFactory过程中,这个过程非常耗资源。
(1)在hibernate操作中,建议一个项目一般创建一个sessionFactory对象
3、具体实现
(1)写工具类,写静态代码块实现
静态代码块在类加载时候执行,执行一次
public class HibernateUtils {
private static final Configuration cfg;
private static final SessionFactory sessionFactory;
//静态代码块实现
static{
//加载核心配置文件
Configuration cfg = new Configuration();
cfg.configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
}
//提供方法返回sessionFactory
public static SessionFactory getSessionFactory(){
return sessionFactory;
}
}
Session(重点)
1、session类似于jdbc中connection
2、调用session里面不同的方法实现crud操作
(1)添加save方法
(2)修改update方法
(3)删除delete方法
(4)根据id查询get方法
3、session对象单线程对象
(1)不可共享只能独占
Transaction
1、事务对象
Transaction tx = beginTransaction();
2、事务提交和创建方法
tx.commit();
tx.rollback();
3、事务相关的概念
(1)事务四个概念ACID
原子性:事务中的操作不可分割
一致性:执行事务前后数据库状态不变
隔离性:不同事务相互独立,互不干扰
持久性:事务一经提交永久修改
解决配置文件没有提示的问题
1、可以上网
2、把约束文件引入项目
在Intelij idea中打开File->Settings,搜索xml catalog;
复制dtd约束文件的uri
第二天内容简介
1、实体类编写规则
2、hibernate主键生成策略
3、实体类中的操作
(1)crud操作
(2)实体类对象状态
4、hibernate一级缓存
5、hibernate事务操作
(1)事物代码的规范写法
6、hibernate的其他api
实体类的编写规则
1、属性私有
2、私有属性get/set方法公有
3、要求有一个属性作为唯一值
4、实体类里面的属性建议不使用基本数据类型,使用基本数据类型对应的包装类
(1)八个基本数据类型对应的包装类
int-Integer
char-Character
其他-首字母大写
(2)比如 表示学生的分数,假如int score
如果学生得了0分 int score = 0;
如果学生没有参加考试 int score = 0的写法不能准确表示这种情况
解决:使用包装类就可以,Integer score = null表示学生没有参加考试
hibernate主键生成策略
1、hibernate要求实体类中有一个属性作为唯一的值,对应表主键,主键可以有不同生成策略
2、hibernate主键生成策略
3、在class属性里面有很多值
(1)native:根据数据库类型灵活选择identity、sequence、hilo
(2)uuid:hibernate运用uuid算法生成一个32位十六进制字符串唯一标识一个元组
4、演示生成策略值uuid
(1)使用uuid的生成策略,实体类id属性必须是字符串类型
(2)配置部分修改为uuid策略
实体类操作
对实体类crud操作
添加操作
1、调用session中的save方法
//添加功能
User user = new User();
user.setUsername("QQX");
user.setPassword("5100");
user.setAddress("UK");
//调用session
session.save(user);
根据id查询
1、调用session里面的get方法
//根据id做查询
//调用session中的get方法
//第一个参数:实体类的Class
//第二个参数:id值
User user = session.get(User.class,1);
System.out.println("user = " + user);
底层查询语句
Hibernate:
select
user0_.uid as uid1_0_0_,
user0_.username as username2_0_0_,
user0_.password as password3_0_0_,
user0_.address as address4_0_0_
from
user user0_
where
user0_.uid=?
修改操作
1、首先查询,修改值
(1)先根据id查询,后返回
//修改操作
//根据id进行查询
User user = session.get(User.class,2);
//向返回的User对象中设置值
user.setUsername("YP");
//调用session的方法update修改
session.update(user);
//到user对象中找到uid的值,根据uid进行修改
底层SQL语句
Hibernate:
select
user0_.uid as uid1_0_0_,
user0_.username as username2_0_0_,
user0_.password as password3_0_0_,
user0_.address as address4_0_0_
from
user user0_
where
user0_.uid=?
Hibernate:
update
user
set
username=?,
password=?,
address=?
where
uid=?
删除操作
1、调用session里面的delete方法实现
第一种方式:
//第一种方式:先查后删
User user = session.get(User.class,2);
session.delete(user);
Hibernate:
select
user0_.uid as uid1_0_0_,
user0_.username as username2_0_0_,
user0_.password as password3_0_0_,
user0_.address as address4_0_0_
from
user user0_
where
user0_.uid=?
Hibernate:
delete
from
user
where
uid=?
第二种方式:
//第二种方式:先创建对象再删除
User user = new User();
user.setUid(3);
session.delete(user);
Hibernate:
delete
from
user
where
uid=?
注意,使用update修改时,所有属性都会被修改。
实体类对象的状态(概念)
1、实体类的状态有三种
(1)瞬时态,对象里面没有id值,对象与session没有关系
User user = new User();
user.setUsername("QQX");
user.setPassword("5100");
user.setAddress("UK");
(2)持久态,对象里面有id值,对象与session也有关系
User user = session.get(User.class,1);
(3)托管态,对象里面有id值,对象与session无关
User user = new User();
user.setUid(3);
2、演示操作实体类对象的方法
(1)saveOrUpdate方法,实现添加或修改
//saveOrUpdate
User user = new User();
user.setUsername("LB");
user.setPassword("520");
user.setAddress("France");
//实体类对象是瞬时态时做添加操作
session.saveOrUpdate(user);
User user = new User();
user.setUid(2);
user.setUsername("LB");
user.setPassword("520");
user.setAddress("France");
//实体类对象是托管态,做修改操作
session.saveOrUpdate(user);
User user = session.get(User.class,1);
user.setUsername("ZC");
//实体类对象是持久态,做修改操作
session.saveOrUpdate(user);
Hibernate的一级缓存
什么是缓存?
1、数据存到数据库里面,数据库的底层存储介质就是文件系统,使用流方式操作文件效率不高
(1)把数据存到内存中,不需要使用流方式,可以直接读取内存中数据
(2)把数据存到内存中,提供读取效率
Hibernate缓存
1、Hibernate框架中提供很多优化方式,hibernate中的缓存就是一种优化的方式
2、hibernate缓存特点
第一类 hibernate中的一级缓存
(1)hibernate的一级缓存默认就是打开的
(2)hibernate中的一级缓存使用范围,是session范围。
session.beginTransaction();
...(session范围)
session.close();
(3)hibernate的一级缓存中,存储数据必须持久态数据
第二类 hibernate中的二级缓存
(1)目前已经不使用,替代技术redis
(2)二级缓存默认不是打开状态,需要配置
(3)二级缓存的适用范围是sessionFactory范围
验证一级缓存的存在
1、验证的方式
(1)首先根据uid=1查询,返回对象
(2)其次再根据uid=1查询,返回对象
//测试一级缓存
//执行第一个查询后有SQL语句输出
User user = session.get(User.class,1);
System.out.println("user = " + user);
//执行第二个查询后没有SQL语句输出
User user2 = session.get(User.class,1);
System.out.println("user2 = " + user2);
输出结果:
Hibernate:
select
user0_.uid as uid1_0_0_,
user0_.username as username2_0_0_,
user0_.password as password3_0_0_,
user0_.address as address4_0_0_
from
user user0_
where
user0_.uid=?
user = User{uid=1, username='ZC', password='456', address='England'}
user2 = User{uid=1, username='ZC', password='456', address='England'}
结论:第一次查询使用SQL语句,第二次执行get方法之后没有执行sql语句而是访问一级缓存中的内容。
Hibernate一级缓存执行过程
第一次查询:查询一级缓存发现没有数据,查询数据库,返回持久态对象并将其放到一级缓存中。
第二次查询:从一级缓存中直接返回持久态对象。
注意:两次返回的并不是同一个对象。
hibernate一级缓存的特性
1、持久态对象会自动更新数据库
User user=session.get(User.class,1);
user.setUsername(“张三”);
//session.update(user);
执行过程:
把返回的持久态对象放到一级缓存中
把持久态对象放到一级缓存对应的快照区中
修改持久态对象的值,同时修改一级缓存中内容,但不会修改一级缓存对应的快照区
最后要提交事务时,比较一级缓存与一级缓存对应快照区的内容,如果不相同,把一级缓存中的内容更新到数据库中。
Hibernate事务操作
1、什么是事务?
2、事务特性ACID
3、不考虑隔离性产生的问题:
(1)脏读
(2)不可重复读
(3)虚读(幻读)
4、设置事务隔离级别
(1)MySQL默认隔离级别repeatable read
(2)Hibernate中事务的管理
在hibernate核心配置文件中配置:
Hibernate事务代码的规范写法
1、代码结构
try{
开启事务
提交事务
}catch(异常){
回滚事务
}finally{
关闭事务
}
代码
Hibernate绑定线程session
1、session类似于jdbc的connection,之前在web阶段学习过threadLocal
2、帮助用户实现本地线程绑定session
3、获取与本地线程绑定session
(1)在hibernate配置文件中配置
(2)调用sessionFactory里面的方法得到
4、获取与本地线程绑定的session变量后,不再需要关闭了,否则就会报错
Hibernate中一些api的使用
Query对象
1、使用Query对象不需要写SQL语句,但是要写HQL语句
(1)hql:Hibernate Query Language
(2)hql与sql相似,但有区别
sql操作的是表和字段,hql操作实体类和实体类里面的属性
2、查询所有的hql语句
(1)from 实体类名称
3、query对象的使用
(1)创建一个Query对象
(2)调用Query对象的方法得到结果
Criteria对象
1、使用Criteria对象查询操作,不用写查询语句,直接调用方法实现
2、实现过程
(1)创建Criteria对象
(2)调用Criteria对象的方法得到结果
SQLQuery对象
1、使用hibernate时候,调用底层的SQL语句来实现
2、实现过程
(1)创建SQLQuery对象
(2)调用对象的方法得到结果,结果以数组list的形式返回
(3)返回list每一项是对象
表与表之间的关系回顾
1、一对多
(1)分类和商品之间的关系,一个分类中可以有多个商品,一个商品中只能有一个分类
(2)客户与联系人是一对多的关系
客户:与公司有业务往来
联系人:公司员工分别负责联系不同的客户
(3)一对多关系,“多”的一方创建字段作为外键,存储“一”的一方的主键,参照数据库知识
2、多对多
(1)订单和商品之间的关系是多对多,一个订单中有多个商品,一个商品可以出现在订单中
(2)多对多关系,创建中间表
3、一对一
(1)配偶
hibernate的一对多操作
一对多映射配置
以客户与联系人为例,客户是一,联系人是多
第一步:创建实体类,客户与联系人
第二步:让这两个实体类之间先互相进行表示
(1)在客户实体类里面表示多个联系人
一个客户里面有多个联系人
(2)在联系人实体类里面表示所属的客户
第三步:配置映射关系
(1)一般一个实体类都要对应一个映射文件
(2)把映射最基本的部分完成
(3)在映射文件中配置一对多的关系
在客户映射文件中,表示所有的联系人
在联系人映射文件中表示所有的客户
一个联系人只能属于一个客户
第四步:在核心配置文件中引用实体类的配置文件
测试:
一对多的级联操作
级联操作
1、级联保存
2、级联删除
一对多级联保存:
1、添加客户,为客户添加一个联系人
(1)复杂写法
测试结果:
(2)简化写法
一般根据客户添加联系人
第一步 在客户映射文件中进行配置
在客户映射文件中set标签上进行配置
第二步 创建客户和联系人对象,把联系人放到客户中即可,最终只需要保存客户就行了
一对多级联删除
1、删除某个客户,把客户里面的所有联系人都删除
2、具体实现
第一步 在客户的映射文件中set标签,进行配置
(1)使用属性cascade值为delete
第二步 在代码中删除客户
(1)根据id查询对象
(2)根据外键的id值查询联系人
(3)把联系人的外键设为NULL
(4)删除联系人与客户
一对多修改
1 让联系人所属客户不再是baidu而是tencent
2 inverse属性
(1)LinkMan被修改了两次。因为hibernate双向维护外键,当修改联系人时修改了一次外键,当修改客户时又修改了一次外键。
(2)解决方式:让其中一方放弃外键的维护
一对多里面,让“一”的一方(也就是客户)放弃外键
一个国家有总统和平民,总统不可能认识所有平民,平民都认识总统
(3)具体实现
在放弃外键维护的一方的配置文件中进行配置,在set标签上使用inverse属性,默认为false表示不放弃,将其设置为true
hibernate多对多的操作
多对多映射配置
以用户与角色为例演示
第一步 创建实体类,用户和角色
第二步 让两个实体类之间互相表示
(1)用户里边表示所有的角色,使用set集合
(2)一个角色中有多个用户,使用set集合
第三步 配置映射关系
(1)配置基本关系
(2)配置多对多关系
- 在用户中表示所有相关的角色,使用set标签
- 在角色中表示所有相关的用户,使用set标签
第四步 在核心配置文件中引入配置文件
测试
多对多级联保存
根据用户保存角色
第一步 在用户配置文件中set标签进行配置,cascade属性值设为save-update
第二步 写代码实现
(1)创建用户和角色对象,把角色放到用户里面,最终保存用户就可以了
多对多级联删除
第一步 在set标签中进行配置,cascade属性值中添加delete
第二步 删除对象
注意:了解即可,一般不使用
维护中间表
1、用户和角色是多对多的关系,通过中间表维护
2、让某个用户具备某种角色
第一步 根据id查询用户和角色
第二步 把角色放到用户的set集合中
3、让某个用户不再具备某种角色
第一步 根据id查询用户和角色
第二步 把角色从用户的set集合中移除
hibernate查询方式
1、对象导航查询
(1)根据id查询客户,再根据客户查询所有的联系人
2、OID查询
(1)根据id查询某一条记录,返回对象
3、hql查询
(1)创建Query对象,写HQL语句
4、QBC查询
(1)创建Criteria对象
5、本地sql查询
(1)创建SQLQuery对象,写SQL语句
对象导航查询
1 查询某个客户里面所有联系人过程,使用对象导航过程
2 代码
OID查询
1 根据id查询记录
(1)调用session里面的get方法
HQL查询
1 hql = hibernate query language
hibernate提供一种数据库查询语言,hql语言yusql语言很相似
区别:普通SQL语句操作的是数据库表和字段,hql语句操作的是实体类和属性
2 常用的hql语句
(1)查询所有:from 实体类名称
【注意】是实体类名称,不是实体类对象名称,也不是数据库表名称
(2)条件查询:from 实体类名称 where 属性名称=? and 属性名称=?
(3)排序查询:from 实体类名称 order by 属性名称 asc/desc
3 使用hql语句查询操作的时候,使用Query对象
(1)创建Query对象,写hql语句
(2)调用Query对象方法得到查询结果
查询所有
1 查询所有的客户记录
(1)创建Query对象,写hql语句
(2)调用Query对象方法得到查询结果
2 查询所有:from 实体类名称
条件查询
1 hql条件查询的语句写法
(1)from 实体类名称 where 实体类属性名称=? and 实体类属性名称=?
from 实体类名称 where 实体类属性名称 like ?
2 代码
【注意】新版本HQL占位符:?0 ?1 ?2 …
使用setParameter方法
引用别名必须在前面加冒号
3 字符串匹配查询
排序查询
1 hql排序语句写法
(1)from 实体类名称 order by 属性名称 asc/desc
2 代码
分页查询
1 mysql实现分页
(1)使用limit关键字
sql语句 SELECT * FROM t_customer LIMIT 0,50
2 hql实现分页
(1)在hql语句中不能使用limit关键字
3 分页操作
投影查询
1 投影查询
2 投影查询的hql语句写法
(1)select 属性名称列表 from 实体类名称
(2)select后面不支持*
3 代码
聚集函数的使用
1 常用的聚集函数
(1)count sum max min avg
2 hql聚集函数的写法
(1)查询表记录数
select count(*) from 实体类名称
QBC查询
1 使用hql查询需要写hql查询语句,使用qbc不需要写查询语句,使用方法实现
2 使用qbc时,操作的是实体类对象和属性
3 使用qbc需要首先创建Criteria对象
查询所有
1 创建JPA 的CriteriQuery对象
2 调用CriteriaQuery对象方法配置查询条件
3 根据CriteriaQuery对象创建Criteria对象
4 调用方法得到结果
条件查询
排序查询
分页查询
统计查询
离线查询
HQL实现多表查询
HQL多表查询
(1)内连接
(2)左外连接
(3)右外连接
(4)迫切内连接
(5)迫切左外连接
HQL内连接
1 内连接查询hql语句写法
(1)from Customer c inner join c.linkManSet
返回List,List里面每一个元素都是一个数组
2 演示迫切内连接
(1)迫切内连接的底层实现与内连接一样
(2)区别:使用内连接返回List中每一个元素都是一个数组,使用迫切内连接返回List每一个元素都是对象
(3)hql语句写法:
from Customer c inner join fetch c.linkManSet
HQL左外连接
1 左外连接的hql语句写法
(1)左外连接:from Customer c left outer join c.linkManSet
(2)迫切左外连接:from Customer c left outer join fetch c.linkManSet
Hibernate检索策略
检索策略的概念
1 hibernate检索策略分为两类
(1)立即查询 根据id查询,调用get方法,一调用get方法马上发送语句查询数据库
(2)延迟查询 根据id查询,还有load方法,调用load方法不会,马上发送语句查询数据,只有得到对象里面的值时才会发送语句查询数据库。
2 延迟查询又分为两类
(1)类级别的延迟:根据id查询返回实体类,调用load方法不会马上发送语句
(2)关联级别的延迟:
查询某个客户,再查询这个客户的所有联系人,查询客户所有联系人的过程是否需要延迟。这个延迟就称为关联级别的延迟。
关联级别的延迟操作
1 在映射文件中进行配置
(1)根据客户得到所有的联系人,在客户的映射文件中进行配置
2 在set标签上使用属性
(1)fetch:值select
(2)lazy:值
- true:延迟(默认),要什么就从数据库读取全部数据
- false:不延迟
- extra:极其延迟,要什么就给什么,绝不读取不要的数据,及其懒惰
批量抓取
1 查询所有的客户,返回list集合,遍历list集合,得到每个客户的所有联系人
发送了很多次SQL语句
2 在客户的配置文件中的set标签中配置batch-size属性
只发送了一次sql语句
补充:采用注解方式配置实体类
//1 一对多关系
@Entity//实体类
@Table(name="t_customer")//数据库表名称
public class Customer {
@Id//主键
@GeneratedValue(strategy=GenerationType.IDENTITY)//主键生成策略
@Column(name="cid")//数据库表字段名称
private Integer cid;
@Column(name="cust_name")
private String custName;
@Column(name="cust_level")
private String custLevel;
@Column(name="cust_source")
private String custSource;
@Column(name="cust_phone")
private String custPhone;
@Column(name="cust_mobile")
private String custMobile;
//一对多关系的配置
//targetEntity表示关联实体类
//@Cascade用于配置级联操作
@OneToMany(targetEntity=LinkMan.class,mappedBy="customer")
@Cascade({CascadeType.SAVE_UPDATE,CascadeType.DELETE})
private Set<LinkMan> linkManSet = new HashSet<LinkMan>();
//省略get、set、toString方法
}
@Entity
@Table(name="t_linkman")
public class LinkMan {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="lkm_id")
private Integer lkmId;
@Column(name="lkm_name")
private String lkmName;
@Column(name="lkm_gender")
private String lkmGender;
@Column(name="lkm_phone")
private String lkmPhone;
//配置一对多的关联
@ManyToOne(targetEntity=Customer.class,cascade= {CascadeType.PERSIST,CascadeType.REMOVE})
//配置外键,name表示外键数据库表字段名
@JoinColumn(name="clid")
private Customer customer;
//省略get、set、toString方法
}
//2 多对多关系
@Entity
@Table(name="t_role")
public class Role {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="role_id")
private Integer roleId;
@Column(name="role_name")
private String roleName;
@Column(name="role_memo")
private String roleMemo;
//配置多对多关联,targetEntity是关联的实体类
@ManyToMany(targetEntity=cn.ljh.hibernate.entity.User.class)
//配置中间表,name表示中间表的名称,joinColumns表示本实体类在中间表的外键,inverseJoinColumns表示其他实体类在中间表的外键
@JoinTable(
name="t_user_role",
joinColumns={
//配置外键,name是在中间表中的字段名,referencedColumnName是被外键引用的字段名
@JoinColumn(name="role_id",referencedColumnName="role_id")},
inverseJoinColumns={
//配置外键,name是在中间表中的字段名,referencedColumnName是被外键引用的字段名
@JoinColumn(name="user_id",referencedColumnName="user_id")}
)
//配置级联操作
@Cascade(CascadeType.SAVE_UPDATE)
private Set<User> userSet=new HashSet<>();
}
@Entity
@Table(name = "t_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Integer userId;
@Column(name = "user_name")
private String userName;
@Column(name = "user_password")
private String userPassword;
//配置多对多关联,targetEntity表示关联实体类,
//mappedBy表示放弃维护外键,指定在其他实体类中被引用的属性名
@ManyToMany(targetEntity = cn.ljh.hibernate.entity.Role.class, mappedBy = "userSet")
private Set<Role> roleSet = new HashSet<>();
}
//3 一对一关系
@Entity
@Table(name="t_id_card")
public class IdCard {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="i_id")
private Integer iId;
@Column(name="i_name")
private String iName;
@Column(name="i_gender")
private String iGender;
@Column(name="i_address")
private String iAddress;
//配置一对一关系
@OneToOne(targetEntity=StudentCard.class)
//配置外键,name表示外键的数据库字段名
@JoinColumn(name="stu_id")
//配置级联操作
@Cascade(CascadeType.SAVE_UPDATE)
private StudentCard studentCard;
//省略get、set、toString方法
}
@Entity
@Table(name="t_student_card")
public class StudentCard {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="stu_id")
private Integer stuId;
@Column(name="stu_name")
private String stuName;
@Column(name="stu_class")
private Integer stuClass;
//配置一对一关系并放弃维护外键
@OneToOne(targetEntity=IdCard.class,mappedBy="studentCard")
private IdCard idCard;
//省略get、set、toString方法
}
//主键映射是另一种一对一关系的配置方法,但实际开发中不经常使用,
//具体做法是将上面的OneToOne中的targetEntity删除,
//将@JoinColumn改为@PrimaryKeyJoinColumn即可。