上一篇文章我们简单介绍了Hibernate相关的一些最基本的文件及其作用,并在最后完整的搭建了Hibernate的运行环境,成功的完成了与数据库的映射。但是至于其中的一些更加细节的地方并没有很详尽的解释,本篇则主要介绍Hibernate中的一个关键元素,持久化类。主要涉及以下一些内容:

  • 定义用作持久化类的基本要求
  • 持久化对象的几种不同状态及其相互之间的转换
  • 使用Hibernate完成对数据库的crud操作

一、定义用作持久化类的基本要求

     所谓的持久化类其实本质上也就是一个普通的Java类,只不过我们通过配置文件让它与数据库中的某张表形成对应关系。虽然Hibernate号称低侵入式设计,对持久化类基本不做要求,但是实际上为了一些优化效率而言,遵守一定的规则则可以提高我们框架的运行效率。

     首先,在该类中需要提供一个无参的构造器。因为我们的持久化类和数据库中具体的数据表形成了映射,那么我们从数据库中取出的数据都会被转换成持久化类的对象返回,这里的无参构造器就是用于框架在反射时构建持久化类对象时候使用的。当然,这一点一般不用我们关心,在Java类中如果没有显式指定构造器都会有一个默认的无参构造器。

     其次,在该类中定义的属性,也就是用于与数据表的字段相对应的元素,它们需要满足Javabean规范,提供相对应的getter和setter方法。这一点毋庸置疑,和我们平常对类属性方法策略是相同的,但是如果有其他需要,也可以自定义访问策略,此处只是Hibernate建议。

     最后,该类不能不定义为final类。在Hibernate中通过生成代理对象来优化框架性能是很常见的操作,而大部分生成代理的方式是通过javassist生成持久化的子类进行代理,如果持久化被定义为final,显然是无法进行代理的。

     还有一些其他的规则需要遵守,但是由于并不是强制要求且只有在某些场景下才具有相应的应用价值,此处暂时不做介绍,等到相应的场景再进行补充。

二、持久化对象的三种不同的状态

     一个持久化对象对应于数据表中的一条记录,那么无论是对数据表的增加删除还是修改都是基于该持久化对象的。比如我想要插入一条记录到数据表中,我就可以new一个持久化对象并为其各个属性(对应于数据表的字段)赋值,然后映射到数据表中。这就是典型的以操作对象的方式操作数据库,但是这个持久化对象是有几种状态的,某个状态下对对象的修改是可以映射到数据表的,而某个状态下则不能作为持久化对象与数据表进行映射操作。而持久化对象主要有以下三个不同状态:

  • 瞬态:对象刚刚被new创建出来,只是一个普通的类对象。
  • 持久化:持久化对象与一个Hibernate Session相关联,在这个状态下,对象的所有属性值的改动,都是可以在事务结束时提交到数据库中的
  • 脱管:原本处于持久状态的对象因为其对应的Session被关闭,而失去持久化能力。此时的对象就处于脱管状态。一旦有Session愿意关联脱管对象,那么该对象就可以立马变为持久状态。

至于这三种不同状态下的相互转换可以用下面这张图很明显的表示出来:

其中,Transient表示瞬态,Persisitent表示持久化,Detached表示脱管状态。这张图同时也囊括了持久化对象的整个生命周期,至于其中各个方法的详细介绍,本篇的下一小节将陆续介绍,通过这些方法的调用来感受持久化对象的状态变化。

三、使用Hibernate完成对数据库的crud操作

     上述主要介绍了有关Hibernate持久化对象的一些基本状态等内容,但是对于上图中具体方法调用后,持久化对象状态改变情况并不是很直观。本小节就将从具体代码执行的结果看这些状态之间的切换,至于一些配置文件的内容此处不再编写(详见上篇文章,此处节约篇幅突出重点),首先我们看insert操作。

     1、持久化实体对象

     持久化实体对象也可以理解为插入一条记录到数据表中,反正最终都是让我们new出来的持久化对象和数据表中的某一行相关联。例如:

Transaction transaction = session.beginTransaction();

UserInfo user = new UserInfo();
user.setName("single");
user.setAge(21); session.save(user);
//提交事务
transaction.commit();
session.close();

此处只列出了最核心的一部分代码。我们首先创建了一个user的持久化对象,此时该对象只是一个普通Java对象并不具备持久化能力,这个状态就是瞬态。接着我们调用save方法,这个方法就会将user对象当前各个属性的值映射到数据库中,并且在save方法调用后,user这个对象此时的状态就变成了持久化状态。所以说,我们的插入操作也是持久化实体对象的一个过程。从Navicat中可以显然的看出来,新数据已经插入:

此时的user,只要session不关闭就可以不断的通过修改user属性的值来映射数据表。例如下面一段程序:

UserInfo user = new UserInfo();
user.setName("single");
user.setAge(21); session.save(user); user.setName("cyy");
//提交事务
transaction.commit();
session.close();

我们在save方法之后再次对user对象的属性进行修改,然后我们看保存到数据库中的是什么。

再看看控制台的输出:

显然,调用save方法,Hibernate会为我们生成一条insert语句,我们重新修改user对象的属性值,Hibernate又为我们生成了一条update语句。

