第五章 Hibernate核心API介绍与其使用

5.1 Configuration接口
5.1.1加载hibernate.cfg.xml并完成系统的配置
       Configuration接口的作用是对Hibernate进行配置、并启动Hibernate和连接数据库系统。
       在Hibernate的启动过程中,Configuration类的实例首先定位缺省XML配置文件(hibernate.cfg.xml),并读取关的配置项目,然后创建出一个SessionFactory对象。根5.1.2据Configuration对象创建一个SessionFactory对象。

Configuration cfg = new Configuration();
		cfg.configure();
		SessionFactory sessionFactory = cfg.buildSessionFactory();

5.1.3 也可以采用自定义的XML配置文件(少用)
        可以指定开发者自己的*.hbm.xml文件的位置,而不是使用默认的classpath下面的hibernate.cfg.xml。但需要在代码中指示开发者自定义的XML配置文件。

cfg.configure("hibernate2.cfg.xml");

5.2 SessionFactory接口

5.2.1 利用工厂类SessionFactory中取得Session的实例

Session session = sessionFactory.openSession();

5.2.2 SessionFactory并不是轻量级的
       但要注意的是SessionFactory并不是轻量级的!(占内存)
       实际上它的设计者的意图是让它能在整个应用中共享。

5.2.3 每个数据存储源对应创建一个SessionFactory(单例) 

5.2.4 SessionFactory的缓存
       可分为两类:内置缓存和外置缓存。

5.2.4.1 SessionFactory的内置缓存中存放了Hibernate配置信息和映射元数据信息、同时也缓存了Hibernate自动生成的SQL语句等;

 
5.2.4.2 SessionFactory的外置缓存是一个可配置的缓存插件
       在默认情况下,SessionFactory不会启用这个缓存插件。
       外置缓存能存放大量数据库数据的拷贝,外置缓存的物理介质可以是内存或者硬盘。

5.3 Session接口

5.3.1轻量级的类
        在Hibernate中,实例化的Session是一个轻量级的类,创建和销毁它都不会占用很多资源。
        这在实际项目中确实很重要,因为在客户程序中,可能会不断地创建以及销毁Session对象,如果Session的开销太大,会给系统带来不良影响。

5.3.2非线程安全的(一请求---一线程----一session---一事务)

        值得注意的是Session对象是非线程安全的,因此最好是一个线程只创建一个Session对象(将它设计为局部对象)。

private static ThreadLocal threadSession = new ThreadLocal();
public static Session getThreadLocalSession(){
		Session s = (Session) threadSession.get();
		if(s == null){
			s = sessionFactory.openSession();
			threadSession.set(s);
		}
		return s;
	}

5.3.3 Session看作介于数据连接与事务管理一种中间接口
       我们可以将session想象成一个持久对象的缓冲区,Hibernate能检测到这些持久对象的改变,并及时刷新数据库。 

5.3.4 每一个Session实例和一个数据库事务绑定 
       通常将每一个Session实例和一个数据库事务绑定,也就是说,每执行一个数据库事务(操作),都应该先创建一个新的Session实例。
       如果事务执行中出现异常,应该撤销事务;同时不论事务执行成功与否,最后都应该调用Session的close()方法,从而释放Session实例占用的资源。

5.3.5如何获得Session对象
       首先创建SessionFactory对象,应用程序如果访问多个数据源时,则应该产生多个SessionFactory;但是仅仅为了服务于某个请求时,不要创建一个新的     SessionFactory,因为创建SessionFactory 需要耗费大量的资源。

       然后根据SessionFactory再创建Session对象

5.3.6 Session的编程规则---需要随时更新和释放 
       注意:应该要session.close()语句放在finally语句块中。

5.3.7 Sessin 接口中针对单条记录的基本的CURD操作方法 

    1、save();  

session.save(Object);// session的save方法是向数据库中保存一个对象

   
    2、delete()  

 session.delete(Object);//Object对象需要有ID。对象删除后,对象状态为Transistent状态

    3、load()   

Session.load(Class arg0, Serializable arg1) throws HibernateException

* arg0:需要加载对象的类,例如:User.class
* arg1:查询条件(实现了序列化接口的对象):例"4028818a245fdd0301245fdd06380001"字符串已经实现了序列化接口。如果是数值类类型,则hibernate会自动使用包装类,例如 1
* 此方法返回类型为Object,但返回的是代理对象。
* 执行此方法时不会立即发出查询SQL语句。只有在使用对象时,它才发出查询SQL语句,加载对象。
* 因为load方法实现了lazy(称为延迟加载、赖加载)
* 延迟加载:只有真正使用这个对象的时候,才加载(才发出SQL语句)
* hibernate延迟加载实现原理是代理方式。
* 采用load()方法加载数据,如果数据库中没有相应的记录,则会抛出异常对象不找到(org.hibernate.ObjectNotFoundException)

