【框架】[Hibernate]多表操作与缓存技术

转载请注明出处:http://blog.csdn.net/qq_26525215

本文源自大学之旅_谙忆的博客

多表操作

   关系型数据库具有三种常用关系:一对一关系、一对多关系和多对多关系。
   建立了一对多关系的表之间,一方中的表叫“主表”,多方中的表叫“子表”;两表中相关联的字段,在主表中叫“主键”,在子表中称“外键”。

一对多关系操作

我们以院系表与学生表为例。
在Hibernate映射中,在院系表中添加一个集合属性,集合属性存放该院系下的学生。
学生表中将院系编号字段映射成一个院系类对象。
这样通过院系类对象的属性集合找到该院系下的所有学生。
通过学生对象的院系属性也很快定位到院系的其它信息不仅仅是院系编号。

在POJO类中:
我们需要在学生对象中建立院系对象。
在院系对象中建立学生对象的集合。

学生表的映射文件:

<hibernate-mapping>
    <class name="bean.Student" table="student" catalog="support">
        <id name="sno" type="java.lang.String">
            <column name="sno" length="4" />
            <generator class="assigned"></generator>
        </id>
<!--name设定待映射的持久化类的属性名-->
<!--column设定和持久化类的属性对应的表的外键-->
<!--class设定持久化类的属性的类型-->
        <many-to-one name="dept" class="bean.Dept" fetch="select">
<!-- fetch ,可以设置fetch = "select" 和 fetch = "join"
用一对多来举例:
fetch = "select"是在查询的时候先查询出一端的实体,然后在根据一端的查询出多端的实体,会产生1+n条sql语句;
fetch = "join"是在查询的时候使用外连接进行查询,不会差生1+n的现象。 -->
            <column name="deptid" length="4" />
        </many-to-one>
        <property name="sname" type="java.lang.String">
            <column name="sname" length="20" />
        </property>
    </class>
</hibernate-mapping>

院系的表映射文件:

Dept.hbm.xml
<hibernate-mapping>
    <class name="bean.Dept" table="dept" catalog="support">
        <id name="deptid" type="java.lang.String">
            <column name="deptid" length="4" />
            <generator class="assigned"></generator>
        </id>
        <property name="deptname" type="java.lang.String">
            <column name="deptname" length="30" />
        </property>
<!-- name设定待映射的持久化类的属性名-->
        <set name="students" inverse="true">
<!--所关联的持久类对应的表的外键-->
            <key>
                <column name="deptid" length="4" />
            </key>
<!--设定持久化所关联的类-->
            <one-to-many class="bean.Student" />
        </set>
    </class>
</hibernate-mapping>

测试一对多关系操作

Session s=HibernateSessionFactory.getSession();
       Query q=s.createQuery("from Dept");
       List l=q.list();
       for(int i=0;i<l.size();i++){
             Dept dept=(Dept)l.get(i);
             System.out.println(dept.getDeptid());
             Set stu= dept.getStudents();//通过院系实例可以查询该院学生
             Iterator it=stu.iterator();
             while(it.hasNext()){
                  Student st=(Student)it.next();
                  System.out.print(st.getSno()+"  ");
             }
       }

通过上面的,我们无论查询哪一方,我们总是可以知道另一方。
例如:
查询学生,我们可以通过学生对象拿到他的院系。

级联操作与延迟加载

1、cascade级联操作

所谓cascade,如果有两个表,在更新一方的时候,可以根据对象之间的关联关系,对被关联方进行相应的更新。比如说院系表和学生表之间是一对多关系,使用cascade, 如删除院系表中的一条院系记录时,该院系下的所有学生记录也自动删除。这种现象称为级联删除。当创建一个新的院系实例,该院系实例集合属性中保存有学生。当该院系实例持久化时,自动将集合学生也自动添加到数据库的学生表中去。这称为级联增加。

all : 所有情况下均进行关联操作。
none:所有情况下均不进行关联操作。这是默认值。
save-update:执行save/update/saveOrUpdate时进行关联操作
delete:在执行delete时进行关联操作。

级联示例

删除院系表dept同时将该院系下所有学生student删除。可以在院系类映射文件中如下定义。

