Hibernate课堂笔记.docx

上传人:b****0 文档编号:9571883 上传时间:2023-05-20 格式:DOCX 页数:22 大小:23.65KB
下载 相关 举报
Hibernate课堂笔记.docx_第1页
第1页 / 共22页
Hibernate课堂笔记.docx_第2页
第2页 / 共22页
Hibernate课堂笔记.docx_第3页
第3页 / 共22页
Hibernate课堂笔记.docx_第4页
第4页 / 共22页
Hibernate课堂笔记.docx_第5页
第5页 / 共22页
Hibernate课堂笔记.docx_第6页
第6页 / 共22页
Hibernate课堂笔记.docx_第7页
第7页 / 共22页
Hibernate课堂笔记.docx_第8页
第8页 / 共22页
Hibernate课堂笔记.docx_第9页
第9页 / 共22页
Hibernate课堂笔记.docx_第10页
第10页 / 共22页
Hibernate课堂笔记.docx_第11页
第11页 / 共22页
Hibernate课堂笔记.docx_第12页
第12页 / 共22页
Hibernate课堂笔记.docx_第13页
第13页 / 共22页
Hibernate课堂笔记.docx_第14页
第14页 / 共22页
Hibernate课堂笔记.docx_第15页
第15页 / 共22页
Hibernate课堂笔记.docx_第16页
第16页 / 共22页
Hibernate课堂笔记.docx_第17页
第17页 / 共22页
Hibernate课堂笔记.docx_第18页
第18页 / 共22页
Hibernate课堂笔记.docx_第19页
第19页 / 共22页
Hibernate课堂笔记.docx_第20页
第20页 / 共22页
亲,该文档总共22页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

Hibernate课堂笔记.docx

《Hibernate课堂笔记.docx》由会员分享,可在线阅读,更多相关《Hibernate课堂笔记.docx(22页珍藏版)》请在冰点文库上搜索。

Hibernate课堂笔记.docx

Hibernate课堂笔记

Hibernate课堂笔记

一、Hibernate环境搭建

1)Hibernate3最后一个版本Hibernate3.6.10的环境搭建

1、导入项目所需要的包

hibernate3.jar,lib/required下的所有包和lib/jpa下的包

2、编写配置文件和映射文件

参考documentation\manual\zh-CN\html_single

1.1.4.Hibernate配置

1.1.3.映射文件

3、创建SessionFactory和Session

publicclassHibernateUtil{

privatestaticSessionFactorysessionFactory=null;

static{

sessionFactory=newConfiguration().configure().buildSessionFactory();

}

publicSessiongetSession(){

returnsessionFactory.openSession();

}

}

2)截至目前为止,Hibernate4最新版本Hibernate4.3.8的环境搭建

1、导入项目所需要的包

lib/required下的所有包

2、编写配置文件和映射文件

参考documentation\manual\en-US\html_single

1.1.4.Hibernateconfiguration

1.1.3.Themappingfile

3、创建SessionFactory和Session

publicclassHibernateUtil{

privatestaticSessionFactorysessionFactory=null;

static{

Configurationcfg=newConfiguration().configure();

ServiceRegistrysr=newStandardServiceRegistryBuilder().applySettings(cfg.getProperties()).build();

sessionFactory=cfg.buildSessionFactory(serviceRegistry);

}

publicSessiongetSession(){

returnsessionFactory.openSession();

}

}

 

二、Hibernate对象三种状态

Hibernate中的对象有三种状态:

瞬时状态(Transient),持久状态(Persistent),脱管状态(Detached)

1.瞬时状态(Transient)

由new命令开辟内存空间的Java对象,也就是平时所熟悉的普通Java对象。

如:

Studentstu=newStudent();

瞬时对象特点:

(1)不和Session实例关联

(2)在数据库中没有和瞬时对象关联的记录

2.持久状态(Persistent)

持久的实例在数据库中有对应的记录,并拥有一个持久化标识(identifier).

持久对象总是与Session和Transaction相关联,在一个Session中,对持久对象的改变不会马上对数据库进行变更,

而必须在Transaction终止,也就是执行commit()之后,才在数据库中真正运行SQL进行变更,持久对象的状态才会与数据库进行同步。

在同步之前的持久对象称为脏(dirty)对象。

瞬时对象转为持久对象:

(1)通过Session的save()和saveOrUpdate()方法把一个瞬时对象与数据库相关联,这个瞬时对象就成为持久化对象。