try {
    session = sf.openSession();
    session.beginTransaction();
    User user = (User)session.load(User.class,1);
    //只有在使用对象时,它才发出查询SQL语句,加载对象。
    System.out.println("user.name=" + user.getName());

    //因为此的user为persistent状态,所以数据库进行同步为龙哥。
    user.setName("发哥");

    session.getTransaction().commit();
} catch (HibernateException e) {
    e.printStackTrace();
    session.getTransaction().rollback();
} finally{
    if (session != null){
    if (session.isOpen())
    session.close();
}

  

  4、Get()

   

 Session.get(Class arg0, Serializable arg1)方法

* arg0:需要加载对象的类,例如:User.class
* arg1:查询条件(实现了序列化接口的对象):
        例"4028818a245fdd0301245fdd06380001"字符串已经实现了序列化接口。如果是基数类型,则hibernate会自动转换成包装类,如 1
        返回值: 此方法返回类型为Object,也就是对象,然后我们再强行转换为需要加载的对象就可以了。
        如果数据不存在,则返回null;
        注:执行此方法时立即发出查询SQL语句。加载User对象
        加载数据库中存在的数据,代码如下:

try {
     session = sf.openSession();
     session.beginTransaction();

     / * 此方法返回类型为Object,也就是对象,然后我们再强行转换为需要加载 的对象就可以了。如果数据不存在,则返回null
       * 执行此方法时立即发出查询SQL语句。加载User对象。
       */
     User user = (User)session.get(User.class, 1);

     //数据加载完后的状态为persistent状态。数据将与数据库同步。
     System.out.println("user.name=" + user.getName());

     //因为此的user为persistent状态,所以数据库进行同步为龙哥。
     user.setName("龙哥");

     session.getTransaction().commit();
} catch (HibernateException e) {
     e.printStackTrace();
     session.getTransaction().rollback();
} finally{
     if (session != null){
     if (session.isOpen()){
         session.close();
     }
}

    5、load()与get()区别
    不存在对应记录时表现不一样;
    load返回的是代理对象,等到真正使用对象的内容时才发出sql语句,这样就要求在第一次使用对象时,要求session处于open状态,否则出错
    get直接从数据库加载,不会延迟加载
    get()和load()只根据主键查询,不能根据其它字段查询,如果想根据非主键查询,可以使用HQL

    6、update()
    用来更新detached对象,更新完成后转为为persistent状态(默认更新全部字段)
    更新transient对象会报错(没有ID)
    更新自己设定ID的transient对象可以(默认更新全部字段)
    persistent状态的对象,只要设定字段不同的值,在session提交时,会自动更新(默认更新全部字段)
    更新部分更新的字段(更改了哪个字段就更新哪个字段的内容)
    方法1:update/updatable属性
     xml:设定<property>标签的update属性,设置在更新时是否参数更新

<property name="name" update="false"/>

     注意:update可取值为true(默认):参与更新;false:更新时不参与更新
     annotateon:设定@Column的updatable属性值,true参与更新,false:不参与更新

@Column(updatable=false)
public String getTitle() {return title;}

    注意:此种方法很少用,因为它不灵活
    方法二:dynamic-update属性
    注意:此方法目前只适合xml方式,JAP1.0 annotation没有对应的
    在实体类的映射文件中的<class>标签中,使用dynamic-update属性,true:表示修改了哪个字段就更新哪个字段,其它字段不更新,但要求是同一个session(不能跨session),如果跨了session同样会更新所有的字段内容。
<class name="com.bjsxt.Student" dynamic-update="true">
 代码:

@Test
public void testUpdate5() {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Student s = (Student)session.get(Student.class, 1);
s.setName("zhangsan5");
//提交时,会只更新name字段,因为此时的s为persistent状态
session.getTransaction().commit();
s.setName("z4");
Session session2 = sessionFactory.getCurrentSession();
session2.beginTransaction();
//更新时,会更新所有的字段,因为此时的s不是persistent状态
session2.update(s);
session2.getTransaction().commit();}

            如果需要跨session实现更新修改的部分字段,需要使用session.merget()方法,合并字段内容

@Test
public void testUpdate6() {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Student s = (Student)session.get(Student.class, 1);
s.setName("zhangsan6");
session.getTransaction().commit();
s.setName("z4");
Session session2 = sessionFactory.getCurrentSession();
session2.beginTransaction();
session2.merge(s);
session2.getTransaction().commit()}

    这样虽然可以实现部分字段更新,但这样会多出一条select语句,因为在字段数据合并时,需要比较字段内容是否已变化,就需要从数据库中取出这条记录进行比较
使用HQL(EJBQL)面向对象的查询语言(建议)

@Test
public void testUpdate7() {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Query q = session.createQuery(
"update Student s set s.name='z5' where s.id = 1");
q.executeUpdate();
session.getTransaction().commit();
} 

    7、saveOrUpdate()
    在执行的时候hibernate会检查,如果对象在数据库中已经有对应的记录(是指主键),则会更新update,否则会添加数据save

   

   8、clear()
    清除session缓存
    无论是load还是get,都会首先查找缓存(一级缓存,也叫session级缓存),如果没有,才会去数据库查找,调用clear()方法可以强制清除session缓存

Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Teacher t = (Teacher)session.load(Teacher.class, 1);
System.out.println(t.getName());
session.clear();
Teacher t2 = (Teacher)session.load(Teacher.class, 1);
System.out.println(t2.getName());
session.getTransaction().commit();

     注意:这样就会发出两条SELECT语句,如果把session.clear()去除,则只会发出一条SELECT语句,因为第二次load时,是使用session缓存中ID为1的对象,而这个对象已经在第一次load到缓存中 了。
    9、flush()
    在hibernate中也存在flush这个功能,在默认的情况下session.commit()之前时,其实执行了一个flush命令。
    Session.flush功能:
    清理缓存;
    执行sql(确定是执行SQL语句(确定生成update、insert、delete语句等),然后执行SQL语句。)

    Session在什么情况下执行flush:
    默认在事务提交时执行;
    注意:flush时,可以自己设定,使用session.setFlushMode(FlushMode)来指定。
 <pre name="code" class="java" session.setFlushMode(FlushMode);

   FlushMode的枚举值:
    FlushMode.ALWAYS:任务一条SQL语句,都会flush一次
    FlushMode.AUTO :自动flush(默认)
    FlushMode.COMMIT: 只有在commit时才flush
FlushMode.MANUAL:手动flush。
FlushMode.NEVER :永远不flush  此选项在性能优化时可能用,比如session取数据为只读时用,这样就不需要与数据库同步了

注意:设置flush模式时,需要在session开启事务之前设置。
可以显示的调用flush;
在执行查询前,如:iterate.
注:如果主键生成策略是uuid等不是由数据库生成的,则session.save()时并不会发出SQL语句,只有flush时才会发出SQL语句,但如果主键生成策略是native由数据库生成的,则session.save的同时就发出SQL语句。

10、evict()
例如:session.evict(user)
作用:从session缓存(EntityEntries属性)中逐出该对象
但是与commit同时使用,会抛出异常

session = HibernateUtils.getSession();
tx = session.beginTransaction();

User1 user = new User1();
user.setName("李四");
user.setPassword("123");
user.setCreateTime(new Date());
user.setExpireTime(new Date());

//利用Hibernate将实体类对象保存到数据库中,因为user主键生成策略采用的是uuid,所以调用完成save后,只是将user纳入session的管理,不会发出insert语句,但是id已经生成,session中的existsInDatabase状态为false
session.save(user);

session.evict(user);//从session缓存(EntityEntries属性)中逐出该对象
//无法成功提交,因为hibernate在清理缓存时,在session的临时集合(insertions)中取出user对象进行insert操作后需要更新entityEntries属性中的existsInDatabase为true,而我们采用evict已经将user从session中逐出了,所以找不到相关数据,无法更新,抛出异常。

tx.commit();

解决在逐出session缓存中的对象不抛出异常的方法:

//在session.evict()之前进行显示的调用session.flush()方法就可以了。
session.save(user);

//flush后hibernate会清理缓存,会将user对象保存到数据库中,将session中的insertions中的user对象清除,并且会设置session中的existsInDatabase状态为false
session.flush();

session.evict(user);//从session缓存(EntityEntries属性)中逐出该对象

//可以成功提交,因为hibernate在清理缓存时,在Session的insertions中集合中无法找到user对象所以不会发出insert语句,也不会更新session中existsInDatabase的状态。
tx.commit();

5.4 Transaction接口

 Transaction tx = null;
		try{
			tx = session.beginTransaction();
			session.save(obj);
			tx.commit();
		}catch(HibernateException e){
			if(tx != null){
				tx.rollback();
			}
			throw e;
		}finally{
			if(session != null){
				session.close();
			}
		}
	}
时间: 2024-09-20 09:35:02

第五章 Hibernate核心API介绍与其使用的相关文章

《HttpClient 官方文档》第五章 Fluent API

第五章:流式 API 5.1 易用 API 接口 4.2版本的 HttpClient 带来了一组非常容易使用的流式 API(Fluent API) 接口.暴露的流式API(Fluent API) 接口中仅仅是 HttpClient 最基本的一些功能,这些接口是在不需要使用 HttpClient 丰富的灵活性时,为了一些简单的功能而准备的. 例如:流式接口(Fluent API) 增加了使用者对连接的管理和资源的分配上的便利性.这里有一系列通过 HttpClient 流式接口(Fluent API

Android群英传笔记——第五章:Android Scroll分析

Android群英传笔记--第五章:Android Scroll分析 滑动事件算是Android比较常用的效果了,而且滑动事件他本身也是有许多的知识点,今天,我们就一起来耍耍Scroll吧 一.滑动效果是如何产生的 滑动一个View的本质其实就是移动一个View,改变其当钱所在的位置,他的原理和动画效果十分的相似,就是通过不断的改变View的坐标来实现这一效果,动态且不断的改变View的坐标,从而实现View跟随用户触摸滑动而滑动 但是在讲解滑动效果之前,需要先了解一下Android中窗口坐标体

第十一章 Hibernate的查询 Hibernate可以使用的查询语言

        我们在之前讲Hibernate的核心API的时候,我们知道可以通过Session对象根据实体类及id可以获取到单个数据对象.那么我们如果想像JDBC的使用一样,想通过一些特定的条件来获取我们想要的数据我们应该怎么样做呢.这就是我们今天要学习的内容--Hibernate的查询.         Session的查询相关的内容在第五章里面:http://blog.csdn.net/p_3er/article/details/8981465 Hibernate可以使用的查询语言如下几种

Hibernate核心接口简介

接口 在项目中使用Hibernate框架,非常关键的一点就是要了解Hibernate的核心接口.Hibernate接口位于业务层和持久化层,如图1所示. 图1 Hibernate核心接口的层次架构关系 Hibernate的核心接口一共有5个,分别为:Session.SessionFactory.Transaction.Query和Configuration.这5个核心接口在任何开发中都会用到.通过这些接口,不仅可以对持久化对象进行存取,还能够进行事务控制.下面对这五的核心接口分别加以介绍. ·S

SEO从零开始第五章——新闻源与百度敏感词

  营销手段中包含了SEO,SEO是营销一部分如果想在SEO界有所成就那一定要学会网络营销手段,网络营销会了SEO自然就会了,因为SEO是根本网络营销而变的.2013年5月28日百度外链工具全新升级,我记得在SEO从零开始第2章节说过,快照全部停留在27号,28号百度肯定有动作,百度拒绝外链技术越来越成熟, 回到正题,最近很多灰色行业在大量收购百度新闻源来做百度敏感词语,先说说我自己理解的原理,先知道原理然后再推荐百度如何针对这些问题.目前主流获得敏感词语排名的方案企业,新闻源站劫持获取排名.百

x264代码剖析(十五):核心算法之宏块编码中的变换编码

x264代码剖析(十五):核心算法之宏块编码中的变换编码           为了进一步节省图像的传输码率,需要对图像进行压缩,通常采用变换编码及量化来消除图像中的相关性以减少图像编码的动态范围.本文主要介绍变换编码的相关内容,并给出x264中变换编码的代码分析.   1.变换编码           变换编码将图像时域信号变换成频域信号,在频域中图像信号能量大部分集中在低频区域,相对时域信号,码率有较大的下降. H.264对图像或预测残差采用4×4整数离散余弦变换技术,避免了以往标准中使用的通

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【五】——在Web Api中实现Http方法(Put,Post,Delete)

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[五]--在Web Api中实现Http方法(Put,Post,Delete) 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在Web Api中,我们对资源的CRUD操作都是通过相应的Http方法来实现--Post(新增),Put(修改),Delete(删除),Get(查询).查询在前几章我们已经实现了,本章就在我们的案列(CourseController)

Html5 学习系列(五)Canvas绘图API快速入门(2)

Canvas绘图API Demos 上一篇文章中,笔者已经给大家演示了怎么快速用Canvas的API绘制一个矩形出来.接下里我会在本文中给各位介绍Canvas的其他API:绘制线条.绘制椭圆.绘制图片.图片处理等...如果想获得更好的阅读效果请点击老马的独立博客地址. 一.Canvas绘制线条     Context对象的beginPath方法表示开始绘制路径,moveTo(x, y)方法设置线段的起点,lineTo(x, y)方法设置线段的终点,stroke方法用来给透明的线段着色.movet

走近VB.Net(五) VB.Net核心概念

概念 走近VB.Net(五) VB.Net核心概念 VB.Net中文教程在行文上有些重复太多甚至有些啰嗦,以至让人读得索然无味,但是,这个VB.Net中文教程确实是很难得甚至可以说是经典的VB.Net文章.说老实一点,除了读得累一些外,实在是比我写的好多少倍.第二个问题就是很多人谈到很惨,说一切要从头学起,其实所要你学的不过是一些简单的语法变化,最重要的是观念的改变,也就是思维方式的转向,也就是说在经过了最初的摸索以后,你在VB6(我是不懂VB6的,我只懂一些D(不是你想的那个D),没有面向对象