hibernate学习之第十篇

news/2024/7/3 8:39:28

级联和关系维护
Cascade 用来说明当对主对象进行某种操作时,是否对其关联的从对象也作类似的操作,常用的cascade:none,all,save-update,delete,lock,refresh,evict,replicate,persist,merge,delete-orphan(one-to-many).一般对many-to-many,many-to-many不设置级联,在<one-to-one>和<one-to-one>中设置级联。

inverse表示“是否放弃维护关联关系 ”(在java里两个对象产生关联时,对数据库表的影响),在one-to-many和many-to-many的集合定义中使用,inverse=“true”表示该对象不维护关联关系;该属性的值一般在使用有序集合时设置成false(注意hibernate的缺省值是false )。
one-to-many维护关联关系就是更新外键。many-to-many维护关联关系就是在中间表增减记录。
注:配置成one-to-one的对象不维护关联关系。

接着上面的部门和员工的例子:
department的映射配置文件为:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="hibernate.collections">

        <class name="Department">
                <id name="id">
                        <generator class="native" />
                </id>
                <property name="name"/>
               
                <map name="emps">
                        <key column="depart_id" />
                        <map-key type="string" column="name"/>
                        <one-to-many class="Employee" />
                </map>
        </class>
</hibernate-mapping>
 

程序:

static void add(){
     Department depart = new Department();
        depart.setName("depart");

        Employee e1 = new Employee();
        e1.setName("e1");
        Employee e2 = new Employee();
        e2.setName("e2");

        Map<String, Employee> emps = new HashMap<String, Employee>();
        emps.put(e1.getName(), e1);
        emps.put(e2.getName(), e2);

        depart.setEmps(emps);
        Session s = HibernateUtil.getSession();
        Transaction tx = s.beginTransaction();
        //s.save(e1);
        //s.save(e2);
        s.save(depart);
        tx.commit();
}

 

执行以上代码,程序出现异常:严重: Could not synchronize database state with session
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: hibernate.collections.Employee

在代码中,department知道了employee.s1和s2未持久化,使得保存department时出现异常。 把配置文件做一下修改,
                <map name="emps" cascade="save-update" >
                        <key column="depart_id" />
                        <map-key type="string" column="name"/>
                        <one-to-many class="Employee" />
                </map>


再运行以上代码,就可以正确的保存s1和s2了,因为对他们进行了级联操作,保存department时,也save了employee。

级联操作,可以把上面的选项以逗号分隔开,逐一添加即可。如:
  <map name="emps" cascade="save-update,delete,refresh" ></map>

但级联操作也要慎用,要根据自己具体的业务需求来进行相关配置。

还有:
在修改department.hbm.xml配置文件:

        <map name="emps">
                        <key column="depart_id" />
                        <map-key type="string" column="name"/>
                        <one-to-many class="Employee" />
                </map>
 

执行以下代码:

 static void add() {
        Department depart = new Department();
        depart.setName("depart");

        Employee e1 = new Employee();
        e1.setName("e1");
        e1.setDepart(depart);
        Employee e2 = new Employee();
        e2.setName("e2");
        e2.setDepart(depart);

        Map<String, Employee> emps = new HashMap<String, Employee>();
        emps.put(e1.getName(), e1);
        emps.put(e2.getName(), e2);

        depart.setEmps(emps);
        Session s = HibernateUtil.getSession();
        Transaction tx = s.beginTransaction();
        s.save(e1);
        s.save(e2);
        s.save(depart);
        tx.commit();
    }

 

hibernate输出以下sql语句:

Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Department (name) values (?)
Hibernate: update Employee set name=?, depart_id=? where id=?
Hibernate: update Employee set name=?, depart_id=? where id=?
Hibernate: update Employee set depart_id=?, name=? where id=?
Hibernate: update Employee set depart_id=?, name=? where id=?
 


上面的三条插入语句很容易理解。下面的四条更新语句分别对应:
 e1.setDepart(depart);
 e2.setDepart(depart);
 depart.setEmps(emps);
可以验证,如果把 e1.setDepart(depart);   e2.setDepart(depart);这两句注释掉,产生的更新语句只有两条:

Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Department (name) values (?)
Hibernate: update Employee set depart_id=?, name=? where id=?
Hibernate: update Employee set depart_id=?, name=? where id=?
 



由此可见,hibernate根据程序代码的执行,采取相应的操作。其实更新语句只需做一次就够了 。对于数据库而言,在程序中,告诉部门有哪些员工,或者告诉员工,你属于那个部门。对于前者,部门需要维护关系。对于后者,员工需要维护关系。他们最终都可以在数据库表中表达出部门和员工的关系。在程序中对两者都手动设定了双方的关系,这样也可以,但显得有些冗余(做了两次更新)。因此,双方都会对关系进行维护,所以,双方都会向数据库提交设定关系的请求,这就带来了数据的重复设置,正如上面的四条更新语句。

解决问题的方案是:我们可以让其中一方放弃对关系的维护。 我们一般让一方放弃对关系的维护,让多方维护。这也比较好理解,正如现实生活中,老师不一定要记住所有学生,但学生记住老师则相对比较容易。
充:inverse不能在有序的集合中使用 。比如一般不这样配置:
<list name="emps" inverse="true"></list> 原因是,list需要维护添加的顺序,如果放弃了关系的维护,那么顺序就也不回得到hibernate的管理。这无疑是矛盾的。
只要在配置文件中做一下修改即可:
                <map name="emps" inverse="true">
                        <key column="depart_id" />
                        <map-key type="string" column="name"/>
                        <one-to-many class="Employee" />
                </map>