(2)使用get(),load()待方法查询到的数据对象,将成为持久化对象。

持久化对象的特点:

(1)和Session实例关联

(2)在数据库中有和持久对象关联的记录

3.脱管状态(Detached)

与持久对象关联的Session被关闭后,对象就变为脱管对象。

对脱管对象的引用依然有效,对象可继续被修改。

脱管对象特点:

(1)本质上和瞬时对象相同

(2)只是比瞬时对象多了一个数据库记录标识值id.

持久对象转为脱管对象:

当执行close()或clear(),evict()之后,持久对象会变为脱管对象。

瞬时对象转为持久对象:

通过Session的update(),saveOrUpdate()和lock()等方法,把脱管对象变为持久对象。

4.结合save(),update(),saveOrUpdate()方法说明对象的状态

(1)Save()方法将瞬时对象保存到数据库,对象的临时状态将变为持久化状态。

当对象在持久化状态时,它一直位于Session的缓存中,

对它的任何操作在事务提交时都将同步到数据库,因此,对一个已经持久的对象调用save()或update()方法是没有意义的。

如:

Studentstu=newStrudnet();

stu.setCarId(“200234567”);

stu.setId(“100”);

//打开Session,开启事务

session.save(stu);

stu.setCardId(“20076548”);

session.save(stu);//无效

session.update(stu);//无效

//提交事务,关闭Session

(2)update()方法两种用途重新关联脱管对象为持久化状态对象,显示调用update()以更新对象。

调用update()只为了关联一个脱管对象到持久状态,

当对象已经是持久状态时,调用update()就没有多大意义了。

如:

//打开session,开启事务

stu=(Student)session.get(Student.class,”123456”);

stu.setName(“Body”);

session.update(stu);//由于stu是持久对象,必然位于Session缓冲中,

对stu所做的变更将//被同步到数据库中。

所以update()是没有意义的,可以不要这句效果一样的。

//提交事务,关闭Session

Hibernate总是执行update语句,不管这个脱管对象在离开Session之后有没有更改过,在清理缓存时Hibernate总是发送一条update语句,

以确保脱管对象和数据库记录的数据一致,如:

Studentstu=newStrudnet();

stu.setCarId(“1234”);

//打开Session1,开启事务

session1.save(stu);

//提交事务,关闭Session1

stu.set(“4567”);//对脱管对象进行更改

//打开Session2,开启事务

session2.update(stu);

//提交事务,关闭Session2

如果希望只有脱管对象改变了,Hibernate才生成update语句,可以把映射文件中标签的select-before-update设为true,

这种会先发送一条select语句取得数据库中的值,判断值是否相同,如果相同就不执行update语句。

不过这种做法有一定的缺点,

每次update语句之前总是要发送一条多余的select语句,影响性能。

对于偶尔更改的类,设置才是有效的,对于经常要更改的类这样做是影响效率的。

(3)saveOrUpdate()方法兼具save()和update()方法的功能,对于传入的对象,saveOrUpdate()首先判断其是脱管对象还是临时对象,然后调用合适的方法。

 

三、load和get的区别

hibernate延迟加载(get和load的区别)

1.load加载方式

当使用load方法来得到一个对象时,此时hibernate会使用延迟加载的机制来加载这个对象,

即:

当我们使用session.load()方法来加载一个对象时,此时并不会发出sql语句,当前得到的这个对象其实是一个代理对象,这个代理对象只保存了实体对象的id值,

只有当我们要使用这个对象,得到其它属性时,这个时候才会发出sql语句,从数据库中去查询我们的对象。

       session=HibernateUtil.openSession();

/*

*通过load的方式加载对象时,会使用延迟加载机制,此时并不会发出sql语句,只有当我们需要使用的时候才会从数据库中去查询

*/

Useruser=(User)session.load(User.class,2);

我们看到,如果我们仅仅是通过load来加载我们的User对象,此时从控制台我们会发现并不会从数据库中查询出该对象,即并不会发出sql语句,但如果我们要使用该对象时:

      session=HibernateUtil.openSession();

      Useruser=(User)session.load(User.class,2);

      System.out.println(user);

此时我们看到控制台会发出了sql查询语句,会将该对象从数据库中查询出来

这个时候我们可能会想,那么既然调用load方法时,并不会发出sql语句去从数据库中查出该对象,那么这个User对象到底是个什么对象呢?

