2.Hibernate

 

         

目录

                                          Hibernate

一、Hibernate是什么,它有什么作用?

二、Hibernate快速入门

三、Hibernate常用API 

四、Hibernate持久化类与主键生成策略

1.Hibernate持久化类

2.Hibernate主键生成策略

五、Hibernate持久化对象状态

六、Hibernate一、二级缓存

七、Hibernate关联映射--数据对象三种关系

1.一对一   唯一外键对应 或 主键对应

2.一对多(多对一)  在多添加外键  一个集合(一方)

3.多对多   中间表   两集合

八、Hibernate注解开发

         PO类注解配置

九、Hibernate检索方式概述

十、Hibernate事务管理

十一、Hibernate优化方案


                                Hibernate

一、Hibernate是什么,它有什么作用?

 Hibernate它是一个轻量级jdbc封装,也就是说,我们可以使用hibernate来完成原来我们使用jdbc完成操作,就是与数据库的交互操作。它是在dao层去使用的。

Hibernate框架基于ORM设计思想,它将关系型数据库中的表与我们java中的类进行映射,一个对象就对应着表中的一条记录,而表中的字段对应着类中的属性。

对象关系映射(英语:Object Relation Mapping,简称ORM

简说,我们使用orm可以将我们的对象与我们的类去进行映射,使的我们可以去操作对象就完成对表的操作。

配置文件将类与表进行映射

使用hinernate提供API来实现操作对象完成操作表的过程

二、Hibernate快速入门

      导入hibernate框架相关依赖jar包

1导入lib/required下所有的jar

2导入数据库的驱动jar包

3日志相关jar包

4 将hibernate/project/etc/log4j.properties日志文件导入到工程src下

      Hibernate的相关配置文件

1.xxx.hbm.xml 它主要是用于描述数据库中的表的映射关系。映射配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <!-- name属性它是实体类的全名 table 表的名称 catalog 数据库名称 -->
	<class name="www.huihex.dao.User" table="t_user"  catalog="test">
        <!-- id它是用于描述主键 --> <!-- java数据类型 -->
		<id name="id" column="id" type="int">  
			<!-- 主键生成策略 -->
			<generator class="native"></generator>
		</id>
		<!-- 使用property来描述属性与字段的对应关系 -->
		<!-- hibernate数据类型 -->
		<property name="name" column="name" length="20" type="string"></property>  
		<property name="age" column="age" length="20"></property>
		<property name="address">
		    <!-- sql数据类型 -->
			<column name="address" length="50" sql-type="varchar(50)"></column> 
		</property>
	</class>
</hibernate-mapping>

2.hibernate.cfg.xml 它是hibernate框架核心配置文件 。可以改变hibernate.cfg.xml的名字  一般不修改

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
		<!-- 配置关于数据库连接的四个项 driverClass url username password -->
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="hibernate.connection.url">jdbc:mysql:///test</property>
		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.connection.password">root</property>

		<!-- 设置连接提供者 -->
		<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
		<!-- c3p0连接池的配置 -->
		<property name="hibernate.c3p0.max_size">20</property> <!-- 最大连接池 -->
		<property name="hibernate.c3p0.min_size">5</property> <!-- 最小连接数 -->
		<property name="hibernate.c3p0.timeout">120</property> <!-- 超时 -->
		<property name="hibernate.c3p0.idle_test_period">3000</property> <!-- 空闲连接 -->
 		
		<!-- 可以将向数据库发送的sql显示出来 -->
		<property name="hibernate.show_sql">true</property>
		<!-- 格式化sql -->
		<property name="hibernate.format_sql">true</property>
		<!-- hibernate的方言 -->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

		<!-- 自动创建表 -->
	    <property name="hibernate.hbm2ddl.auto">update</property> 

		<!-- 用于设置事务提交方式  默认不自动提交 -->
	    <property name="hibernate.connection.autocommit">false</property> 

		<!-- 配置hibernate的映射文件所在位置 -->
		<mapping resource="www/huihex/dao/User.hbm.xml" />
	</session-factory>
</hibernate-configuration>

       Hibernate代码测试

package www.huihex.controller;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
import www.huihex.dao.User;

public class UserController {
	// 保存一个User
		@Test
		public void saveUser() {
			// 创建一个Customer
			User user = new User();
			user.setName("赵四");
			user.setAge(50);
			user.setAddress("上海市");

			// 使用hibernate的api来完成将customer信息保存到mysql中操作
			// 加载hibernate.cfg.xml
			Configuration config = new Configuration().configure(); 

			SessionFactory sessionFactory = config.buildSessionFactory();
			// 相当于得到一个Connection。
			Session session = sessionFactory.openSession(); 
			// 开启事务
			Transaction transaction = session.beginTransaction();
			// 操作
			session.save(user);
			// 事务提交
			transaction.commit();
			session.close();
			sessionFactory.close();
		}
}

       Hibernate执行原理总结

hibernate工作原理:

1、通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件

2、由hibernate.cfg.xml中的<mapping resource="com/xx/User.hbm.xml"/>读取解析映射信息。

3、通过config.buildSessionFactory();//得到sessionFactory。

4、sessionFactory.openSession();//得到session。

5、session.beginTransaction();//开启事务。

6、persistent operate; //执行操作

7、session.getTransaction().commit();//提交事务

8、关闭session;

9、关闭sessionFactory;

三、Hibernate常用API 

Configuration 、SessionFactory、Session、Transaction、Query(HQL、SQL)、Criteria。

update、saveorupdate、delete

四、Hibernate持久化类与主键生成策略

1.Hibernate持久化类

什么是持久化类?

Persistent Object  (PO)

PO=POJO+hbm映射配置。

对于hibernate中的PO编写规则:

1.必须提供一个无参数的public构造方法。

2.所有属性要private ,对外提供public 的get/set方法。

3.在PO类必须提供一个标识属性,让它与数据库中的主键对应,我们管这个属性叫OID。

4.PO类中的属性尽量使用基本数据类型的包装类。

Int-Integer  double--Double  float-Float

5.PO类它不能使用final修饰符。

OID作用:

       OID指的是与数据库中表的主键对应的属性。

       Hibernate框架它是通过OID来区分不同的PO对象,如果在内存中有两个相同的OID对象,那么hibernate认为它们是同一个对象。

为什么PO类属性它要使用包装类型?

使用基本数据类型是没有办法去描述不存在概念,如果使用包装类型,它就是一个对象,对于对象它的默认值是null。

PO类不可以使用final修饰?(hibernate中的get/load方法的区别)

Get/load方法它们都是根据id去查询对象。

     get直接得到了一个持久化类型对象,它就是立即查询操作。

     load它得到的是持久化类开的代理类型对象(子类对象)。它采用了一种延迟策略来查询数据。

     get方法在查询时,如果不存在返回null。

     load方法在查询时,如果 不存在,会产生异常 ObjectNotFoundException。

       2.Hibernate主键生成策略

Hibernate中定义的主键类型包括:自然主键和代理主键: 

自然主键:具有业务含义 字段 作为主键,比如:学号、身份证号。

代理主键:不具有业务含义 字段作为主键(例如 自增id),比如:mysql自增主键,oracle序列生成的主键、uuid()方法生成的唯一序列串。

建议:企业开发中使用代理主键!

主键生成器  increment  identity  sequence  native  uuid   assigned

五、Hibernate持久化对象状态

有三种:

  1. 瞬时态:也叫做临时态或自由态,它一般指我们new出来的对象,它不存在OID,与hibernate session无关联,在数据库中也无记录。它使用完成后,会被jvm直接回收掉,它只是用于信息携带。

简单说:无OID 与数据库中的信息无关联,不在session管理范围内。

    2.持久态:在hibernate session管理范围内,它具有持久化标识OID它的特点,在事务未提交前一直是持久             态,当它发生改变时,hibernate是可以检测到的。

简单说:有OID 由session管理,在数据库中有可能有,也有可有没有。

    3.托管态:也叫做游离态或离线态,它是指持久态对象失去了与session的关联,托管态对象它存在OID,在数          据库中有可能存在,也有可能不存在。

对于托管态对象,它发生改变时hibernet不能检测到。

测试

2.持久化类三种状态切换

判断持久化类对象三种状态:

1.是否有OID。

2.判断是否与session关联。

图示:

1.瞬时态(new 出来的)

瞬时------持久  save   saveOrUpdate

瞬时-----脱管(游离)  手动设置oid

2.持久态  它是由session管理

持久-----瞬时   delete() 被删除后持久化对象不在建议使用

持久-----脱管  注意:session它的缓存就是所说的一级缓存

                       evict(清除一级缓存 中指定的一个对象)

                       clear(清空一级缓存)

                       close(关闭,清空一级缓存)

3.脱管态  (它是无法直接获取)

脱管-----瞬时   直接将oid删除

脱管-----持久  update  saveOrUpdate lock(过时)

六、Hibernate一、二级缓存

Hibernate的一级缓存就是指session缓存。在session中定义了一系列的集合来存储数据,它们构成session 缓存。只要session没有关闭,它就会一直存在。

actionQueue它是一个行列队列,它主要记录crud操作的相关信息。

persistenceContext它是持久化上下文,它其实是真正缓存。

当我们通过hibernate中的session提供的一些API例如 save  get  update等进行操作时,就会将持久化对象            保存到session中,当下一次在去查询缓存中具有的对象(OID值来判断),就不会去从数据库查询,而是直接从缓存中获取。Hibernate的一级缓存存在的目的就是为了减少对数据库访问。

在hibernate中还有一个二级缓存,它是SessionFactory级别缓存。

持久化对象具有自动更新数据库能力(快照)

执行代码  发现控制台打印 查询和修改的SQL语句 数据库数据也修改了。

          为什么持久化对象具有自动更新数据库能力?

         

          当事物提交, session关闭, 向数据库发送请求时,会判断一级缓存的数据是否与快照区一致,如果不一致,就会发送             update语句。

七、Hibernate关联映射--数据对象三种关系

1.一对一   唯一外键对应 或 主键对应

        

2.一对多(多对一)  在多添加外键  一个集合(一方)

          

   

图一:双向关联 

图二:单向关联    希望保存订单时也保存客户  会报错   

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance               before flushing: cn.itheima.oneToMany.Customer

…………..

这个异常代表提一个持久化对象关联了一个瞬时对象。

       解决办法:级联操作

      我们现在要做的是保存订单时保存客户,需要在订单的hbm配置文件中修改 在设置《many-to-one cascade="save-update"

      设置cascade=save-update 那么在保存订单时就可以自动将客户保存。

      如果我们要完成保存客户时,保存订单,也使用cascade=save-update。

     在实际开发中

     我们在开发中要配置双向关联配置。---------可以通过任意一方来操作对方

     在操作代码,尽量来要进行单向关联。------可以尽量资源浪费。

    我们可以使用inverse属性来设置,双向关联时由哪一方来维护表与表之间的关系。

    关于inverse的取值:

    外键在哪一个表中,我们就让哪一方来维护外键。   

   级联删除   cascade=delete 

使用cascade可以完成级联操作

它可常用取值:

none这是一个默认值

save-update,当我们配置它时,底层使用save update或save-update完成操作,级联保存临时对象,如果是游离对象,会执行update.

delete 级联删除

delete-ophan 删除与当前对象解除关系的对象。

all 它包含了save-update  delete操作

all-delete-orphan 它包信了delete-orphan与all操作

3.多对多   中间表   两集合

        

八、Hibernate注解开发

           PO类注解配置

             我们最终需要在hibernate.cfg.xml文件中将我们类中的注解配置引用生效  《mapping class》

            问题:1.如果我们主键生成策略想使用UUID类型?

           

         问题2:如果设定类的属性不在表中映射?

        

           一对多(多对一)

          Customer类

         

          

          Order类

          

       测试保存客户时保存订单,但订单中没有关联客户的id,为什么?因为mappedBy  我们必须代码中手动关联

      多对多

Teacher类中

Student类中

九、Hibernate检索方式概述

       1导航对象图检索方式,根据已加载的对象导航到其它对象

2.OID检索方式,按照对象的OID来检索对象

3.HQL检索方式,使用面向对象的HQL查询语言

4.QBC检索方式,使用QBC(Query by Criteria)API来检索对象,这种API封装了基于字符串形式的查询语句,提供了更加面向对象的查询接口

5.本地SQL检索方式,使用本地数据库的SQL查询语句

Hql多表操作分类:

  1. 交叉连接
  2. 内连接
    1. 显示内连接
    2. 隐式内连接
    3. 迫切内连接 迫切内连接得到的结果是直接封装到PO类中,而内连接是Object[]数组,数组中封装是PO类对象。
  3. 外连接

左外连接

右外连接           

迫切左外连接       注意:在hibernate中有迫切连接的概念,而sql中没有。

十、Hibernate事务管理

           1.什么是事物

             事务就是逻辑上的一组操作,组成这组操作的各个单元要么全部成功,要么全都失败。

           2.事物的特性(ACID)

             原子性:不可分割

             一致性:事务在执行前后,要保证数据的一致。

             隔离性:一个事务在执行的过程中,不应该受到其它事务的干扰。

             持久性:事务一旦结束,数据持久化到数据库。

    3.问题:不考虑事务的隔离性,会产生什么问题?

       脏读:一个事务读取到另一个事务的未提交数据。

             不可重复读:一个事务读取到另一个事务提交的数据(主要是指update),会导致两次读取的结果不一致。

             虚读(幻读): 一个事务读取到另一个事务提交的数据(主要是指insert),会导致两次读取结果不一致。

            4.问题:对于上述问题如何解决?  设置隔离级别来解决

           READ_UNCOMMITED 读取未提交,它引发所有的隔离问题。

           READ_COMMITTED  读已提交,阻止脏读,可能发生不可重复读与虚读。

           REPEATABLE_READ 重复读  阻止脏读,不可重复读 可能发生虚读。

          SERIALIZABLE 串行化 解决所有问题 不允许两个事务,同时操作一个目标数据。(效率低下)

          ORACLE  默认的是事务隔离级别  READ_COMMITTED。

          MYSQL 默认的事务隔离级别  REPEATABLE_READ。

   5.Hibernate中设置事务隔离级别   

             在hibernate.cfg.xml文件中配置

     hibernate.connection.isolation可取的值有 1 2 4 8

        1代表的事务隔离级别为READ UNCOMMITTED

        2代表的事务隔离级别为READ COMMITTED

        4代表的事务隔离级别为 REPEATABLE READ

        8代表的事务隔离级别为 SERIALIZABLE

6. Hibernate提供了三种管理session的方式

   1.Session对象的生命周期与本地线程绑定(ThreadLocal)

   2.Session对象的生命周期与JTA事务绑定(分布式事务管理)

   3.Hibernate委托程序来管理Session的生命周期

   主要介绍关于本地线程绑定Session。

     步骤1:需要在hibernate.cfg.xml文件配置

     

    步骤2:  在获取session时不要在使用openSession而是使用getCurrentSession()方法。

十一、Hibernate优化方案

          HQL优化

         1.使用参数绑定

      使用绑定参数的原因是让数据库一次解析SQL,对后续的重复请求可以使用用生成好的执行计划,这样做节省CPU时间和内存。  避免SQL注入

        2.尽量少使用NOT 如果where子句中包含not关键字,那么执行时该字段的索引失效。

        3.尽量使用where来替换having

Having在检索出所有记录后才对结果集进行过滤,这个处理需要一定的开销,而where子句限制记录的数目,能减少这方面的开销

4.减少对表的查询

在含有子查询的HQL中,尽量减少对表的查询,降低开销

5.使用表的别名

当在HQL语句中连接多个表时,使用别名,提高程序阅读性,并把别名前缀与每个列上,这样一来,可以减少解析时间并减少列歧义引起的语法错误。

6.实体的更新与删除

在hibernate3以后支持hql的update与delete操作

 一级缓存优化  手动清除一级缓存

 检索策略(抓取策略)

延迟加载 是hibernate为提高程序执行的效率而提供的一种机制,即只有真正使用该对象的数据时才会创建。

load方法采用的策略延迟加载.

get方法采用的策略立即加载。

set上的fetch与lazy它主要是用于设置关联的集合信息的抓取策略。

Fetch可取值有:

SELECT 多条简单的sql   (默认值)

JOIN 采用迫切左外连接

SUBSELECT 将生成子查询的SQL

lazy可取值有:

TURE 延迟检索   (默认值)

FALSE 立即检索

EXTRA 加强延迟检索(及其懒惰)

发布了14 篇原创文章 · 获赞 0 · 访问量 452

猜你喜欢

转载自blog.csdn.net/qq_38118080/article/details/100022912