hibernate学习笔记

来源:互联网 发布:个人域名转企业域名 编辑:程序博客网 时间:2024/06/03 20:29

什么是hibernate?

一个java领域的持久化框架

持久化”包括和数据库相关的各种操作:

  • 保存:把对象永久保存到数据库中。
  • 更新:更新数据库中对象(记录)的状态。*
  • 删除:从数据库中删除一个对象。
  • 查询:根据特定的查询条件,把符合查询条件的一个或多个对象从数据库加载到内存中。
  • 加载:根据特定的OID,把一个对象从数据库加载到内存中。

ORM(Object/Relation Mapping): 对象/关系映射

类 ——> 表
对象—–> 行(记录)
属性 —–> 列(字段)

ORM的思想:将关系数据库中表中的记录映射成为对象,以对象的形式展现,程序员可以把对数据库的操作转化为对对象的操作。

hibernate开发步骤:

1、创建hibernate配置文件(hibernate.cfg.xm)

<!-- 配置连接数据库的基本信息 -->        <property name="connection.username">root</property>        <property name="connection.password">123456</property>        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>        <property name="connection.url">jdbc:mysql:///hibernate</property>        <!-- 配置 hibernate 的基本信息 -->        <!-- hibernate 所使用的数据库方言 -->        <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>                <!-- 执行操作时是否在控制台打印 SQL -->        <property name="show_sql">true</property>        <!-- 是否对 SQL 进行格式化 -->        <property name="format_sql">true</property>        <!-- 指定自动生成数据表的策略 -->        <property name="hbm2ddl.auto">update</property>        <!-- 指定关联的 .hbm.xml 文件 -->        <mapping resource="com/topview/helloworld/News.hbm.xml"/></mapping>  

2、创建持久化类 (persistent objects)
3、创建对象关系映射文件(*.hbm.xml)
4、通过hibernate API编写访问数据库的代码

//1. 创建一个 SessionFactory 对象        SessionFactory sessionFactory = null;        //1). 创建 Configuration 对象: 对应 hibernate 的基本配置信息和 对象关系映射信息        Configuration configuration = new Configuration().configure();        //4.0 之前这样创建//        sessionFactory = configuration.buildSessionFactory();        //2). 创建一个 ServiceRegistry 对象: hibernate 4.x 新添加的对象        //hibernate 的任何配置和服务都需要在该对象中注册后才能有效.        ServiceRegistry serviceRegistry =                 new ServiceRegistryBuilder().applySettings(configuration.getProperties())                                            .buildServiceRegistry();        //3).        sessionFactory = configuration.buildSessionFactory(serviceRegistry);        //2. 创建一个 Session 对象        Session session = sessionFactory.openSession();        //3. 开启事务        Transaction transaction = session.beginTransaction();        //4. 执行保存操作        News news = new News("Java12345", "ATGUIGU", new Date(new java.util.Date().getTime();        session.save(news);        //5. 提交事务         transaction.commit();        //6. 关闭 Session        session.close();        //7. 关闭 SessionFactory 对象        sessionFactory.close();  

持久化类的特点:

  • 提供一个无参的构造器,使hibernate能够通过反射(Constructor.newInstance())来实例化持久化类
  • 提供一个标识属性,通常映射为数据库表的主键,如若没有,一些功能将不起作用,如Session.saveOrUpdate()
  • get set 方法
  • 使用非final类:: 在运行时生成代理是 Hibernate 的一个重要的功能. (如延迟加载的时候)如果持久化类没有实现任何接口, Hibnernate使用 CGLIB 生成代理. 如果使用的是 final 类, 则无法生成 CGLIB 代理。
  • 重写 eqauls 和 hashCode 方法: 如果需要把持久化类的实例放到 Set 中(当需要进行关联映射时), 则应该重写这两个方法

Configuration类

负责管理 Hibernate 的配置信息。创造configutian的两种方式:

  • 使用hibernate.properties文件:Configuration cfg = new Configuration();
  • 使用hibernate.cfg.xml: Configuration cfg = new Configuration().configure();
  • 当然也可指定配置文件的位置:Configuration cfg = new Configuration().configure(File file);

SessionFactory接口

  • 生成session的工厂,一旦构建完成,则不再改变。是线程安全的。一般一个程序只实例化一个对象。
  • Hibernate4 新增了一个 ServiceRegistry接口,所有基于 Hibernate 的配置或者服务都必须统一向这个 ServiceRegistry 注册后才能生效。
  • 创建sessionFactory的步骤:
 Configuration configuration = new Configuration().configure();  ServiceRegistry serviceRegistry =                 new ServiceRegistryBuilder().applySettings(configuration.getProperties())              .buildServiceRegistry();sessionFactory = configuration.buildSessionFactory(serviceRegistry);