<!--表示级联删除-->
<set name="students" inverse="false" cascade="delete">
       <key>
           <column name="deptid" length="4" />
       </key>
        <one-to-many class="bean.Student" />
</set>
还可以定义级联增加、修改等
<set name="students" inverse="false" cascade=
                                   "none|all|delete| save-update">
        <key>
             <column name="deptid" length="4" />
         </key>
         <one-to-many class="bean.Student" />
</set>

2、inverse属性

这个属性不好理解,打个比方来说这个属性。
一个学校有个校长,学校里有很多学生。学生表中假设有一个字段是校长编号(多方),如果我们增加一个学生,学生记录中校长编号字段如何填呢?显然学生自己填(即由学生方维护)要容易些,学生记住校长现实点。如果你要让校长填写学生的校长编号这个字段(即由校长方维护)则比较难,因为校长如何记住那么多学生呢?

inverse属性示例. (没有采用inverse)
Team.hbm.xml代码如下(省略部分):

   <class name="bean.Team" table="TEAM" >
        <set name="students" cascade="all">
         <key>
          <column name="TEAM_ID" length="20" />
         </key>
         <one-to-many class="bean.Student" />
        </set>
   </class>

Student.hbm.xml代码如下(省略部分):

    <class name=" bean.Student" table="STUDENT" >
            <many-to-one name="team" class="bean.Team" fetch="select">
            <column name="TEAM_ID" length="20" />
          </many-to-one>
       </class>

从上面的代码中没有出现一个inverse关键字,证明维护关系由班级表和学生表一起来维护。比如:现在有新的学生要进入某一个班级(班级号t001),可以编写如下的代码来完成该功能。

Session session = HibernateSessionFactory.getSession();
  Transaction tran = session.beginTransaction();
  Query query = session.createQuery("from Student");
  List list = query.list();
  Team team = (Team) session.get(Team.class, "t001");
  for (int i = 0; i < list.size(); i++) {
      Student stu = (Student) list.get(i);
      if (stu.getTeam() == null) {
         team.getStudents().add(stu);
       }
  }
  tran.commit();

这段代码通过班级来添加学生信息的,也就是说添加学生信息可以由班级来维护。

现在只给出Team.hbm.xml配置文件,其中添加了inverse关键,学生映射文件未变。 (采用inverse)

<class name="bean.Team" table="TEAM" >
        <set name="students" inverse="true" cascade="all">
         <key>
          <column name="TEAM_ID" length="20" />
         </key>
         <one-to-many class="bean.Student" />
        </set>
    </class>

按照上面的配置信息,如果还是想完成新的学生要进入某一个班级(如班级号为t001的班级)这个功能,代码编写如下:

Session session = HibernateSessionFactory.getSession();
  Transaction tran = session.beginTransaction();
  Query query = session.createQuery("from Student");
  List list = query.list();
  Team team = (Team) session.get(Team.class, "t001");
  for (int i = 0; i < list.size(); i++) {
     Student stu = (Student) list.get(i);
     if(stu.getTeam() == null) {
         stu.setTeam(team);//学生自己维护班级
     }
  }
  tran.commit();

这段代码通过学生来添加班级信息的,也就是说添加学生信息可以由学生自己来维护。

3、延迟加载

(1) 属性的延迟加载
如Person表有一个人员图片字段(对应java.sql.Clob类型)属于大数据对象,当我们加载该对象时,我们不得不每一次都要加载这个字段,而不论我们是否真的需要它,而且这种大数据对象的读取本身会带来很大的性能开销。我们可以如下配置我们的实体类的映射文件:

 <hibernate-mapping>
 <class name="bean.Person" table="person">
      ……
  <property name="pimage" type="java.sql.Clob"
                         column="pimage" lazy="true"/>
 </class>
 </hibernate-mapping>

多对多关系操作

以学生与教师为例,一个教师可以教对个学生,一个学生也可以接受多个老师的教育。所以他们之间是多对多的关系。我们一般建立3个表:学生表、教师表以及学生教师表。

