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 ...
随机推荐
- Xamarin.Forms中 Navigation,NavigationPage详解
1.Xamarin Forms下有四个成员类:Element,VisualElement,Page,NavigationPage 基类为Element,继承的子类分别是VisualElement,Pa ...
- jsonp的使用记录
最近前端的同事说要写一个手机查看的html5页面,需要我提供数据. 这个很ok啊,立马写了个服务返回数据.但是对方调用不了,因为跨域了. 返回错误如下: Failed to load xxxxxx: ...
- WPF 控件库——仿制Windows10的进度条
WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...
- centos 7 安装mysql5.6rpm格式
1查看是否安装了mysql rpm -qa|grep -i mysql 如果安装了请卸载:rpm -e --nodeps MySQL... 2.没有安装则进行如下操作 下载mysql rpm ta ...
- bitcoin script
P2PK P2PKH,MS,P2SH,OP_RETURN 等的区别 1.P2PK pay_to_public_key pubkey script: <pubkey> OP_CHECKSIG ...
- win7下安装numpy
OS: WIN7 32bit Python: 3.4 在以下网站下载: numpy-MKL-1.9.0.win32-py3.4.exe
- Django-05模型层之多表操作2
7.3 多表操作 一.创建模型 实例:我们来假定下面这些概念,字段和关系作者模型:一个作者有姓名和年龄.作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情模型和作者模型之 ...
- “全栈2019”Java第五十一章:继承与final关键字详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- Redis + Redis-sentinel + keepalived部署过程
1 Redis缓存服务 Redis是一个key-value存储系统.与memcached一样,为了保证效率,数据都是缓存在内存中的.区别的是redis支持周期性的把更新的数据写入磁盘或者把修改操作 ...
- [ActionScript 3.0] 结合FMS实现简单视频录制
首先在本机上安装Flash Media Server,简称FMS,在测试过程中window防火墙开启可能有影响,可先关闭防火墙,FMS安装好后检查相关服务有没有启动,若没有,可启动任务管理器,点击服务 ...