Session 接口

  • Session 接口是 Hibernate 向应用程序提供的操纵数据库的最主要的接口, 它提供了基本的保存, 更新, 删除和加载 Java 对象的方法.
  • Session 具有一个缓存, 位于缓存中的对象称为持久化对象, 它和数据库中的相关记录对应. Session 能够在某些时间点, 按照缓存中对象的变化来执行相关的 SQL 语句, 来同步更新数据库, 这一过程被称为刷新缓存(flush)
  • Session 的常用方法:
    1、取得持久化对象的方法: get() load()
    2、持久化对象都得保存,更新和删除:save(),update(),saveOrUpdate(),delete()
    3、开启事务: beginTransaction().
    4、管理 Session 的方法:isOpen(),flush(), clear(), evict(), close()等

Session缓存

  • 在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存. 只要 Session 实例没有结束生命周期, 且没有清理缓存,则存放在它缓存中的对象也不会结束生命周期
  • Session 缓存可减少 Hibernate 应用程序访问数据库的频率

flush缓存

  • flush:Session 按照缓存中对象的属性变化来同步更新数据库
  • 默认情况下 Session 在以下时间点刷新缓存:
    1、显式调用 Session 的 flush() 方法
    2、当应用程序调用 Transaction 的 commit()方法的时, 该方法先 flush ,然后在向数据库提交事务
    3、当应用程序执行一些查询(HQL, Criteria)操作时,如果缓存中持久化对象的属性已经发生了变化,会先flush 缓存,以保证查询结果能够反映持久化对象的最新状态
  • flush 缓存的例外情况: 如果对象使用 native 生成器生成 OID, 那么当调用 Session 的 save() 方法保存对象时, 会立即执行向数据库插入该实体的 insert 语句.(以保证该oid存在)
  • commit() 和 flush() 方法的区别:flush 执行一系列 sql语句,但不提交事务;commit 方法先调用flush() 方法,然后提交事务. 意味着提交事务意味着对数据库操作永久保存下来。

持久化对象的状态:

站在持久化的角度, Hibernate 把对象分为 4 种状态: 持久化状态, 临时状态, 游离状态, 删除状态. Session 的特定方法能使对象从一个状态转换到另一个状态
* 临时对象(Transient):在使用代理主键的情况下, OID 通常为 null,不处于 Session 的缓存中。在数据库中没有对应的记录。
* 持久化对象(也叫”托管”)(Persist):OID 不为 null,位于 Session 缓存中。若在数据库中已经有和其对应的记录, 持久化对象和数据库中的相关记录对应。Session 在 flush 缓存时, 会根据持久化对象的属性变化, 来同步更新数据库。在同一个 Session 实例的缓存中, 数据库表中的每条记录只对应唯一的持久化对象
* 删除对象(Removed):在数据库中没有和其OID对应的记录。不再处于session缓存中。
* 游离对象(也叫脱管)(Detached):OID不为空,不再处于session缓存中。

session的save()方法:
* 使一个临时对象转变为持久化对象。并把它加入到session缓存中。
* 选用映射文件指定的标识符生成器, 为持久化对象分配唯一的 OID. 在 使用代理主键的情况下, setId() 方法为 对象设置 OID 是无效的.

persist() 和 save() 区别:
当对一个 OID 不为 Null 的对象执行 save() 方法时, 会把该对象以一个新的 oid保存到数据库中; 但执行 persist() 方法时会抛出一个异常

session的get()和load()的区别:
* 当数据库中不存在与 OID 对应的记录时, load() 方法抛出 ObjectNotFoundException异常, 而 get() 方法返回 null
* 采用不同的延迟检索策略:load 方法支持延迟加载策略。而 get 不支持。

映射文件说明(hibernate-mapping):

  • <hibernate-mapping package="" default-lazy="true">
  • <class name="" table="" dynamic-insert="false" dynamic-update="false">
  • <id name="" column="" type=""><generator class=""/></id>(标识符生成器)
  • <property="" column="" length="" not-null="" unique=""/>
  • 当一个持久化类组合了其他类且该类没有oid属性,则用<component name="" class="">来映射
  • 单向多对一:<many-to-one name="" class="" column="" not-null=""/>
  • 双向多对一:
<set name="" table="" inverse="true" cascade="delete-orphan|save-update" order-by=""><key column=""/><one-to-many class=""/></set>
  • 基于外键的双向一对一映射:
    对于基于外键的1-1关联,其外键可以存放在任意一边,在需要存放外键一端,增加many-to-one元素。为many-to-one元素增加unique=“true” 属性来表示为1-1关联
    <many-to-one name="" class="" column="" cascade="" unique="true"/>
    另一端需要使用one-to-one元素,该元素使用 property-ref属性指定使用被关联实体主键以外的字段作为关联字段
    <one-to-one name="" class="" property-ref=""./>
  • 基于主键的双向一对一映射:
    指一端的主键生成器使用 foreign 策略,表明根据”对方”的主键来生成自己的主键,自己并不能独立生成主键. 子元素指定使用当前持久化类的哪个属性作为 “对方”.
<id name="" column=""><generator class="foreign"><param name="property">xxx</param></generator></id>

采用foreign主键生成器策略的一端增加 one-to-one 元素映射关联属性,其one-to-one属性还应增加 constrained=“true” 属性;另一端增加one-to-one元素映射关联属性。

<one-to-one name="" class="" constrained="true"/>
  • 单向n-n
    多对多的关联必须使用连接表。
    与 1-n 映射类似,必须为 set 集合元素添加 key 子元素,指定 中间表中参照 主表的外键。 与 1-n 关联映射不同的是,建立 n-n 关联时, 集合中的元素使用 many-to-many. many-to-many 子元素的 class 属性指定 集合中存放的对象, column 属性指定 中间表中参照 另一张表的外键。
 <set name="categories" table="CATEGORIES_ITEMS" inverse="true">            <key column="I_ID"></key>            <many-to-many class="com.topview.n2n.Category" column="C_ID"/></set>  
  • 双向n-n
    与单向n-n一样,但集合元素也应该添加映射。而且必须在其中一个指定inverse为true.否则两端都维护关联关系可能会造成主键冲突。

联合主键映射

1、将复合主键对应的属性与实体其它属性放在一起。

<composite-id>   <key-property name="id" column="" type=""/>   <key-property name="name" column=="" type""/></composite-id>

2、将主键属性提取到一个类中,实体类只需包含主键类的一个引用。

<composite-id name="" class="">   <key-property name="" column="" type=""/>    <key-property name="" column="" type=""/></composite-id>

注意:使用复合主键的实体类必须实现serializable接口,(与get(Class class,Serializable id)或load()有关).且必须重写equals和hashCode方法。

继承映射

1、subclass
* 父类和子类使用同一张表
* 因为父类和子类的实例全部保存在同一个表中,因此需要在该表内增加一列,使用该列来区分每行记录到低是哪个类的实例—-这个列被称为辨别者列(discriminator).
* 在这种映射策略下,使用 subclass 来映射子类,使用 class 或 subclass 的 discriminator-value 属性指定辨别者列的值
* 所有子类定义的字段都不能有非空约束。

 <class name="Person" table="PERSONS" discriminator-value="PERSON">     .....        <!-- 配置辨别者列 -->        <discriminator column="TYPE" type="string"></discriminator>        <!-- 映射子类 Student, 使用 subclass 进行映射 -->        <subclass name="Student" discriminator-value="STUDENT">            <property name="school" type="string" column="SCHOOL"></property>        </subclass>    </class>  

2、joined-subclass
* 每个子类一张表
* 父类实例保存在父类表中,子类实例由父类表和子类表共同存储。因为子类实例也是一个特殊的父类实例,因此必然也包含了父类实例的属性。于是将子类和父类共有的属性保存在父类表中,子类增加的属性,则保存在子类表中。
* 无须使用鉴别者列,但需要为每个子类使用 key 元素映射共有主键。子类增加的属性可以添加非空约束。

 <class name="Person" table="PERSONS">....      <joined-subclass name="Student" table="STUDENTS">            <key column="STUDENT_id"></key>            <property name="school" type="string" column="SCHOOL"></property>        </joined-subclass>    </class>  

3、union-subclass
* 每一个实体对象映射到一张独立的表中。子类实例的数据仅保存在子类表中。
* 使用 union-subclass 映射策略是不可使用 identity 的主键生成策略, 因为同一类继承层次中所有实体类都需要使用同一个主键种子, 即多个持久化实体对应的记录的主键应该是连续的. 受此影响, 也不该使用 native 主键生成策略, 因为 native 会根据数据库来选择使用 identity 或 sequence.

 <class name="Person" table="PERSONS">        <id name="id" type="java.lang.Integer">            <column name="ID" />            <generator class="hilo" />        </id>                .......        <union-subclass name="Student" table="STUDENTS">            <property name="school" column="SCHOOL" type="string"></property>        </union-subclass>            </class>  