但是在没有提交事务之前,所有的Sql语句对于数据库的操作都是预操作,并不会实际改变数据库。直到事务提交的时候,所有的操作才变为实际数据表的变化。还有几个和save相关的方法在这里简单介绍下:

  • Serializable save(Object var1):这是我们上述一直在使用的save方法,var1就是我们的持久化对象,通过调用该方法,Hibernate会为我们生成一条insert语句并立即对数据库进行一次预插入操作。最后返回该对象所对应的数据表中一行的主键值。
  • void persist(Object var1):这个方法所做的事情和save方法是一样的,都是将持久化对象的各个属性值去映射到数据表中的一行数据,只是不返回对应的主键的值。

除此之外,persisit方法和save方法还有一个重要区别。save方法在调用后会立马向数据库发送一条Sql,做一次预插入操作。而perisist方法采用懒加载机制,persist如果在事务之外调用,它不会立即向数据库发送Sql语句进行预插入,而是暂时被缓存直到清除缓存的时候才向数据进行插入。这样做有一个好处就是减少了对数据库的访问次数,但是缺点就在于数据库中的数据始终没有得到更新,容易产生脏数据读取。通过个例子看看:

UserInfo user = new UserInfo();
user.setName("single");
user.setAge(21); session.save(user);

我们将这段代码从事务中抽离出来单独执行,通过打断点可以看到在save方法调用结束之时控制台输出的信息:

显然,save方法调用结束就会立马对数据库进行预插入操作。下面我们看persisit方法:

UserInfo user = new UserInfo();
user.setName("single");
user.setAge(21); session.persist(user);
session.flush();

通过断点调试,可以看到perisist方法调用结束后,控制台并没有输出任何信息,反而在flush方法调用完毕之后,控制台输出insert语句。这就是persisit的懒加载思想,平常的一般操作首选save,在一些长会话流程的时候可以选择persist方法降低数据库压力。

     2、根据主键加载持久化实体

     以上我们可以通过save方法向数据库中插入一条记录,同样我们也可以使用get方法根据主键的值从数据库中加载出来一个持久化对象。下面我们看个例子,首先展示下userinfo表中内容:

接着我们使用Hibernate取出其中某条记录:

/*这里依然只是展示部分代码,说明问题即可*/
UserInfo user = (UserInfo)session.get(UserInfo.class,2);
System.out.println("name: "+user.getName()+",age: "+ user.getAge()); //提交事务
transaction.commit();

这里的get方法主要有两个参数,第一个参数指定要加载的数据表,第二个参数指定主键值。Hibernate将根据该主键的值进行加载,最后会返回一个Object对象。运行结果如下:

从运行结果来看,显然我们成功的根据主键值加载出来一个userInfo对象。除此之外,get方法调用结束后也会立即向数据库进行访问操作,这点和save方法是类似的。当然,如果主键的值不存在,那么将返回null,否则则会返回相对应的持久化对象。这里需要注意一点的是,我们的get方法是用于加载一个持久化对象的,而对于数据库的各种查询操作将在后文介绍。

     3、更新持久化实体

     除了insert和get,我们还可以通过操作持久化对象的属性值来修改数据表中的数据内容。例如:

UserInfo user = (UserInfo)session.get(UserInfo.class, 2);
user.setName("aaaa");
user.setAge(111); session.update(user); transaction.commit();
session.close();

程序比较简单,从数据库的变化来看,上述程序将主键值为2的记录name和age字段的信息做了修改。程序在控制台一共输出了两条Sql语句,一条是get方法调用结束生成的,一条是commit时候生成的update更新语句。也就是说update方法调用结束后并没有立即访问数据库,而是暂时存放在缓存中,等事务提交的时候在要求数据库执行。

     3、删除持久化实体

     Hibernate中提供delete方法通过持久化对象来删除数据表中的一行记录。例如:

//删除数据库中id为3的记录
UserInfo user = (UserInfo)session.get(UserInfo.class,3); session.delete(user); //提交事务
transaction.commit();
session.close();

首先我们获得数据表中id为3的一条记录的引用,然后直接调用delete方法删除该记录。同样的,Hibernate为我们生成两条Sql语句,一条是get生成的,一条是delete方法产生的,但是delete方法结束后并没有立即向数据库发送Sql语句,而是等到事务提交之时。

最后还要提到两个方法,这两个方法用于清除session中的持久化对象。

  • clear:调用该方法将清除与session绑定的所有持久化对象,这些对象统统变为脱管状态,或者说游离状态
  • evict:该方法有一个参数,调用该方法将显式指定清除session中的某个具体的持久化对象,调用完毕之后,该对象将处于游离状态

至此,有关持久化类及其生成的对象的相关知识,已经简单的介绍了,下篇我们将学习映射。总结不到之处,望指出。

