hibernate 学习笔记2
1.Criteria查询接口适用于组合多个限制条件来搜索一个查询集。
要使用Criteria,需要遵循以下步骤:
*创建查询接口: Criteria criteria=session.createCriteria(User.class);
*设置查询条件: criteria.add(Restrictions.gt(“age”,10);
*查询数据: List<User> list=criteria.list();
2.关系映射:一个用户(cust_customer)对应多个联系人(cust_linkman)
*在CustCustomer.hbm.xml中配置
<!--设置与多方的联系-->
<!--
name:javabean中set集合的名称
key:column:外键名称
one-to-many class:set集合中类的全路径-->
<set name="linkMans">
<!--外键-->
<key column="lkm_cust_id"/>
<!--对应关系-->
<one-to-many class="edu.whu.swe.lxl.learn.hibernate.model.CstLinkman"/>
</set>
*在CustLinkman.hbm.xml中配置
<!--设置一对多-->
<!--
name:javabean的属性名
class:属性的类的全名
column:外键名-->
<many-to-one name="customer" class="edu.whu.swe.lxl.learn.hibernate.model.CustCustomer" column="lkm_cust_id"/>
3.双向关联:既保存主表,也保存从表
*java代码:
public void testBathDirectSave(){
// 新建一个用户和多个联系人
CustCustomer customer=new CustCustomer();
customer.setCustName("马蓉");
CstLinkman lkm1 = new CstLinkman();
lkm1.setLkmName("强哥");
CstLinkman lkm2 = new CstLinkman();
lkm2.setLkmName("小宋");
// 双向关联
// 客户关联联系人
customer.getLinkMans().add(lkm1);
customer.getLinkMans().add(lkm2);
// 联系人关联客户
lkm1.setCustomer(customer);
lkm2.setCustomer(customer);
session.save(customer);
session.save(lkm1);
session.save(lkm2);
}
*SQL输出:
**Hibernate:
insert
into
cust_customer
(cust_name, cust_user_id, cust_create_id, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
**Hibernate:
insert
into
cst_linkman
(lkm_name, lkm_gender, lkm_phone, lkm_mobile, lkm_email, lkm_qq, lkm_position, lkm_memo, lkm_cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
**Hibernate:
insert
into
cst_linkman
(lkm_name, lkm_gender, lkm_phone, lkm_mobile, lkm_email, lkm_qq, lkm_position, lkm_memo, lkm_cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
**Hibernate:
update
cst_linkman
set
lkm_cust_id=?
where
lkm_id=?
**Hibernate:
update
cst_linkman
set
lkm_cust_id=?
where
lkm_id=?
可以看到,双向保存时,对从表其实是做了更新操作的。
4.级联保存:级联保存只需要保存一方关系,多方关系会自动保存。先测试只保存主表:
*配置:通过在一方关系的hbm.xml中配置set的cascade属性为save-update,从而使得多方关系中的Javabean从Transient状态自动转为Persistent态。
<set name="linkMans" cascade="save-update">
<!--外键-->
<key column="lkm_cust_id"/>
<!--对应关系-->
<one-to-many class="edu.whu.swe.lxl.learn.hibernate.model.CstLinkman"/>
</set>
*java代码:
public void testSingleDirectSave(){
// 新建一个用户和多个联系人
CustCustomer customer=new CustCustomer();
customer.setCustName("马蓉1");
CstLinkman lkm1 = new CstLinkman();
lkm1.setLkmName("强哥1");
CstLinkman lkm2 = new CstLinkman();
lkm2.setLkmName("小宋1");
// 单向关联
// 只需要客户关联联系人
customer.getLinkMans().add(lkm1);
customer.getLinkMans().add(lkm2);
// 不需要联系人关联客户
// 只需要保存客户,联系人由框架自动保存
session.save(customer);
}
*SQL操作:
**Hibernate:
insert
into
cust_customer
(cust_name, cust_user_id, cust_create_id, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
**Hibernate:
insert
into
cst_linkman
(lkm_name, lkm_gender, lkm_phone, lkm_mobile, lkm_email, lkm_qq, lkm_position, lkm_memo, lkm_cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
**Hibernate:
insert
into
cst_linkman
(lkm_name, lkm_gender, lkm_phone, lkm_mobile, lkm_email, lkm_qq, lkm_position, lkm_memo, lkm_cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
**Hibernate:
update
cst_linkman
set
lkm_cust_id=?
where
lkm_id=?
**Hibernate:
update
cst_linkman
set
lkm_cust_id=?
where
lkm_id=?
这种方法虽然java代码中只需要单项保存就可以了,但是仍然先对多方从表进行insert操作后在进行update操作,一共有5次SQL操作。
5.级联保存,将级联保存配置在从表,在java中也只进行从表的保存操作。这种方法可以减少SQL语句。
*配置,同样,也需要在多端的hbm.xml中配置cascade属性为save-update:
<many-to-one name="customer"
class="edu.whu.swe.lxl.learn.hibernate.model.CustCustomer"
column="lkm_cust_id" cascade="save-update"/>
*Java代码:
public void
testSingleDirectInManySave(){
// 新建一个用户和多个联系人
CustCustomer customer=new
CustCustomer();
customer.setCustName("马蓉2");
CstLinkman lkm1 = new CstLinkman();
lkm1.setLkmName("强哥2");
CstLinkman lkm2 = new CstLinkman();
lkm2.setLkmName("小宋2");
// 单向关联
// 这是只关联联系人,而不对客户方进行操作
lkm1.setCustomer(customer);
lkm2.setCustomer(customer);
// 不需要联系人关联客户
// 只保存联系人,客户由框架自动保存
session.save(lkm1);
session.save(lkm2);
}
*SQL语句:
**Hibernate:
insert
into
cust_customer
(cust_name, cust_user_id,
cust_create_id, cust_source, cust_industry, cust_level, cust_linkman,
cust_phone, cust_mobile)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
**Hibernate:
insert
into
cst_linkman
(lkm_name, lkm_gender, lkm_phone,
lkm_mobile, lkm_email, lkm_qq, lkm_position, lkm_memo, lkm_cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
**Hibernate:
insert
into
cst_linkman
(lkm_name, lkm_gender, lkm_phone,
lkm_mobile, lkm_email, lkm_qq, lkm_position, lkm_memo, lkm_cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
可以看到,这种在多端执行级联保存的方式,没有进行update操作,而是一步到位只进行insert操作,减少数据库的读写。
6.cascade设置有以下几种:
1)all: 包含出了delete-orphan外的所有情况,即save-update和delete。
2)none: 所有情况下均不进行关联操作。这是默认值。
3)save-update:
在执行save/update/saveOrUpdate时进行关联操作。
4)delete: 在执行delete 时进行关联操作。
5)delete-orphan: 孤儿删除,只能配置在一端。在delete的基础之上,当需要把外键设置为null时,直接删除外键对应的多端,一般用以对remove的支持。
6)all-delete-orphan:
当一个节点在对象图中成为孤儿节点时,删除该节点。
我们使用得是save-update,当执行级联保存操作时,如果相关联的对象在表中没有记录,则会一起save,即执行insert SQL操作,如果有(说明在快照区有相关联的对象的副本),则看是否发生改变,在觉得是否update相关联的对象。
所谓孤儿,只有在一对多的情况中才存在,指的是一端已经没有了,多端还有一些存在,它的外键是null。
7. inverse设置是否让主表来update从表的值来,且只对save和update有效。
这个是我比较难理解的一个点。
inverse的值是boolean值,也就是能设置为true或false。 如果一方的映射文件中设置为true,说明在映射关系(一对多,多对多等)中让从表自己来维护外键值。如果为false,就主表来设置从表的外键值。默认值是false,也就是会去update从表的外键值。
并且这属性只能在一端设置(inverse是set的属性)。比如一对多,这个一端。也就是在有set集合的这方设置。
维护关系:维护什么关系呢?包括两个方面
1、也就是维护外键的关系了,通俗点讲,就是哪一方去设置这个被外键约束的字段的值。就拿上面这个例子来说,cust_customer和cst_linkman两张表不管进行什么操作,只要关系到了另一张表,就不可避免的要操作外键字段,比如,linkman查询自己所对应的客户,就得通过被外键约束的字段值到customer中的主键中查找,如果customer想查询自己有哪些联系人,就得拿着自己的主键值跟linkman中的外键字段做比较,找到相同的值则是属于自己的联系人。
这个是查询操作,
现在如果是添加操作呢,linkman表中添加一条记录,并且对应于customer表中的一个客户,linkman中有被外键约束修饰的字段,那是通过CstLinkman(java)的insert语句就对这个外键字段赋值,还是让CustCustomer(java)对象使用update语句对其赋值呢,两个都能对这个外键字段的值进行操作,谁去操作呢?如果不做设置,两个都会操作,就出现了上面说的这种有5次SQL操作的情况(对于linkman表,有两次insert是有CstLinkman发出的,还有两次update是有CustCustomer发出的)。虽然不会出现问题,但是会影响性能。其实只需要CstLinkman发出的两次insert就可以插入两条联系人记录了。如果让对方维护外键关系,则自己这方就不维护了。
2、维护级联的关系,就是cascade的那几种设置了。
如果在一端的CustCustomer.hbm.xml中加入set的inverse=”true”属性,这时候无论在java中执行哪方的保存,都不会出现多余的update SQL操作,说明一端(主表)不会去维护外键关系,而只有让从表去维护。再次强调,inverse不影响是否级联操作,只是设置谁来维护外键的值。很多文章都误以为是设置cascade是否有效,这是错误的,误导人。
但是,inverse不是乱设置的,inverse如果设置为true,那么一端是不会去维护外键的值的,它会留给多端去维护,但如果多端没有通过setCuster()方法来设置相应的外键值,则为java类属性默认值Null,此时外键的值就会为null。所以一定要记得为从表的对象也设置好外键值。
由此可以看出,hibernate的级联保存方式,指的是如何发送SQL语句,而不会对java对象本身的赋值行为执行任何的操作,对任何java对象的赋值,都需要程序员自己去执行。
Hibernate唯一能自动对java对象赋值的操作是查询操作。
参考文献:https://www.cnblogs.com/whgk/p/6135591.html
8.在级联删除中,应把cascade=delete级联配置在一端,如果配置在多端,可能会导致多端数据删除不赶紧,留下孤点数据,原因如下:
当delete配置在多端时,则由多端去维护delete的一致性,所以当删除多端的某一条数据时,级联删除通过外键值查询到一端表的主键,找到对应的记录,并把这个记录删除。删除一端的数据之后,数据库如果设置的外键约束是 on delete set null,则留下了孤点数据。
而且,根据一般的业务逻辑,也应该是删除了一端数据之后,才删除所有的多端记录。而删除某一个多端记录时,是不需要级联删除一端的数据的。举个例子:建筑-房间是一对多关系,删除了多端的房间,是不需要整栋建筑的。但是建筑如果删除了,房间自然就不存在了,所有的房间都应该被删除。所以delete应该配置在一端。
9.delete和delete-orphan的区别,stackoverflow上已经有人说的很明白了:
Cascade DELETE
means if this entity is deleted, delete the related entity or entities.
DELETE_ORPHAN
means if an entity is removed from a related one-to-many collection, then not
only disassociate it from the current entity, but delete it.
To give you an
example, consider two entities: House and Room.
DELETE on the
Room list on House means that if you delete the House then delete all it's
Rooms.
DELETE_ORPHAN on
the Room list on House means if you remove a Room from that collection, delete
it entirely. Without it, the Room would still exist but not be attached to
anything (hence "orphan").
In UML and OO
modelling terms, this is basically the difference between composition and
aggregation. The House->Room relationship is an example of composition. A
Room is part of a House and doesn't exist independently.
An example of
aggregation is, say, Class (parent) to Student (child). Delete the Class and
the Student still exists (undoubtedly in other classes). Removing the Student
from the Class doesn't typically mean deleting him or her.
大致的意思就是,delete只在删除一端的记录时,会删除多端的所有记录;而delete-orphan在当处于持久态的一端对象对他的set执行了remove时,会删除所remove的多端对象对应的从表记录。
在UML中,delete和delete-orphan的使用场景分别是“聚合”和“组成”。学生-班级关系是“聚合”,因此学生允许孤儿(没有班级),所以使用delete比较合理。建筑-房间关系是“组成”,如果一栋建筑没有了某个房间,那么这栋房间就不存在了,也就说说房间是不可能是脱离建筑的孤儿,所以当一个房间从建筑中remove时,就应该把房间从从表中删除,所以使用delete-orphan比较合适。
值得注意的是,delete-orphan包括了delete的效果。
参考:https://stackoverflow.com/questions/1377585/what-is-the-difference-between-delete-orphan-and-delete
总结:级联保存通常配置在多端(从表),级联删除配置在一端(主表)delete-orphan或delete。这样做的好处是:
1)当保存数据时,只需要设置多端(从表)的外键属性值并保存多端,主表会通过级联保存自动保存,因为主表无需维护外键,因此可以无需设置主表的set值,让它为null就行。
2)当删除时,通过删除主表来删除一端记录,并且级联删除所有的关联的多端(从表)记录。
3)删除多端(从表)的某一记录之后,主表不受影响,可以防止因主表级联删除之后,引起从表中其他记录的外键为null,甚至因no action或restrict而导致无法级联删除主表记录(与预期不一致)。
4)如果要通过一端(主表)来级联保存从表,也可以在一端(主表)中配置级联保存,并把reverse=true设置打开,此时,虽然不用手动session.save()多端对象(从表记录),但是需要在java代码中手动设置从表的外键值,否则外键的值为null。另外,在一端执行remove之后,也不会对多端执行delete操作(因为一端不去维护外键了);如果要让一端(主表)来维护从表的外键值,则reverse=false(默认就是false),这样在级联保存从表记录(inset)之后,还会发出update SQL来维护从表的外键值,这样会降低程序的性能。
hibernate 学习笔记2的更多相关文章
- Hibernate学习笔记(二)
2016/4/22 23:19:44 Hibernate学习笔记(二) 1.1 Hibernate的持久化类状态 1.1.1 Hibernate的持久化类状态 持久化:就是一个实体类与数据库表建立了映 ...
- Hibernate学习笔记(一)
2016/4/18 19:58:58 Hibernate学习笔记(一) 1.Hibernate框架的概述: 就是一个持久层的ORM框架. ORM:对象关系映射.将Java中实体对象与关系型数据库中表建 ...
- Hibernate 学习笔记一
Hibernate 学习笔记一 今天学习了hibernate的一点入门知识,主要是配置domain对象和表的关系映射,hibernate的一些常用的配置,以及对应的一个向数据库插入数据的小例子.期间碰 ...
- Hibernate学习笔记-Hibernate HQL查询
Session是持久层操作的基础,相当于JDBC中的Connection,通过Session会话来保存.更新.查找数据.session是Hibernate运作的中心,对象的生命周期.事务的管理.数据库 ...
- Hibernate学习笔记
一.Hibernate基础 1.Hibernate简介 Hibernate是一种对象关系映射(ORM)框架,是实现持久化存储的一种解决方案.Java包括Java类到数据库表的映射和数据查询及获取的方法 ...
- Hibernate学习笔记(四)
我是从b站视频上学习的hibernate框架,其中有很多和当前版本不符合之处,我在笔记中进行了修改以下是b站视频地址:https://www.bilibili.com/video/av14626440 ...
- Hibernate学习笔记(三)
我是从b站视频上学习的hibernate框架,其中有很多和当前版本不符合之处,我在笔记中进行了修改以下是b站视频地址:https://www.bilibili.com/video/av14626440 ...
- HIbernate学习笔记(一) 了解hibernate并搭建环境建立第一个hello world程序
Hibernate是一个开放源代码的ORM(对象关系映射)框架,它对JDBC进行了轻量级的封装,Java程序员可以使用面向对象的编程思维来操纵数据库,它通过对象属性和数据库表字段之间的映射关系,将对象 ...
- Hibernate学习笔记-Hibernate关系映射
1. 初识Hibernate——关系映射 http://blog.csdn.net/laner0515/article/details/12905711 2. Hibernate 笔记8 关系映射1( ...
- Hibernate学习笔记(1)Hibernate构造
一 准备工作 首先,我们将创建一个简单的基于控制台(console-based)Hibernate应用. 我们所做的第一件事就是创建我们的开发文件夹.并把所有需要用到的Java件放进去.解压缩从Hib ...
随机推荐
- [修正] Firemonkey 中英文混排折行,省略字符,首字避开标点
问题:FMX 在移动平台的文字显示并非由该平台的原生 API 来显示,而是由 FMX.TextLayout.GPU 来处理,也许是官方没留意到中文字符的问题,造成在中英文混排折行时,有些问题. 修正: ...
- 利用PhotoShop对大图像进行等分切片
图文介绍利用PhotoShop等分切图 1.调用切片工具,右键选择划分切片 2.指定水平划分.垂直划分的等分数量,点击确定 3.在文件菜单中选择存储为... 4.配置图像质量参数.点击存储.指定存储位 ...
- oracle通过job执行procedure
1. 先创建一个FUNCTION CREATE OR REPLACE FUNCTION GET_TIMEOUT_PROGRAM(i_customerNo IN TK_CUST_PROG_D.CUSTO ...
- Ubuntu 安装 Memcached
直接使用命令 sudo apt-get install Memcached 进行安装 安装完, 默认只能本地连接,需要修改一下配制文件,打开 /etc/Memcached.conf 文件, 找到一个 ...
- 贝塞尔曲线 WPF MVVM N阶实现 公式详解+源代码下载
源代码下载 效果图: 本程序主要实现: N阶贝塞尔曲线(通用公式) 本程序主要使用技术 MVVM InterAction 事件绑定 动态添加Canvas的Item 第一部分公式: n=有效坐标点数量 ...
- 4.client、offset、scroll系列
client.offset.scroll系列 他们的作用主要与计算盒模型.盒子的偏移量和滚动有关 clientTop 内容区域到边框顶部的距离 ,说白了,就是边框的高度 clientLeft 内容区域 ...
- jQuery动态数字翻滚计数到指定数字的文字特效代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- “全栈2019”Java第七章:IntelliJ IDEA注释快捷键
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- Servlet实现禁用cookie重写URL获取session
前言 一个女人让他的程序员丈夫去商店买东西:你去附近的商店买些鸡蛋,如果有香蕉的话,买8个回来,这个丈夫买了8个鸡蛋回来,他的妻子大吃一惊:你为什么买了8个鸡蛋?! 程序员丈夫回答:因为他们有香蕉. ...
- [Swift]在Swift中实现自增(++)、自减(--)运算符:利用extension扩展Int类
自增(++).自减(--)运算符主要用在For循环中,Swift有自己更简易的循环遍历方法,而且类似x- ++x这种代码不易维护. Swift为了营造自己的编码风格,树立自己的代码精神体系,已经不支持 ...