在执行以下代码:

Department depart = new Department();
        depart.setName("depart");

        Employee e1 = new Employee();
        e1.setName("e1");
        e1.setDepart(depart);
        Employee e2 = new Employee();
        e2.setName("e2");
        e2.setDepart(depart);

        Map<String, Employee> emps = new HashMap<String, Employee>();
        emps.put(e1.getName(), e1);
        emps.put(e2.getName(), e2);

        depart.setEmps(emps);
        Session s = HibernateUtil.getSession();
        Transaction tx = s.beginTransaction();
        s.save(e1);
        s.save(e2);
        s.save(depart);
        tx.commit();
 


执行的sql语句为:

Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Department (name) values (?)
Hibernate: update Employee set name=?, depart_id=? where id=?
Hibernate: update Employee set name=?, depart_id=? where id=?
 


分析
:inverse="true"表示放弃对关系的维护。所以上面的两条更新语句是由Employee的setDepart方法产生的。因为关系有Employee来维护。由于department放弃了关系的维护,即使在代码中做了 depart.setEmps(emps)操作,hibernate也会忽略。通过以上方法,可以有效的减少数据库的操作次数,同时不影响关系的建立。

所谓的关系维护,就是更新外键。

改进:
从以上显示的sql语句,可以看出,在插入employee数据是也是插入了depart_id的,只不过是空值,然后插入department,这时就有了depart_id了,这时就去更新employee表,把depart_id更新。其实可以先保存department,这时一开始就有depart_id了,就不会有更新语句了。
代码如下:

 static void add() {
        Department depart = new Department();
        depart.setName("depart");

        Employee e1 = new Employee();
        e1.setName("e1");
        e1.setDepart(depart);
        Employee e2 = new Employee();
        e2.setName("e2");
        e2.setDepart(depart);

        Map<String, Employee> emps = new HashMap<String, Employee>();
        emps.put(e1.getName(), e1);
        emps.put(e2.getName(), e2);

        depart.setEmps(emps);
        Session s = HibernateUtil.getSession();
        Transaction tx = s.beginTransaction();
        s.save(depart);
        s.save(e1);
        s.save(e2);
        tx.commit();
    }

 

输出的sql语句为:

Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
 



心得: 根据程序执行过程中,打印输出的sql语句,只需冷静地分析程序的执行过程,不断地改进调优,可以有效的改善程序的性能。


http://www.niftyadmin.cn/n/2864062.html

相关文章

Redis——基于lamp架构做mysql的缓存服务器和配置gearman实现数据同步

一.前言 对一个关系型数据库进行调优以获得高查询性能可能会比较困难。如果对数据模型优化和对查询调优不起作用&#xff0c;DBA就可以使用缓存系统&#xff0c;比如Redis&#xff0c;它是一个可以提供内存和永久数据存储的键值数据存储系统。 由于Redis能够将数据快速读写至…

hibernate学习之第十一篇(1)

hibernate的继承映射 《一》一张表映射一棵继承树 使用discriminator&#xff08;鉴别标志&#xff09; 类Worker和Farmer都继承自Person 类Person的源代码如下&#xff1a; package hibernate.extend; public class Person { private int id; private String name; private…

Redis——redis集群方案之codis集群的搭建部署

一.什么是codis集群 codis集群简介 Codis是一个分布式的Redis解决方案&#xff0c;对于上层的应用来说&#xff0c;连接Codis Proxy和连接原生的Redis Server没有明显的区别&#xff08;不支持的命令列表&#xff09;&#xff0c;上层应用可以像使用单机的Redis一样使用&#…

hibernate学习之第十一篇(2)

《二》每个子类映射到一张表&#xff08;joined-subclass&#xff09; 配置文件修改为&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" &qu…

MFS——分布式文件系统的安装与部署

一.什么是MFS MFS简介 分布式文件系统是指文件系统管理的物理存储资源通过计算机网络与各节点相连。简单讲&#xff0c;就是把一些分散的共享文件夹&#xff0c;集合到一个文件夹内。对于用户来说&#xff0c;只需要打开该虚拟文件夹&#xff0c;就可以使用这些分散的文件夹进…

hibernate学习之第十二篇

《三》混合使用“一个类继承体系一张表”和“每个子类一张表” 比如上面的例子&#xff0c;worker类可能属性很少&#xff0c;而farmer属性却很多&#xff0c;把两者都与person放在同一张表中&#xff0c;则显得表的 结构不是很合理&#xff0c;会有很多字段是null。所以我们可…

MFS——如何恢复挂掉的mfsmaster服务

需要了解的知识&#xff1a; 在正常关闭的时候&#xff0c;/var/lib/mfs目录中会产生metadata.mfs这个文件&#xff0c;这个文件是开启mfsmaster服务时必备的文件。如果没有该文件,那么mfsmaster服务也就起不来。在正常开启的时候&#xff0c;/var/lib/mfs目录中就会产生metad…

hibernate学习之第十二篇(续)

《四》每个具体类映射一张独立的表&#xff08;union-subclass&#xff09;&#xff0c;即表与子类之间的独立一对一关系 所有的子类的表中的信息都是完整的&#xff0c;不需要对表进行关联了。 person.hbm.xml的配置如下&#xff1a; <?xml version"1.0" enco…