hibernate的中的查询与级联操作

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来维护从表的外键值,这样会降低程序的性能。

原文地址:https://www.cnblogs.com/JMLiu/p/9530005.html

时间: 2024-11-06 03:45:56

hibernate的中的查询与级联操作的相关文章

hibernate中关系操作(inverse)和级联操作(cascade)详解

以用户.角色.用户文件为例讲解inverse(关系操作)和(cascade)操作 inverse 取值 true(不维护关系)或false(维护关系  默认为false) 该属性主要操作的是外键 cascade 取值null(默认值).save-update .all .delete 用户.角色是多对多的关系 用户的映射文件表示: <hibernate-mapping> <class name="com.xing.elec.domain.ElecUser" table

【SSH三大框架】Hibernate基础第九篇:cascade关联关系的级联操作

这里要说的是Hibernate的关联关系的级联操作,使用cascade属性控制. 依旧用部门和员工举例.多个员工相应一个部门(多对一关联关系) 员工类:Employee.java package cn.itcast.hibernate.domain; public class Employee { private int id; private String name; private Department depart; public int getId() { return id; } pu

Hibernate级联操作和加载机制(二) cascade and fetch

上一篇介绍了Hibernate持久化对象时候的级联操作,本篇介绍读取时候的级联操作. 还是用上一篇的例子,一份问卷有多个问题,但是每个问题只能属于一份问卷.我们先看测试用例: @Test public void testReadFromQuestionnaire(){ Session session = sessionFactory.getCurrentSession(); session.beginTransaction(); Questionnaire qn = (Questionnaire

Hibernate HQL中的子查询

子查询是SQL语句中非常重要的功能特性,它可以在SQL语句中利用另外一条SQL语句的查询结果,在Hibernate中HQL查询同样对子查询功能提供了支持. 如下面代码所示: List list=session.createQuery("from Customer c where 1<(select count(o) from c.orders o)").list(); 上面的程序查询订单数超过1的所有客户,因此和上面子查询HQL语句对应的SQL语句为: Select * from

Hibernate(八)__级联操作、struts+hibernate+接口编程架构

级联操作 所谓级联操作就是说,当你进行主对象某个操作时,从对象hibernate自动完成相应操作. 比如: Department <---->Student 对象关系,我希望当我删除一个department ,那么就自动删除该部门的所有学生. 再比如: bbs项目主帖<---->回帖 , 把主帖删除,那我们就希望把该主帖的回帖自动删除,这样我们可以使用级联(cascade)操作. 案例:如何配置级联操作,当删除某个部门的时候,我们自动删除其学生. 首先我们在配置文件中修改: <

【Hibernate学习】——级联操作

级联策略:负责控制关联两端对象到对象的级联关系的操作,包括更新.删除等,也就是说对一个对象进行更新.删除时,其它对象也受影响,比如我删除一个对象,那么跟它是多对一关系的对象也全部被删除. 在前面用了抓取策略之后,后面试了一下级联操作的注解:cascadeType.MERGE方式 @OneToOne(cascade={CascadeType.MERGE}) @JoinColumn(name="company_id") publicCompany getCompany() { return

Hibernate级联操作解密(inverse和cascade)

总结: Cascade:对级联操作进行限制,有如下几个参数: all : 所有情况下均进行关联操作.  none:所有情况下均不进行关联操作.这是默认值.  save-update:在执行save/update/saveOrUpdate时进行关联操作.  delete:在执行delete时进行关联操作. Inverse:在一对多模型中,只能在一的一方设置,inverse的作用就是在级联发生后,会再次更新子表数据的外键为主表的主键.确保子表外键不会为空. 下面演示一个班级学生的例子(一对多): 班

使用hibernate作为底层,jquery实现级联操作(附带oracle数据库)

原文:使用hibernate作为底层,jquery实现级联操作(附带oracle数据库) 源代码下载地址:http://www.zuidaima.com/share/1564685226675200.htm 为了减轻压力,项目中的hibernate jar包已经删除.请自行增加即可正常运行.若没有jar包请在官方群:南京-木木-11187  或者私信我索要. 备注:数据库在项目根目录的db文件夹下,双击run.bat即可导入.(PS:请用文本文档打开看下用户名和密码是否和你的一致.)如果出现不懂

Hibernate的Cascade——级联操作

在Hibernate中,针对持久化实体的配置文件中有Cascade这样一个属性,顾名思义就是级联,也就是说在操作当 前实体时,针对当前实体的操作会影响到相应配置的关联实体.比如针对当前实体进行保存操作时,会同时保存 与其关联的实体,当然这种额外操作的产生取决于你是否在当前实体的配置文件中对关联实体的元素配置了 Cascade属性. 而需要进行级联的操作可能涉及到增加,修改,删除等相应的数据库操作,具体Cascade的取值则 分为多种,如all,表示针对所有操作都会进行级联,如save-updat