0 回顾
0.1 hibernate主键生成策略
自然主键:
assigned
代理主键:
identity
increment
native
hilo
sequence
uuid
0.2 hibernate基本查询
0.2.1 HQL
HQL:
session.createQuery(HQL);
Query
-list()
/uniqueResult()
setParameter(index/name, args);
setString/Int()
0.2.2 Criteria
Criteria:
session.createCriteria(class);
add(Restrictions.idEq(id)/eq("name", arg))
list/uniqueResult
0.2.3 SQL
SQL:
session.createSQLQuery(sql);
,API同QueryaddEntity(class)
-> 指定封装类型
0.3 hibernate事务
事务级别
- 读未提交、
- 读已提交、
- 可重复读、
- 串行化
开启事务:
- servicedao:执行sql,用到同一个session
- getCurrentSession()
property:current_session_context_class=thread
<!-- 配置session和当前线程绑定 "current_session_context_class" thread --> <property name="current_session_context_class">thread</property>
一、表关联的关系
- 1-n:在n的一方添加1的一方的主键作为外键
- n-n:需要第三张表存储各自外键
1.1 一对多(1-n)
1.1.1 添加关联关系
//
@Test
public void test01() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
// 1> 准备Customer对象
Customer c1 = new Customer();
c1.setCust_name("百度");
Customer c2 = new Customer();
c2.setCust_name("网易");
// 2> 准备Linkman对象
Linkman l1 = new Linkman();
l1.setLkm_name("老王");
Linkman l2 = new Linkman();
l2.setLkm_name("老张");
Linkman l3 = new Linkman();
l3.setLkm_name("老李");
Linkman l4 = new Linkman();
l4.setLkm_name("老刘");
// 3>添加关联关系
c1.getLinkmen().add(l1);
c1.getLinkmen().add(l2);
l1.setCustomer(c1);
l2.setCustomer(c1);
c2.getLinkmen().add(l3);
c2.getLinkmen().add(l4);
l3.setCustomer(c2);
l4.setCustomer(c2);
// 4> 将对象持久化
session.save(c1);
session.save(c2);
// cascade="save-update" 可以省略如下代码
// session.save(l1);
// session.save(l2);
// session.save(l3);
// session.save(l4);
// --------------------
tx.commit();
session.close();
}
1.1.1.1 被引用表(1表)配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="beans">
<class name="Customer" table="cst_customer" >
<id name="cust_id" >
<generator class="native" ></generator>
</id>
<property name="cust_name" ></property>
<property name="cust_source"></property>
<property name="cust_industry"></property>
<property name="cust_level"></property>
<property name="cust_phone"></property>
<property name="cust_mobile"></property>
<!-- 配置一对多关系 -->
<!-- set:表示一对多
|- name:多的一方属性名
|- inverse:是否放弃外键维护,
默认为"false",不放弃
true,放弃维护,只有 1的一方 才能放弃
|- cascade:级联操作选项
save-update:保存Customer的时候,自带的Linkman一起保存
delete:级联删除
all: save-update + delete
key - column:表示自己被别人引用的外键名
one-to-many - class:多的一方的引用类型
-->
<set name="linkmen" inverse="true" cascade="save-update">
<key column="lkm_cust_id"></key>
<one-to-many class="Linkman"/>
</set>
</class>
</hibernate-mapping>
- <font color="red">重点</font>
<set name="linkmen" inverse="true" cascade="save-update">
<key column="lkm_cust_id"></key>
<one-to-many class="Linkman"/>
</set>
属性辨析:
set
name
:多的一方属性名inverse
:是否放弃外键维护- 默认为"
false
",不放弃 true
,放弃维护,只有 1的一方 才能放弃
- 默认为"
cascade
:级联操作选项save-update
:保存Customer
的时候,自带的Linkman
一起保存delete
:级联删除all
:save-update
+delete
key
column
:表示<font color="red">自己被别人引用</font>的外键名
one-to-many
class
:多的一方的引用类型
1.1.1.2 被应用表(n表)配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="beans">
<class name="Linkman" table="cst_linkman" >
<id name="lkm_id" >
<generator class="native" ></generator>
</id>
<property name="lkm_name" ></property>
<property name="lkm_gender"></property>
<property name="lkm_phone"></property>
<property name="lkm_mobile"></property>
<property name="lkm_email"></property>
<property name="lkm_qq"></property>
<property name="lkm_position"></property>
<property name="lkm_memo"></property>
<!-- 配置多对一关系 -->
<!-- many-to-one:
|- name:引用一的一方的属性名
|— column:外键字段
|- class:外键对应类型是什么
-->
<many-to-one name="customer" column="lkm_cust_id" class="Customer" ></many-to-one>
</class>
</hibernate-mapping>
- <font color="red">重点</font>
<!-- 配置多对一关系 -->
<!-- many-to-one:
|- name:引用一的一方的属性名
|— column:外键字段
|- class:外键对应类型是什么
-->
<many-to-one name="customer" column="lkm_cust_id" class="Customer" ></many-to-one>
属性辨析
many-to-one
name
:引用1的一方的属性名column
:外键字段class
:外键对应类型
1.1.2 删除操作
// 删除客户1
@Test
public void test02() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
// 1> 查找id为1的客户对象
Customer customer = session.get(Customer.class, 2l);
System.out.println(customer.getLinkmen());
// 2> 删除customer对象
session.delete(customer);
// 所关联的联系人一起删掉:cascade=delete
// --------------------
tx.commit();
session.close();
}
//----------------------------------
// 删除客户2,保留他原先的联系人
@Test
public void test03() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
// 1> 查找id为1的客户对象
Customer customer = session.get(Customer.class, 2l);
System.out.println(customer.getLinkmen());
// 2> 取消关联关系 - 外键
for (Linkman lk : customer.getLinkmen()) {
lk.setCustomer(null);//手动取消
}
// 3> 删除customer对象
session.delete(customer);
// --------------------
tx.commit();
session.close();
}
1.2 多对多(n-n)
1.2.1 添加用户、角色/权限
@Test
// 添加用户、角色/权限
public void test01() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
// 1> 准备User对象
User u1 = new User();
u1.setUser_code("zhangsan");
u1.setUser_name("张三");
User u2 = new User();
u2.setUser_code("lucy");
u2.setUser_name("露西");
// 2> 准备Role对象
Role r1 = new Role();
r1.setRole_name("经理");
Role r2 = new Role();
r2.setRole_name("保安");
// 3>添加关联关系
u1.getRoles().add(r1);
u1.getRoles().add(r2);
u2.getRoles().add(r1);
u2.getRoles().add(r2);
r1.getUsers().add(u1);
r1.getUsers().add(u2);
r2.getUsers().add(u1);
r2.getUsers().add(u2);
// 4> 将对象持久化
session.save(u1);
session.save(u2);
// session.save(r1);
// session.save(r2);
// --------------------
tx.commit();
session.close();
}
1.2.2 添加新的权限
@Test
// 给lucy添加新的权限
public void test02() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
// 1> 获得lucy对象
User lucy = session.get(User.class, 2l);
// 2> 新建新的权限
Role role = new Role();
role.setRole_name("财务");
// 3> 设置关联关系
lucy.getRoles().add(role);
role.getUsers().add(lucy);
// 4> 保存role
session.save(role);
// --------------------
tx.commit();
session.close();
}
1.2.3 删除权限
@Test
// 给张三删除 除了保安以外的权限
public void test03() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
// 1> 获得张三对象
User user = session.get(User.class, 1l);
// 2> 获得经理对象
Role role = session.get(Role.class, 1l);
// 3> 从张三中删除经理
user.getRoles().remove(role);
role.getUsers().remove(user);
// HashSet 删除原理 hashCode equals(Role 和 User必须重写equals和hashCode放法)
// --------------------
tx.commit();
session.close();
}
1.2.4 中间表的配置文件
User
表
<!-- 多对多关系 -->
<!-- set: 多对多
|- name: 包含的属性名
|- table: 第三张表
key:
|- column: 别人引用“我”的外键名 - 第三张表中
many-to-many:
|- class: 包含的属性对应的完整类名
|- column: “我”引用别人的外键
-->
<set name="roles" table="sys_user_role" cascade="save-update">
<key column="user_id"></key>
<many-to-many class="Role" column="role_id"></many-to-many>
</set>
- Role表
<!-- 多对多哪方放弃外键维护,都可以
业务角度来说,是后添加的来维护外键
-->
<set name="users" table="sys_user_role" inverse="true">
<key column="role_id"></key>
<many-to-many class="User" column="user_id"></many-to-many>
</set>
总结:<font color="red">set属性中多了table属性,中间表的表名</font>
外键维护:
- 一对多元素添加的时候,外键添加了两次,说明外键被双方维护
- 减少不必要的外键维护,<font color="red">一定需要有一方放弃外键维护</font>
inverse="true"
,减少不必要的sql语句
级联操作:减少java代码书写
cascade
save-update
delete
all
二、查询总结
2.1 oid查询 - get/load
- 根据主键查询
2.2 对象属性导航查询 - customer.getLinkmen()
- 通过查询结果的属性进行导航查询
2.3 HQL
2.3.1 查询全部
- HQL语句:
from com.ruki.crm.Customer
@Test
public void test01() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
// String hql = "from Customer"; // 简化写法:工程中只有唯一的Custoemr类
// from Customer - hql:*不能用
String hql = "from beans.Customer"; // 完整写法
// String hql = "from java.lang.Object"; // 查询所有对象
// select cust_id, cust_name from cst_customer
// 查询出来的结果,每条记录都封装成一个Object数组
String hql1 = "select cust_id, cust_name from Customer";
// 要求:有对应的构造器
String hql2 = "select new Customer(cust_id, cust_name) from Customer";
Query query = session.createQuery(hql2);
List list = query.list();
System.out.println(list);
// --------------------
tx.commit();
session.close();
}
<font color="red">重点步骤</font>
写HQL语句:
- 查询所有的完整写法:
String hql = "from beans.Customer";
查询含特定字段的
Customer
对象:String hql2 = "select new Customer(cust_id, cust_name) from Customer";
- <font color="red">前提是必须要有有参构造器</font>
- 查询所有的完整写法:
- 传入HQL语句,生成
Query
对象。Query query = session.createQuery(hql2);
Query
对象,返回查询结果。List list = query.list();
2.3.2 条件查询
- 在HQL语句中添加
where
条件即可
2.3.3 分页查询
@Test
// 分页查询
public void test02() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
String hql = "from Linkman";
Query query = session.createQuery(hql);
// 设置分页显示 最开始条数、每页显示条数
// select * from cst_customer limit 0, 2;
query.setFirstResult(0); // startRow 从0开始
query.setMaxResults(2); // pageSize
List list = query.list();
System.out.println(list);
// --------------------
tx.commit();
session.close();
}
2.3.4 聚合函数
@Test
// 聚合函数
public void test03() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
// select count(*) from cst_customer
// select count(cust_id) from Customer
String hql = "select count(cust_id) from Customer";
Query query = session.createQuery(hql);
Number count = (Number) query.uniqueResult();
System.out.println(count);
// --------------------
tx.commit();
session.close();
}
<font color="red">重点步骤</font>
HQL语句的编写,在原生sql语句中进行改进
-- 原生sql select count(*) from cst_customer -- HQL select count(cust_id) from Customer
2.3.5 表链接(关联查询)
关联查询的sql语句
-- 内连接 -- 隐式内连接:等值链接 select * from cst_customer c,cst_linkman l where c.cust_id = l.lkm_cust_id -- 显示内连接: select * from cst_customer c [inner] join cst_linkman l on c.cust_id = l.lkm_cust_id -- 左外 select * from cst_customer c [outer] left join cst_linkman l on c.cust_id = l.lkm_cust_id -- 右外 select * from cst_customer c [outer] right join cst_linkman l on c.cust_id = l.lkm_cust_id
2.3.5.1 迫切内连接
from Customer c join fetch c.linkmen
fetch
将返回结果包装成对象
2.3.5.2 迫切左外连接
from Customer c left join fetch c.linkmen
2.3.5.3 迫切右外连接
from Customer c right join fetch c.linkmen
@Test
public void test05() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
// String hql = "from Customer c join fetch c.linkmen";
// String hql = "from Customer c left join fetch c.linkmen";
String hql = "from Customer c right join fetch c.linkmen";
Query query = session.createQuery(hql);
List list = query.list();
System.out.println(list);
// --------------------
tx.commit();
session.close();
}
2.3.6 排序
@Test
// 排序
public void test04() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
String hql = "from Customer order by cust_id desc";
Query query = session.createQuery(hql);
List list = query.list();
System.out.println(list);
// --------------------
tx.commit();
session.close();
}
2.4 Criteria(没有HQL和SQL语句)
2.4.1 查询全部
- 没有添加任何条件,即为查询全部。
@Test
// 查询全部
public void test01() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
Criteria criteria = session.createCriteria(Customer.class);
List list = criteria.list();
System.out.println(list);
// --------------------
tx.commit();
session.close();
}
2.4.2 条件查询
- 添加条件:
criteria.add(Restrictions.le("lkm_id", 9l));
@Test
// 条件查询全部
/*
* = eq(属性名,值)
* > gt(属性名,值)
* >= ge
* < lt
* <= le
* <> ne
* in in(属性名,集合)
* between and between(属性名,值1,值2)
* like like
* is null isNull
* is not null isNotNull
* or or(条件1,条件2,条件3...)
* and add/and
* select * from cst_linkman where lkm_name like '%李%' or lkm_id > 8
*/
public void test06() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
Criteria criteria = session.createCriteria(Linkman.class);
criteria.add(Restrictions.le("lkm_id", 9l))
.add(
Restrictions.or(
Restrictions.like("lkm_name", "%李%"),
Restrictions.gt("lkm_id", 8l)));
List list = criteria.list();
System.out.println(list);
// --------------------
tx.commit();
session.close();
}
2.4.3 分页查询
- 设置起始数据位置:
criteria.setFirstResult(0);
- 设置最大查询数量:
criteria.setMaxResults(2);
@Test
// 分页查询
public void test02() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
Criteria criteria = session.createCriteria(Customer.class);
criteria.setFirstResult(0);
criteria.setMaxResults(2);
List list = criteria.list();
System.out.println(list);
// --------------------
tx.commit();
session.close();
}
2.4.4 聚合函数
- 添加聚合函数字段:
criteria.setProjection(Projections.rowCount());
@Test
// 聚合函数
public void test03() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
Criteria criteria = session.createCriteria(Customer.class);
// select count(*) from customer where id>5;
// Projections
criteria.setProjection(Projections.rowCount());
// criteria.add(arg0)
List list = criteria.list();
criteria.uniqueResult();
System.out.println(list);
// --------------------
tx.commit();
session.close();
}
2.4.5 排序
- 添加排序规则:
criteria.addOrder(Order.desc("cust_id"));
@Test
// 排序
public void test04() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// --------------------
Criteria criteria = session.createCriteria(Customer.class);
// criteria添加排序规则
criteria.addOrder(Order.desc("cust_id"));
List list = criteria.list();
System.out.println(list);
// --------------------
tx.commit();
session.close();
}
2.5 Criteria离线查询(在session前添加条件)
- 创建离线
Criteria
对象:DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
- 添加条件:
dc.add(Restrictions.like("cust_name", "%李%"));
@Test
public void test01() {
// 模拟web层/service
// 凭空创造Criteria对象
DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
// dc拼接条件的用法和Criteria完全一样
dc.add(Restrictions.like("cust_name", "%李%"));
List<Customer> list = findCustomerByCriteria(dc);
System.out.println(list);
}
// 条件的拼接,以后可以在web层、也可以在service层
// 问题 Criteria 和 session绑定
// session最大范围,service层
// web层拼接条件 提供了离线版Criteria对象
// 模拟dao
public List<Customer> findCustomerByCriteria(DetachedCriteria dc) {
Session session = HibernateUtils.openSession();
Criteria criteria = dc.getExecutableCriteria(session);
return criteria.list();
}
2.6 SQL查询
- 写SQL语句:
String sql = "select * from cst_customer where cust_name=?";
- 获得
SQLQuery
对象:SQLQuery sqlQuery = session.createSQLQuery(sql);
- 设置查询参数:
sqlQuery.setParameter(0, "阿里巴巴");
- 获得结果集:
Customer customer = (Customer) sqlQuery.uniqueResult();
- <font color="red">具体代码见Hibernate_02笔记中的5.3部分</font>
三、查询优化策略
3.1 类级别:懒加载
lazy
-true
/false
- 默认
true
- 默认
get
- 不存在查询优化策略,查的时候直接获得结果load
- 查询时,得到代理对象- 使用对象的时候,才真正查询,获得内容
3.2 表关联级别
fetch
:select
:默认,单表查询join
:关联查询subselect
:子查询
lazy:
true
:默认,懒加载false
:关闭懒加载extra
:及其懒惰
- 结论:优化策略使用默认值
package test;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.junit.Test;
import beans.Customer;
import utils.HibernateUtils;
public class QueryDemo {
@Test
public void test01() {
Session session = HibernateUtils.openSession();
Customer customer = session.load(Customer.class, 3l);
System.out.println(customer);
}
@Test
// fetch: select - 单表查询 (默认)
// lazy: true - 懒加载 (默认)
// false - 立即加载(查父表时,子表同步查询)
// extra - 极其懒惰,用到什么数据,查什么数据
public void test02() {
Session session = HibernateUtils.openSession();
Customer customer = session.load(Customer.class, 3l);
System.out.println(customer);
System.out.println(customer.getLinkmen().size());
System.out.println(customer.getLinkmen());
}
@Test
// fetch: join - 关联查询
// lazy: 失效
public void test03() {
Session session = HibernateUtils.openSession();
Customer customer = session.load(Customer.class, 3l);
System.out.println(customer);
System.out.println(customer.getLinkmen().size());
System.out.println(customer.getLinkmen());
}
@Test
// fetch: subselect - 子查询
// lazy: true
public void test04() {
Session session = HibernateUtils.openSession();
String sql = "from Customer";
Query query = session.createQuery(sql);
List<Customer> list = query.list();
for (Customer c : list) {
System.out.println(c);
System.out.println(c.getLinkmen().size());
System.out.println(c.getLinkmen());
}
}
}