学生类映射文件

 <class name="Student">
         ......
        <!-- name="teachers" 表示:Student类中有一个属性叫teachers (是Set集合)-->
        <!-- table="teacher_student" 表示:中间关联表。表名叫teacher_student -->
        <set name="teachers" table="teacher_student">
      <!-- column="student_id" 表示:中间表teacher_student的字段-->
      <!-- Student类的id与中间表teacher_student的字段student_id对应-->
            <key column="student_id"/>
            <!-- column="teacher_id" 表示:中间表teacher_student的字段-->
            <!-- class="Teacher" 表示:中间表teacher_student的字段teacher_id与 Teacher类的id对应-->
          <many-to-many class="Teacher”
                                           column="teacher_id"/>
       </set>
   </class>

教师类映射文件

  <class name="Teacher">
        ......
       <set name="students" table="teacher_student">
            <key column="teacher_id"/>
            <many-to-many class="Student"
                                                 column="student_id"/>
        </set>
    </class>

(也可以分解成两个一对多关系)
把多对多关联分解为两个一对多关联,具有更好的可扩展性和操作性。

Hibernate缓存技术

缓存是介于物理数据源与应用程序之间,缓存被广泛用于数据库应用领域。缓存的设计就是为了通过存储已经从数据库读取的数据来减少应用程序和数据库之间的数据流量,而数据库的访问只在检索的数据不在当前缓存的时候才需要。

1、Hibernate缓存范围以及分类 (缓存的范围分为三类)

(1) 事务范围:

缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期,当事务结束时,缓存也就结束生命周期。在此范围下,缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存。

(2) 应用范围:

缓存被应用范围内的所有事务共享的。这些事务有可能是并发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于应用的生命周期,应用结束时,缓存也就结束了生命周期,二级缓存存在于应用范围。

(3) 集群范围:

在集群环境中,缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致性,缓存中的数据通常采用对象的松散数据形式,二级缓存也存在与应用范围。

Hibernate 中提供了两级Cache。

第1级别的缓存是Session级别的缓存,即上述事务范围以及应用范围的缓存。这一级别的缓存由Hibernate管理的,一般无需进行干预;缓存的物理介质为内存,由于内存容量有限,必须通过恰当的检索策略和检索方式来限制加载对象的数目。

第2级别的缓存是SessionFactory级别的缓存,属于进程范围或群集范围的缓存。这一级别的缓存可以进行配置和更改,并且可以动态加载和卸载。 第2级缓存的物理介质可以是内存和硬盘,因此第2级缓存可以存放大量的数据,数据过期策略的maxElementsInMemory属性值可以控制内存中的对象数目。

Hibernate本身并不提供2级缓存的产品化实现,而是为众多支持Hibernate的第三方缓存组件提供整合接口。

转载请注明出处:http://blog.csdn.net/qq_26525215

本文源自大学之旅_谙忆的博客

时间: 2024-10-27 09:24:04

【框架】[Hibernate]多表操作与缓存技术的相关文章

Hibernate框架中的缓存技术详解_java

本文实例讲述了Hibernate框架中的缓存技术.分享给大家供大家参考,具体如下: Hibernate框架的缓存分为Session的缓存.SessionFactory的缓存,也称为一级缓存和二级缓存. 一级缓存: 一级缓存是Session级的缓存,其生命周期很短,与Session相互对应,由Hibernate进行管理,属于事务范围的缓存.当程序调用 Session的load()方法.get()方法.save()方法.saveOrUpdate()方法.update()方法或查询接口方法时,Hibe

mysql-测试hibernate框架自动建表并保存数据,没报错,但数据只保存了一部分

问题描述 测试hibernate框架自动建表并保存数据,没报错,但数据只保存了一部分 解决方案 因为你去给Product这个对象创建三个实例,pro.pro2.pro3,对吧,然后你不停的给pro去赋值(pro.setName()),最后pro的最后一个值把前两个覆盖掉了,所以只添加了一个棉花糖.正确的方式是要给每个,你把第29行改成pro2.setName():30行pro2.setDir():33行pro3.setName():34行pro3.setDir(),就万事大吉了,祝你成功! 解决

entity framework-EF框架关于数据库两个关联的表操作的一些问题

