`
jianchen
  • 浏览: 344861 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

hibernate学习之十七篇

阅读更多

零碎知识小结:

◆数据类型:

1,<property name="name" type="java.lang.String"/>

type可以是hibernate,java类型或者你自己的类型(需要实现hibernate的一个接口)

2,基本类型一般不需要在映射文件(hbm.xml)中说明,只有在一个java类型和多个数据库数据类型相对应时并且你想要的和hibernate缺省映射不一致时,需要在映射文件中指明类型(如java.util.Date ,数据库DATE,TIME,DATETIME,TIMESTAMP,hibernate缺省会把java.util.Date映射成DATETIME型,而如果你想映射成TIME,则你必须在映射文件中指定类型)。

◆session是非线程安全的,生命周期较短,代表一个和数据库的连接,在B/S系统中一般不会超过一个请求;内部维护一级缓存和数据库连接,如果session长时间打开,会长时间占用内存和数据库连接。

◆sessionFactory是线程安全的,一个数据库对应一个SessionFactory,生命周期长,一般在整个系统生命周期内有效;SessionFactory保存着和数据库连接的相关信息(user,password,url)和映射信息,以及Hibernate运行时要用到的一些信息。


◆调用session的flush方法,使得一级缓存和数据库进行一次同步。我们在程序中一般不直接调用该方法,而是交由hibernate进行处理,hibernate会尽量把对数据库的操作延迟,在事务提交的时候,或不得不做的时候,一次性的处理,采用批处理能够减少与数据库的交互次数,提高性能。

◆大批量处理
  大量操作数据是可能造成内存溢出。
for(int i=0;i<100000;i++)
    session.save(obj);
解决方法如下:
1,清除session中的数据
for(int i=0;i<100000;i++){
    session.save(obj);
    if(i%20==0){
       session.flush();//调用flush是因为在清除一级缓存时,可能还有数据未真正的保存到数据库中,所以先做一次同步,再清除一级缓存
       session.clear();
    }
}

2,用StatelessSession接口:它不和一级缓存,二级缓存交互,也不触发任何事件,监听器,拦截器,通过该接口的操作会立刻发送给数据库,与jdbc的功能一样。

StatelessSession s = sessionFactory.openStatelessSession();该接口的方法与Session类似。

3,Query.executeUpdate()执行批量更新,会清除相关联的类二级缓存(sessionFactory.evict(class)),也可能会造成级联,和乐观锁定出现问题。


在hibernate 3.0之前,要大批量的更新数据,需执行如下操作:

session s = HibernateUtil.getSession();
Transaction tx = s.beginTransaction();
Query q = s.createQuery("from User");
List<User> users = q.list();
for(User u:users){
    u.setBirthday(new Date());
}

tx.commit();

 

hibernate 3.0后,可以这样做:

 

Query q = s.createQuery("update u set birthday=:bd from User as u");
q.executeUpdate();

 

◆HQL

1,查询多个对象selecet art,user from Article art,User user where art.author.id=user.id and art.id=:id 这种方式返回的是Object[],Object[0]:article,Object[1]:user。

2,分页 query.setFirstResult, qurey.setMaxResults.
查询记录总数query.iterate("select count(*) from Person").next;

3,批量更新 query.executeUpdate()可能造成二级缓存有失效数据。

◆Criteria

1,排序Criteria.addOrder(Order.desc(propertyName));
 
2,关联查询criteria.setFetchMode("propertyName",FetchMode.SELECT)与映射文件中关联关系的fetch作用一致。

3,投影Projections.rowCount(),groupPropery....

4,分页Projections.rowCount();criteria.setFirstResult();criteria.setMaxResults()

5,DetachedCriteria 可在session未创建时,根据用户的组合查询条件来构造查询。即它可在session外创建(在其他层创建比如在Service中创建)然后用detachedCriteria.getExecutableCriteria(Session)方法创建Criteria对象来完成查询。

示例:
在外部构建好离线查询对象DetachedCriteria。一般的criteria对象的创建需要与session对象关联,而离线查询对象的创建则不需要与session相关。
DetachedCriteria dc = DetachedCriteria.forClass(User.class);
String name = request.getParameter("name");
int age = request.getParameter("age");
dc.add(Restrictions.eq("name",name));
dc.add(Restrictions.eq("age",age));

把构建好的离线查询对象传递给dc方法,进行查询。
static List dc(DetachedCriteria dc){

        Session s = HibernateUtil.getSession();
        Criteria c = dc.getExecutableCriteria(s);//这时才与session关联构造出criteria对象,实施查询。
        List rs = c.list();
        s.close();
        return rs;
}


6,Example查询,Example.create(obj);criteria.add(example);

N+1次查询和懒加载

1,用Query.iterator可能会有N+1次查询。
2,懒加载时获取关联对象
3,如果打开对查询的缓存即使用list也可能有N+1次查询。

示例代码:
public class Main {

    public static void main(String[] args) {
        User user = new User();
        user.setBirthday(new Date());
        Name name = new Name();
        name.setFirstName("firstName");
        name.setLastName("lastName");
        user.setUserName(name);
        for (int i = 0; i < 10; i++) {
            user.getUserName().setFirstName("name" + i);
            saveUser(user);
        }
        iterate();
    }

    static void iterate() {
        Session s = HibernateUtil.getSession();
        Query q = s.createQuery("from User");
        Iterator<User> users = q.iterate();
      while(users.hasNext())            {
          System.out.println(users.next().getUserName().getFirstName());
        }


    }
  
    public static void saveUser(User user) {
        Session session = HibernateUtil.getSession();
        Transaction tx = session.beginTransaction();
        session.save(user);
        tx.commit();
        session.close();
    }

先向数据库中插入10条数据。然后查询所有的数据,打印出firstname,输出的sql语句为:
....//前面为10条插入语句
....
Hibernate: select user0_.id as col_0_0_ from user user0_
name0
name1
name2
name3
name4
name5
name6
name7
name8
name9


没有产生10条具体查询的语句,是因为配置了二级缓存和User类的缓存。主键生成方式为hilo而不是native,在保存10个对象后,同时会在二级缓存中进行缓存。等到查询时,先获得满足条件的id ,这就是第一条查询语句的作用。到真正读取时,根据id先到一级缓存,再到二级,最后到数据库中去查。在这里都在二级缓存中命中了。所以没产生另外的10条select语句。

把主键的生成方式改为:native。这样在插入数据后就不会在二级缓存中保存数据了。输出的sql语句为:

Hibernate: select user0_.id as col_0_0_ from user user0_
Hibernate: select user0_.id as id0_0_, user0_.version as version0_0_, user0_.first_name as first3_0_0_, user0_.last_name as last4_0_0_, user0_.birthday as birthday0_0_ from user user0_ where user0_.id=?
name0
Hibernate: select user0_.id as id0_0_, user0_.version as version0_0_, user0_.first_name as first3_0_0_, user0_.last_name as last4_0_0_, user0_.birthday as birthday0_0_ from user user0_ where user0_.id=?
name1
Hibernate: select user0_.id as id0_0_, user0_.version as version0_0_, user0_.first_name as first3_0_0_, user0_.last_name as last4_0_0_, user0_.birthday as birthday0_0_ from user user0_ where user0_.id=?
name2
Hibernate: select user0_.id as id0_0_, user0_.version as version0_0_, user0_.first_name as first3_0_0_, user0_.last_name as last4_0_0_, user0_.birthday as birthday0_0_ from user user0_ where user0_.id=?
name3
Hibernate: select user0_.id as id0_0_, user0_.version as version0_0_, user0_.first_name as first3_0_0_, user0_.last_name as last4_0_0_, user0_.birthday as birthday0_0_ from user user0_ where user0_.id=?
name4
Hibernate: select user0_.id as id0_0_, user0_.version as version0_0_, user0_.first_name as first3_0_0_, user0_.last_name as last4_0_0_, user0_.birthday as birthday0_0_ from user user0_ where user0_.id=?
name5
Hibernate: select user0_.id as id0_0_, user0_.version as version0_0_, user0_.first_name as first3_0_0_, user0_.last_name as last4_0_0_, user0_.birthday as birthday0_0_ from user user0_ where user0_.id=?
name6
Hibernate: select user0_.id as id0_0_, user0_.version as version0_0_, user0_.first_name as first3_0_0_, user0_.last_name as last4_0_0_, user0_.birthday as birthday0_0_ from user user0_ where user0_.id=?
name7
Hibernate: select user0_.id as id0_0_, user0_.version as version0_0_, user0_.first_name as first3_0_0_, user0_.last_name as last4_0_0_, user0_.birthday as birthday0_0_ from user user0_ where user0_.id=?
name8
Hibernate: select user0_.id as id0_0_, user0_.version as version0_0_, user0_.first_name as first3_0_0_, user0_.last_name as last4_0_0_, user0_.birthday as birthday0_0_ from user user0_ where user0_.id=?
name9

一共产生了11条查询语句,这就是所谓的N+1次查询问题。

懒加载也会产生n+1次查询。

拦截器与事件

拦截器与事件都是hibernate的扩展机制,Interceptor接口是老的实现机制,现在改成事件监听机制;他们都是hibernate的回调接口,hibernate在save,delete,update...等会回调这些类。

通过实现监听器接口,编写自己的监听器实现,然后在hibernate配置文件中,注册监听器。
使用<event type="save"></event>标签。type表示监听器对哪种操作感兴趣。
示例:
<event type="save">
   <listener class="hibernatetest.SaveListener"/>
</event>

执行后,监听器的动作得到了执行,但是对象却未保存到数据库中去。
分析:
由于我们编写了自己的监听器,hibernate认为我们有了更好的实现,所以系统默认的监听器会被放弃使用。defaultSaveOrUpdateEventListener该监听器是在发生save动作时,执行保存。我们一般在自己的监听器中做一些其他的事情,所以要保存对象,需要手动的添加监听器的默认实现,在监听器依次执行相关操作,默认的监听器就会保存对象了。
根据监听器配置的先后顺序,在事件发生时,依次调用。
正确做法:

<event type="save">
   <listener class="hibernatetest.SaveListener"/>
   <listener class="org.hibernate.event.def.defaultSaveOrUpdateEventListener"/>
</event>
 

SQL和命名查询。
session.createSQLQuery(arg0)
参数是原生的sql语句。不过不推荐使用,sql会依赖于底层的具体数据库,减弱了程序的可移植性。

session.getNamedQuery(arg0)

命名查询可以放在映射文件中。只不过是把HQL预先定义好,以后可以拿来就用而已。

用Map代替Domain对象;将对象转化为XML。

分享到:
评论
3 楼 jianchen 2009-03-18  
wskccss 写道

不错,好久不用都忘记了,现在看到这样的贴子受益匪浅啊!
不知道LZ在哪里可以找得到你所有的hibernate学习篇呢?
期待回复。



我的所有的hibernate的文章都在javaeye我的博客里啊。总共断断续续的有18篇吧。
2 楼 wskccss 2009-03-17  
不错,好久不用都忘记了,现在看到这样的贴子受益匪浅啊!
不知道LZ在哪里可以找得到你所有的hibernate学习篇呢?
期待回复。

1 楼 wskccss 2009-03-17  
                     

相关推荐

    Hibernate学习笔记整理

    Hibernate学习笔记整理 以下是 Hibernate 框架的详细知识点: Hibernate 介绍 Hibernate 是一个 ORM(Object-Relational Mapping)框架,用于将 Java 对象映射到数据库表中。它提供了一个简洁的方式来访问和操作...

    Hibernate学习.pdf

    ### Hibernate学习知识点详解 #### 1. Hibernate简介与安装配置 **标题:** Hibernate学习 **描述:** Hibernate 学习 Hibernate学习.pdf **标签:** Hibernate 学习 Hibernate学习.pdf **知识点详解:** ####...

    Hibernate 的学习笔记

    ### Hibernate 学习笔记知识点详解 #### 一、Hibernate 简介 - **概念**:Hibernate 是一种“对象/关系映射”(Object/Relational Mapping,简称 ORM)技术,用于解决 Java 应用程序与关系型数据库交互的问题。 - *...

    Hibernate+学习笔记

    【Hibernate 学习笔记】 Hibernate 是一款开源的对象关系映射(ORM)框架,它为 Java 开发者提供了在关系数据库和面向对象编程之间的一个抽象层。这个框架使得开发者可以使用面向对象的方式来操作数据库,而无需...

    Hibernate中文详细学习文档

    17. 过滤数据 17.1. Hibernate 过滤器(filters) 18. XML映射 18.1. 用XML数据进行工作 18.1.1. 指定同时映射XML和类 18.1.2. 只定义XML映射 18.2. XML映射元数据 18.3. 操作XML数据 19. 提升性能 19.1. 抓取...

    hibernate中文参考文档

    Hibernate是一款开源的对象关系映射(Object/Relational Mapping,...整个文档是一个综合性的Hibernate使用指南,它从理论到实践都有所涵盖,对于任何想要深入学习和使用Hibernate框架的Java开发者来说都是宝贵的资源。

    hibernate学习

    【标题】:“Hibernate学习” 【描述】:在Java开发领域,Hibernate是一个强大的对象关系映射(ORM)框架,它极大地简化了数据库操作。通过提供一套API,Hibernate允许开发者使用面向对象的方式来处理数据库交互,...

    Hibernate笔记 马士兵

    第9课 Hibernate的重点学习:Hibernate的对象关系映射 12 一、对象---关系映射模式 12 二、常用的O/R映射框架: 13 第10课 模拟Hibernate原理(OR模拟) 13 一、 项目名称 13 二、 原代码 13 第11课 Hibernate基础配置...

    Hibernate 手册 第一章 Hibernate入门

    《Hibernate 手册 第一章 Hibernate入门》 Hibernate 是一个开放源码的Java持久化框架,它为Java开发者提供了一种对象关系映射工具来管理Java应用中的关系数据。本章将带你逐步走进Hibernate的世界,了解其基本概念...

    hibernate4.2.17

    Hibernate 4.2.17 是一个非常关键的版本,它是Java开发中广泛使用的对象关系映射(ORM)框架Hibernate的重要迭代。SSH(Struts、Spring、Hibernate)是Java Web开发的经典三位一体,Hibernate在其中扮演着数据库交互...

    HIBERNATE官方参考手册

    《Hibernate官方参考手册》是学习和理解Hibernate的核心资料,提供了详尽的API文档、配置指南和使用示例。以下是对Hibernate的一些关键知识点的详细说明: 1. **对象关系映射(ORM)**:ORM是Hibernate的核心特性,...

    Hibernate开发指南.pdf

    ### Hibernate开发指南...通过阅读本书,读者不仅可以学习到如何使用Hibernate来解决常见的数据持久化问题,还可以了解到如何利用Hibernate与其他框架(如Spring)进行高效集成,以构建高性能、高可用性的企业级应用。

    Hibernate Developer Guide

    ### Hibernate 开发者指南知识点详解 #### 一、前言 Hibernate是一款开源的对象关系映射(Object Relational Mapping,简称...通过深入学习这些知识点,可以更好地利用Hibernate的强大功能来构建高性能的应用程序。

    精通Hibernate源码

    通过阅读《精通Hibernate源码》的各个章节,如chapter17到chapter22,读者可以从实践中深化理论知识,掌握Hibernate的内部运行机制,从而在项目开发中游刃有余。在深入学习的过程中,不断实践和总结,才能真正精通...

    Hibernate基础和入门:新建表和插入表

    标题“Hibernate基础和入门:新建表和插入表”表明这篇内容将主要围绕Hibernate这一Java持久化框架的基础知识展开,重点讲解如何使用Hibernate创建数据库表以及进行数据插入操作。Hibernate是一个强大的ORM(对象...

    hibernate_persistence第17-23章书中代码

    《hibernate_persistence》是关于Hibernate持久化技术的一本书,涵盖了从第17章到第23章的代码示例。这些章节的代码主要涉及了Hibernate在数据库操作中的核心功能,包括查询条件设置、高级查询、数据源配置以及与...

    Spring整合Hibernate操作商品库存表

    通过这个项目,学习者不仅可以掌握Spring、Hibernate和JSP的基本使用,还能了解到如何将它们结合到一起,形成一个完整的Web应用。同时,此项目也为添加其他框架如Struts提供了基础,进一步扩展系统的功能和架构。

    精通Hibernate源代码

    4. **Chapter 17**:可能涉及缓存机制,Hibernate提供了第一级缓存和第二级缓存,以提高数据访问速度和减少数据库负载。 5. **Chapter 12**和**Chapter 16**:可能涵盖了事务管理和并发控制,这对于保证数据的一致...

    javaWeb项目整合开发的各个项目源码包括各种框架(struts+hibernate+spring)

    具体到这个项目,源码分为了5个部分(17~21),这可能是因为文件大小的限制,每个文件包含了一部分项目的源代码。在实际开发中,这样的组织方式有助于管理和版本控制,但需要开发者根据提供的文件顺序和说明进行合并...

    Struts 2+Hibernate+Spring整合开发技术详解 12~17章

    通过学习这一部分的内容,开发者能熟练掌握Struts 2、Hibernate和Spring的整合应用,提升开发大型企业级应用的能力。每个章节都可能涵盖上述知识点的一个或多个方面,结合实际示例和源代码,有助于读者深入理解和...

Global site tag (gtag.js) - Google Analytics