其实这个User对象是我们的一个代理对象,这个代理对象仅仅保存了id这个属性:

      session=HibernateUtil.openSession();

/*

*通过load的方式加载对象时,会使用延迟加载机制,此时得到的User对象其实是一个

*代理对象,该代理对象里面仅仅只有id这个属性

*/

Useruser=(User)session.load(User.class,2);

System.out.println(user.getId());

我们看到,如果我们只打印出这个user对象的id值时,此时控制台会打印出该id值,但是同样不会发出sql语句去从数据库中去查询。

这就印证了我们的这个user对象仅仅是一个保存了id的代理对象,但如果我需要打印出user对象的其他属性值时,这个时候会不会发出sql语句呢?

答案是肯定的:

session=HibernateUtil.openSession();

/*

*通过load的方式加载对象时,会使用延迟加载机制,此时得到的User对象其实是一个

*代理对象,该代理对象里面仅仅只有id这个属性

*/

Useruser=(User)session.load(User.class,2);

System.out.println(user.getId());

//如果此时要得到user其他属性,则会从数据库中查询

System.out.println(user.getUsername());

相信通过上述的几个例子,大家应该很好的了解了load的这种加载对象的方式了吧。

2、get加载方式

相对于load的延迟加载方式,get就直接的多,当我们使用session.get()方法来得到一个对象时,不管我们使不使用这个对象,

此时都会发出sql语句去从数据库中查询出来:

       session=HibernateUtil.openSession();

/*

*通过get方法来加载对象时,不管使不使用该对象,都会发出sql语句,从数据库中查询

*/

Useruser=(User)session.get(User.class,2);

此时我们通过get方式来得到user对象,但是我们并没有使用它,但是我们发现控制台会输出sql的查询语句

因此我们可以看到,使用load的加载方式比get的加载方式性能要好一些,因为load加载时,得到的只是一个代理对象,当真正需要使用这个对象时再去从数据库中查询。

3、使用get和load时的一些小问题

当了解了load和get的加载机制以后,我们此时来看看这两种方式会出现的一些小问题:

①如果使用get方式来加载对象,当我们试图得到一个id不存在的对象时,此时会报NullPointException的异常

      session=HibernateUtil.openSession();

/*

*当通过get方式试图得到一个id不存在的user对象时,此时会报NullPointException异常

*/

Useruser=(User)session.get(User.class,20);

System.out.println(user.getUsername());

此时我们看控制台的输出信息,会报空指针的异常

这是因为通过get方式我们会去数据库中查询出该对象,但是这个id值不存在,所以此时user对象是null,所以就会报NullPointException的异常了。

②如果使用load方式来加载对象,当我们试图得到一个id不存在的对象时,此时会报ObjectNotFoundException异常:

复制代码

      session=HibernateUtil.openSession();

/*

*当通过get方式试图得到一个id不存在的user对象时,此时会报ObjectNotFoundException异常

*/

Useruser=(User)session.load(User.class,20);

System.out.println(user.getId());

System.out.println(user.getUsername());

为什么使用load的方式和get的方式来得到一个不存在的对象报的异常不同呢?

其原因还是因为load的延迟加载机制,

使用load时,此时的user对象是一个代理对象,仅仅保存了当前的这个id值,当我们试图得到该对象的username属性时,

这个属性其实是不存在的,所以就会报出ObjectNotFoundException这个异常了。

③org.hibernate.LazyInitializationException异常

接下来我们再来看一个例子:

publicclassUserDAO

{

publicUserloadUser(intid)

{

Sessionsession=null;

Transactiontx=null;

Useruser=null;

try

{

session=HibernateUtil.openSession();

tx=session.beginTransaction();

user=(User)session.load(User.class,1);

mit();

}

catch(Exceptione)

{

e.printStackTrace();

tx.rollback();

}

finally

{

HibernateUtil.close(session);

}

returnuser;

}

}

  @Test

publicvoidtestLazy06()

{

UserDAOuserDAO=newUserDAO();

Useruser=userDAO.loadUser

(2);

System.out.println(user);

}

 

模拟了一个UserDAO这样的对象,然后我们在测试用例里面来通过load加载一个对象,此时我们发现控制台会报LazyInitializationException异常

org.hibernate.LazyInitializationException:

couldnotinitializeproxy-noSession  .............

这个异常是什么原因呢?

还是因为load的延迟加载机制,当我们通过load()方法来加载一个对象时,此时并没有发出sql语句去从数据库中查询出该对象,