初识Hibernate之理解持久化类的更多相关文章

  1. Hibernate中的持久化类

    一.持久化类概述 就是一个JavaBean,这个JavaBean与表建立了映射关系.这个类就称为是持久化类. 简单理解为 持久化类=JavaBean+映射文件. 持久化类:是指其实例需要被Hibern ...

  2. mybatis与hibernate常用的持久化类,及sqlsession和sqlsessionTemplate区别

    首先, 通过翻阅源码,我们来整理一下mybatis进行持久化操作时重要的几个类:SqlSessionFactoryBuilder:build方法创建SqlSessionFactory实例.SqlSes ...

  3. [原创]java WEB学习笔记77:Hibernate学习之路---Hibernate 版本 helloword 与 解析,.环境搭建,hibernate.cfg.xml文件及参数说明,持久化类,对象-关系映射文件.hbm.xml,Hibernate API (Configuration 类,SessionFactory 接口,Session 接口,Transaction(事务))

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  4. Hibernate学习——持久化类的学习

    A.概念 持久化:将内存中的对象持久化(存储)到数据库的过程.Hibernate就是持久化的框架. 持久化类:一个普通java对象与数据库的表建立了映射关系,那么这个类在Hiberna中被称为持久化类 ...

  5. Hibernate中持久化类与持久化对象

    1.JavaBean类 JavaBean类是实体类,必须一下属性,private修饰的成员属性,public修饰的getter与setter访问方法,public修饰的空参构造器,实现Serializ ...

  6. 三大框架 之 Hibernate生成策略与缓存策略(主键生成策略、持久化、持久化类划分、一级缓存、事物管理)

    目录 Hibernate生成策略与缓存策略 主键生成策略 主键分类 主键的生成策略 持久化 什么是持久化 什么是持久化类 持久化类编写规则 持久化类的划分 三种状态区分 持久态对象特征 一级缓存 什么 ...

  7. 三、hibernate中持久化类的使用

    hibernate的持久化类 持久化:将内存中的一个对象持久化到数据库中的过程,hibernate就是一个用来进行持久化的框架 持久化类:一个Java对象与数据库中表建立了关系映射,那么这个类在hib ...

  8. JEECG Hibernate 自动更新 持久化

    Hibernate不调用update却自动更新 - 七郎 - 博客园http://www.cnblogs.com/yangy608/p/4073941.html hibernate自动更新持久化类的问 ...

  9. 1.1Hibernate持久化类和Hibernate持久化对象状态

    一.持久化对象po类 1.po定义 PO,是Persistent Object的缩写,是持久化类.PO是由PO=POJO+hbm映射配置组成. 2.通俗理解 PO类即持久化类,其实就是一个普通的Jav ...

随机推荐

  1. Java基础---IO(一)---IO流概述、字符流、字节流、流操作规律

    第一讲     IO概述 概述 1.IO流:即InputOutput的缩写. 2.特点: 1)IO流用来处理设备间的数据传输. 2)Java对数据的操作是通过流的方式. 3)Java用于操作流的对象都 ...

  2. 7.7 WPF后台代码绑定如果是属性,必须指定一下数据上下文才能实现,而函数(click)就不用

    如: private bool _IsExportWithImage; /// <summary> /// 是否选择导出曲线图 /// </summary> public bo ...

  3. adb 安装apk 报错:Failure [INSTALL_FAILED_CPU_ABI_INCOMPATIBLE]

    这是因为系统里缺少了 Google Play 市场等各种谷歌服务应用,其实是因为版权问题,从 2.0 版本开始 Genymotion  提供的虚拟设备都已经移除了 Google Apps  以及 AR ...

  4. MySQL存储引擎中的MyISAM和InnoDB区别

    MyISAM是MySQL的默认数据库引擎(5.5版之前),由早期的ISAM(Indexed Sequential Access Method:有索引的顺序访问方法)所改良.虽然性能极佳,但却有一个缺点 ...

  5. UI设计基础知识和JavaScript

    [PS基础案例] 人物修图.调整画布大小,建立3个图层,并列放到画布中,用修补工具修掉中间的人物,再用橡皮章盖掉边缘的人物,然后扣出人物,放上新的蓝天,用橡皮擦调整透明度,擦掉水天交接的地方,然后调整 ...

  6. 认识大明星——轻量级容器docker知识树点亮

    docker是一个轻量级容器,属于操作系统层面的虚拟化技术,封装了文件系统(AUFS)以及网络互联,进程隔离等特性. 传统虚拟化架构: docker虚拟化架构: 可以看出,docker是没有Guest ...

  7. JVM启动参数设置

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt174 不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正 ...

  8. [转]Java7中的ForkJoin并发框架初探(上)——需求背景和设计原理

    详见: http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp83 这篇我们来简要了解一下JavaSE7中提供的一个新特性 -- For ...

  9. C语言中指针*p[N], (*P)[N],及**p的区别

    在C语言编程中指针经常困扰着我们,但是若能灵活运用指针的话,将会使得我们编程变得更加轻松与高效.这里讲下*p[N], (*P)[N],及**p的区别,这也是之前经常困扰我的地方. 这三者的定义分别为: ...

  10. IOS学习[Swift中跳转与传值]

    Swift中页面跳转与传值: 1.简单方式 首先,Swift的跳转可分为利用xib文件跳转与storyboard跳转两种方法,我这里选择使用storyboard的界面跳转方法. 1.通过在storyb ...