问题描述 EF框架关于数据库两个关联的表操作的一些问题 在EF创建两个多对多关联的实体,并且映射到数据库中,在对中间表进行查询或是清除中间表的数据时操作失败,使用数据库跟踪发现没有生成相应的代码 static void Main(string[] args) { OAMangerEntities db = new OAMangerEntities(); var user = db.CreateObjectSet<UserInfo>().Where(u => u.ID == 2).Firs

分布式测试框架架构与思考(1)技术选型

"工欲善其事必先利其器".无论是哪个行业,这都是一句至理名言,软件测试当然也不例外.这也正是分布式测试框架(下文简称DST)设计的初衷. DST是海量数据项目背景下,为了解决测试集管理.运行.查询和测试执行.控制以及监控.日志数据的收集整理的一个通用型测试与分析平台.这个平台既包含了传统测试框架的特点也包含了自身的开创性思想.作为DST从前端界面到后端服务的亲身经历和开发者,下面我将从技术选型.架构设计.功能点分析.使用场景以及周边支持工具这几个角度来对DST测试平台做一个总结,进一步

全面剖析.Net环境下的缓存技术_实用技巧

一. 概念1.1   缓存能解决的问题· 性能--将相应数据存储起来以避免数据的重复创建.处理和传输,可有效提高性能.比如将不改变的数据缓存起来,例如国家列表等,这样能明显提高web程序的反应速度: · 稳定性--同一个应用中,对同一数据.逻辑功能和用户界面的多次请求时经常发生的.当用户基数很大时,如果每次请求都进行处理,消耗的资源是很大的浪费,也同时造成系统的不稳定.例如,web应用中,对一些静态页面的呈现内容进行缓存能有效的节省资源,提高稳定性.而缓存数据也能降低对数据库的访问次数,降低数据

使用asp缓存技术,提高asp承载能力

其实当你的web站点采用asp技术建立的初期,可能会感觉到的是asp动态网页技术带来的便利性,以及随意修改性.自如的http控制.但随着访问量的增加,你一定会发现自己的站点访问速度会越来越慢,IIS重新启动得越来越频繁. 一.什么是ASP缓存/为什么要缓存 其实当你的web站点采用asp技术建立的初期,可能会感觉到的是asp动态网页技术带来的便利性,以及随意修改性.自如的http控制.但随着访问量的增加,你一定会发现自己的站点访问速度会越来越慢,IIS重新启动得越来越频繁.那么,你一定想怎么优化

缓存技术及在Rainbow Portal的应用

缓存 1. ASP.NET缓存技术概述 将数据库中的数据缓存到内存(也可以存储在其他场所),则无需在请求每个页面时都访问数据库.由于从内存中返回数据的速度始终比新提供的数据速度快,因而可以大大提高应用程序的性能. ASP.NET为你使用缓存技术提供最大的灵活性,你可以缓存整个HTML页面,或是部分HTML页面,或是各种对象.你可以设置过期策略,或是设置依赖性,即在其他资源如文件或数据库表改变时,自动移出缓存. ASP.NET中有两种基本的缓存: 输出缓存 页面输出缓存是最为简单的缓存机制,该机制

在Hibernate中直接操作JDBC接口

简介: Hibernate 在处理多表关联及分组排序等复杂数据库查询操作时,其固有的 O-R 映射机制会 产生大量冗余 SQL 操作,系统性能比传统的 JDBC 低很多.本文分析了 Hibernate 产生此类问题的原因 ,提出了一个在 Hibernate 框架内直接操作 JDBC 的接口的解决方案,在实际项目中验证了该解决方案 可以有效提高此类查询的效率.文中提供的示例代码可以直接运用于使用 Hibernate 框架的 J2EE 系统 项目. 在 Hibernate 框架中提供直接操作 JDB

PHP缓存技术

1普遍缓存技术 数据缓存:这里所说的数据缓存是指数据库查询缓存,每次访问页面的时候,都会先检测相应的缓存数据是否存在,如果不存在,就连接数据库,得到数据,并把查询结果序列化后保存到文件中,以后同样的查询结果就直接从缓存表或文件中获得. 用的最广的例子看Discuz的搜索功能,把结果ID缓存到一个表中,下次搜索相同关键字时先搜索缓存表. 举个常用的方法,多表关联的时候,把附表中的内容生成数组保存到主表的一个字段中,需要的时候数组分解一下,这样的好处是只读一个表,坏处就是两个数据同步会多不少步骤,数