当前这个对象仅仅是一个只有id的代理对象,我们还并没有使用该对象,但是此时我们的session已经关闭了,

所以当我们在测试用例中使用该对象时就会报LazyInitializationException这个异常了。

所以以后我们只要看到控制台报LazyInitializationException这种异常,就知道是使用了load的方式延迟加载一个对象了,

解决这个的方法有两种,一种是将load改成get的方式来得到该对象,另一种是在表示层来开启我们的session和关闭session。

总之对于get和load的根本区别,一句话,hibernate对于load方法认为该数据在数据库中一定存在,可以放心的使用代理来延迟加载,

如果在使用过程中发现了问题,只能抛异常;而对于get方法,hibernate一定要获取到真实的数据,否则返回null。

 

四、Hibernate主键生成策略

Hibernate各种主键生成策略与配置详解

1、assigned

主键由外部程序负责生成,在save()之前必须指定一个。

Hibernate不负责维护主键生成。

与Hibernate和底层数据库都无关,可以跨数据库。

在存储对象前,必须要使用主键的setter方法给主键赋值,至于这个值怎么生成,完全由自己决定,这种方法应该尽量避免。

特点:

可以跨数据库,人为控制主键生成,应尽量避免。

2、increment

由Hibernate从数据库中取出主键的最大值(每个session只取1次),以该值为基础,每次增量为1,在内存中生成主键,不依赖于底层的数据库,因此可以跨数据库。

Hibernate调用org.hibernate.id.IncrementGenerator类里面的generate()方法,使用selectmax(idColumnName)fromtableName语句获取主键最大值。

该方法被声明成了synchronized,所以在一个独立的Java虚拟机内部是没有问题的,然而,在多个JVM同时并发访问数据库selectmax时就可能取出相同的值,

再insert就会发生Dumplicateentry的错误。

所以只能有一个Hibernate应用进程访问数据库,否则就可能产生主键冲突,

所以不适合多进程并发更新数据库,适合单一进程访问数据库,不能用于群集环境。

官方文档:

只有在没有其他进程往同一张表中插入数据时才能使用,在集群下不要使用。

特点:

跨数据库,不适合多进程并发更新数据库,适合单一进程访问数据库,不能用于群集环境。

3、hilo

hilo(高低位方式highlow)是hibernate中最常用的一种生成方式,需要一张额外的表保存hi的值。

保存hi值的表至少有一条记录(只与第一条记录有关),否则会出现错误。

可以跨数据库。

hibernate_hilo

next_hi

100

hibernate_hilo指定保存hi值的表名

next_hi指定保存hi值的列名

100指定低位的最大值

也可以省略table和column配置,其默认的表为hibernate_unique_key,列为next_hi

100

hilo生成器生成主键的过程(以hibernate_unique_key表,next_hi列为例):

1.获得hi值:

读取并记录数据库的hibernate_unique_key表中next_hi字段的值,数据库中此字段值加1保存。

2.获得lo值:

从0到max_lo循环取值,差值为1,当值为max_lo值时,重新获取hi值,然后lo值继续从0到max_lo循环。

3.根据公式hi*(max_lo+1)+lo计算生成主键值。

注意:

当hi值是0的时候,那么第一个值不是0*(max_lo+1)+0=0,而是lo跳过0从1开始,直接是1、2、3……

那max_lo配置多大合适呢?

这要根据具体情况而定,如果系统一般不重启,而且需要用此表建立大量的主键,可以吧max_lo配置大一点,这样可以减少读取数据表的次数,提高效率;

反之,如果服务器经常重启,可以吧max_lo配置小一点,可以避免每次重启主键之间的间隔太大,造成主键值主键不连贯。

特点:

跨数据库,hilo算法生成的标志只能在一个数据库中保证唯一。

4、seqhilo

与hilo类似,通过hi/lo算法实现的主键生成机制,只是将hilo中的数据表换成了序列sequence,需要数据库中先创建sequence,适用于支持sequence的数据库,如Oracle。

hibernate_seq

100

特点:

与hilo类似,只能在支持序列的数据库中使用。

5、sequence

采用数据库提供的sequence机制生成主键,需要数据库支持sequence。

如oralce、DB、SAPDB、PostgerSQL、McKoi中的sequence。

MySQL这种不支持sequence的数据库则不行(可以使用identity)。

hibe

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 小学教育 > 小学作文

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2