HQL查询

  • 步骤:
    1、通过 Session 的 createQuery() 方法创建一个 Query 对象, 它包括一个 HQL 查询语句. HQL 查询语句中可以包含命名参数。
    2、动态绑定参数
    按参数名字绑定: 在 HQL 查询语句中定义命名参数, 命名参数以 “:” 开头.
    按参数位置绑定: 在 HQL 查询语句中用 “?” 来定义参数位置
    setEntity(): 把参数与一个持久化类绑定
    setParameter(): 绑定任意类型的参数. 该方法的第三个参数显式指定 Hibernate 映射类型
    3、调用 Query 相关方法执行查询语句.
  • HQL 查询语句是面向对象的, Hibernate 负责解析 HQL 查询语句, 然后根据对象-关系映射文件中的映射信息, 把 HQL 查询语句翻译成相应的 SQL 语句
    *Qurey 接口支持方法链编程风格, 它的 setXxx() 方法返回自身实例。
String hql = "SELECT e FROM Employee e INNER JOIN e.dept";Query query = session.createQuery(hql);List<Employee> emps = query.list();  
  • 分页查询:
    setFirstResult(intfirstResult): 设定从哪一个对象开始检索, 参数 firstResult表示这个对象在查询结果中的索引位置, 索引位置的起始值为 0. 默认情况下, Query 从查询结果中的第一个对象开始检索
    setMaxResults(intmaxResults): 设定一次最多检索出的对象的数目. 在默认情况下, Query 和 Criteria 接口检索出查询结果中所有的对象。
  • 命名查询
    在映射文件中定义命名查询语句:
<query name="salaryEmps"><![CDATA[FROM Employee e WHERE e.salary > :minSal AND e.salary < :maxSal]]></query>

元素用于定义一个 HQL 查询语句, 它和 元素并列.
在程序中通过 Session 的 getNamedQuery() 方法获取查询语句对应的 Query 对象.
Query query = session.getNamedQuery("salaryEmps");
* 投影查询
查询结果仅包含实体的部分属性. 通过 SELECT 关键字实现.
Query 的 list() 方法返回的集合中包含的是数组类型的元素, 每个对象数组代表查询结果的一条记录
可以在持久化类中定义一个对象的构造器来包装投影查询返回的记录, 使程序代码能完全运用面向对象的语义来访问查询结果集.
可以通过 DISTINCT 关键字来保证查询结果不会返回重复元素。
* 其他
可以使用group by 和having分组
还可以调用函数:count() max() min() avg()等

二级缓存

<!-- EHCache的配置,hibernate.cfg.xml --> <hibernate-configuration>    <session-factory>       <!-- 设置二级缓存插件EHCache的Provider类-->       <property name="hibernate.cache.provider_class">          org.hibernate.cache.EhCacheProvider       </property>       <!-- 启动"查询缓存" -->       <property name="hibernate.cache.use_query_cache">          true       </property>    </session-factory>  </hibernate-configuration><!-- ehcache.xml --><?xml version="1.0" encoding="UTF-8"?><ehcache>    <!--        缓存到硬盘的路径    -->    <diskStore path="d:/ehcache"></diskStore>    <!--        默认设置        maxElementsInMemory : 在內存中最大緩存的对象数量。        eternal : 缓存的对象是否永远不变。        timeToIdleSeconds :可以操作对象的时间。        timeToLiveSeconds :缓存中对象的生命周期,时间到后查询数据会从数据库中读取。        overflowToDisk :内存满了,是否要缓存到硬盘。    -->    <defaultCache maxElementsInMemory="200" eternal="false"         timeToIdleSeconds="50" timeToLiveSeconds="60" overflowToDisk="true"></defaultCache>    <!--        指定缓存的对象。        下面出现的的属性覆盖上面出现的,没出现的继承上面的。    -->    <cache name="com.suxiaolei.hibernate.pojos.Order" maxElementsInMemory="200" eternal="false"         timeToIdleSeconds="50" timeToLiveSeconds="60" overflowToDisk="true"></cache></ehcache><!-- *.hbm.xml --><?xml version="1.0" encoding='UTF-8'?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" ><hibernate-mapping>   <class>       <!-- 设置该持久化类的二级缓存并发访问策略 read-only read-write nonstrict-read-write transactional-->       <cache usage="read-write"/>       </class></hibernate-mapping><hibernate-mapping>        <class name="com.suxiaolei.hibernate.pojos.Customer" table="customer">            <!-- 主键设置 -->            <id name="id" type="string">                <column name="id"></column>                <generator class="uuid"></generator>            </id>            <!-- 属性设置 -->            <property name="username" column="username" type="string"></property>            <property name="balance" column="balance" type="integer"></property>            <set name="orders" inverse="true" cascade="all" lazy="false" fetch="join">                <cache usage="read-only"/>                <key column="customer_id" ></key>                <one-to-many class="com.suxiaolei.hibernate.pojos.Order"/>            </set>
0 0
原创粉丝点击