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 ...
随机推荐
- DELPHI XE5/6/7 android 无线真机调试
一.下载adbWireless 地址:http://sj.zol.com.cn/detail/41/40834.shtml 安装,需要ROOT权限. 运adbWireless.界面很简单,就一个大按钮 ...
- 基于SSH的网上购物商城系统-JavaWeb项目-有源码
开发工具:Myeclipse/Eclipse + MySQL + Tomcat 项目简介: 基于WEB的网上购物系统主要功能包括:前台用户登录退出.注册.在线购物.修改个人信息.后台商品管理等等.本系 ...
- RobotFramework的Setup和Teardown
测试套件级别的Setup会在本套件测试用例集合执行前先执行,同理Teardown会在本组所有用例执行完成后运行 测试用例级别的Setup会在本条测试用例执行前先执行,同理Teardown会在本条用例执 ...
- python的reflect反射方法
核心内容专自:http://www.liujiangblog.com/course/python/48 在自动化测试的时候,需要从excel中读取关键字,此关键字对应一个方法,如何使用该关键字去调用真 ...
- 创建第一个MVC专案--初识MVC
MVC1.0正式版2009就上市了,可自己今年才开始去接触,汗颜~ 自己在学的过程中也看过一些文章,很多都是大致介绍的没有连接数据库实现下操作,直至自己买了本后发现MVC有很强大的数据库操作类已封装好 ...
- performance checklist
- embree integration 0w - uncompressed bvh nodes ...
- shell脚本小实例
本文收集了一堆的shell脚本技巧,我说过,我写博客主要是作一些学习笔记,方便自己查阅,所以,我会搞出这么一篇文章,也没有什么不可理解的.关于这些技巧的出处,诶,我也忘了,可能来自theunixsch ...
- 「HNOI 2013」游走
题目链接 戳我 \(Solution\) 首先申明几个变量: f[x]:到点x的概率, vis[x]:x点的度 dp[x][y]:(x,y)这条边的概率 number[x][y]:x这条边的编号 下面 ...
- drf序列化器serializers.SerializerMethodField()的用法
问题描述: 为什么DRF中有时候返回的json中图片是带域名的,有时候是不带域名的呢? 解析: 带域名的结果是在view中对模型类序列化的,DRF在序列化图片的时候 会检查上下文有没有request, ...
- Linux常用运维指令
cd data/apps./=========================================== ps -ef | grep tomcatps -ef | grep desktopX ...