HIbernate基础

HIbernate基本运用

1. 什么是hibernate?

Hibernate是一个持久化框架,主要用来做对象持久化的,保存数据知识

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库.Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。

2. 什么是对象持久化?对象持久化有什么用?(解决的问题)

对象持久化就是把内存中的对象永久的保存起来,保护对象的状态,方便使用

对象持久化有什么用: 1.解决掉电的问题 2.共享方便 3.保证对象安全 4.检索方便

3. ORM(对象关系映射)是什么?有什么作用?

ORM 就是对象关系映射。详细一点,是面向对象编程中的对象(Object)和关系数据库的

关系(Relation)的一个映射(Mapping)

产生的原因是因为软件开发已经是面向对象的了。所有的值,操作都是基于对象的概念。

而数据库还是关系数据库。记录的存储还是一条一条的。为了在逻辑上使得软件开发与存取数据库保持一致。都按照对象的概念进行开发,存取,才出现了这种ormapping

实际上,如果面向对象数据库成为主流,ormapping就没用了。

好处:就是上面所属的逻辑上的一致性,开发人员不必管数据库怎么存储,

他只要知道要保存的也是一个对象(和他开发的概念一致)就可以了。

没有ORM之前,都是直接用SQL操作数据库,或者使用DAO之类的机制

进行对象概念到关系数据库概念的转换。

4. hibernate要素

POJO类:持久化对象,和数据库表进行对应

hibernate.cfg.xmlhibernate的核心配置文件,配置数据库连接信息,

Hibernate原数据,以及映射文件(*.hbm.xml)或者持久化类(annotation)

*.hbm.xml:将数据库表和pojo类进行一对应的配置文件

5 hibernate的编程步骤

java project--->add jars-->导入dtd(可略,验证,主要是实现帮助自动标识的功能)-->配置hibernate.cfg.xml---构建映射文件(将类和表建立映射关系)--- 测试类

Dtd导入,实现可联想;

 window——preference--xml catalog--add---对jar包起名字--添加jar

 

 *****以上是在pojo类中添加Annotation标注过程,注释具有自动联想功能***************

 1.创建表(truncate截断表,清空

2.构建projo类  设置属性和geter setter方法 无参和有参的构造方法

3.构建映射文件

4.测试对象

1构建数据库表

   create table employee(

   id number(7) constraint employee_id_pk primary key,

   name varchar2(10) constraint employee_name_nn not null,

   gender varchar2(10) constraint employee_gender_ck check(gender in('male’,’female')));

表已创建。

//注意:gender in(‘male’,’female’)  不是gender in(‘male,female’);

//这种都不会报错,只会当做gender in(‘  ’);一种

SQL> desc employee

 名称                                      是否为空? 类型

 ----------------------------------------- -------- ----------------------------

 

 ID                                        NOT NULL NUMBER(7)

 NAME                                      NOT NULL VARCHAR2(10)

 GENDER                                             VARCHAR2(10)

SQL> create sequence employee_id

   start with 1

   increment by 1;

序列已创建。

 

2)书写pojo实现序列化接口的类  Employee.java

package com.briup.hibernate.chap1;

public class Employee {

    private int id;

    private String name;

    private String gender;

    public Employee() {

super();

// TODO Auto-generated constructor stub

}

@Override

public String toString() {

return "Employee [id=" + id + ", name=" + name + ", gender=" + gender

+ "]";

}

public Employee(int id, String name, String gender) {

super();

this.id = id;

this.name = name;

this.gender = gender;

}

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getGender() {

return gender;

}

public void setGender(String gender) {

this.gender = gender;

}

}

3)书写employee.hbm.xml

 

Employee.hbm.xml :

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD/EN"

  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<!-- 注释标签

配置pojo文件和表之间的映射关系

class name 指定类名称-->

<class name ="com.briup.hibernate.chap1.Employee" table="employee">

<!-- 配置主键关联关系 column表示表中的列 -->

<id name="id" column ="id"></id>

<!-- 配置一般属性关联关系

如果属性名称和列的名称相同可以省略-->

<property name ="name"></property>

    <property name="gender"></property>

</class>

</hibernate-mapping>

4)将映射文件或者pojo类加入到hibernate.cfg.xml

Hibernate.cfg.xml文件:

<?xml version='1.0' encoding='utf-8'?> 

<!DOCTYPE hibernate-configuration

  PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"

  "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <property name="connection.driver_class">

        oracle.jdbc.driver.OracleDriver

        </property>

        <property name="connection.url">

         jdbc:oracle:thin:@127.0.0.1:1521:XE

        </property>

        <property name="connection.username">

         briup

        </property>

        <property name="connection.password">

         briup

        </property>

        <property name="connection.pool_size">

        1

        </property>

        <property name="dialect">

         org.hibernate.dialect.Oracle10gDialect

        </property>

        <property name="current_session_context_class">

         thread

        </property>

        <property name="cache.provider_class">

         org.hibernate.cache.NoCacheProvider

        </property>

        <property name="show_sql">

         true

        </property>

      <!-- 配置文件   通过hibernate类构建表的作用-->

      <mapping resource ="com/briup/hibernate/chap1/employee.hbm.xml"/>

    </session-factory>

</hibernate-configuration>

 

 

6主键生成方式

hibernate提供的一级缓存

hibernate是一个线程对应一个session(负责增删改查,查询事务),一个线程可以看成一个用户。也就是说session级缓存(一级缓存)只能给一个线程用,别的线程用不了,一级缓存就是和线程绑定了。

hibernate一级缓存生命周期很短,和session生命周期一样,一级缓存也称session级的缓存或事务级缓存。如果tb事务提交或回滚了,我们称session就关闭了,生命周期结束了。缓存和连接池的区别:缓存和池都是放在内存里,实现是一样的,都是为了提高性能的。但有细微的差别,池是重量级的,里面的数据是一样的,比如一个池里放100Connection连接对象,这个100个都是一样的。缓存里的数据,每个都不一样。比如读取100条数据库记录放到缓存里,这100条记录都不一样。

缓存主要是用于查询

Hibernate 二级缓存

二级缓存需要sessionFactory来管理,它是进初级的缓存,所有人都可以使用,它是共享的。二级缓存比较复杂,一般用第三方产品。hibernate提供了一个简单实现,用Hashtable做的,只能作为我们的测试使用,商用还是需要第三方产品。

使用缓存,肯定是长时间不改变的数据,如果经常变化的数据放到缓存里就没有太大意义了。因为经常变化,还是需要经常到数据库里查询,那就没有必要用缓存了。

hibernate做了一些优化,和一些第三方的缓存产品做了集成。老师采用EHCache缓存产品

/**

* API:

* 1.Configuration:这个类负责读取XML文档(映射配置文件)

* configure():xml   Configuration中的方法

* buildSessionFactory():创建一个生产session对象的工厂,其实是再次检查

SessionFactory  factory = configuration.buildSessionFactory()

返回一个SessionFactory对象,可以产生Session对象

* 因为hibernatejdbc不一样,jdbc是如果不手动设置开启事务,那它

* 就是马上执行sql,hibernate的不会马上执行,是事务提交后执行

* 默认情况下就是打开事务的状态,这里只是再检查以下

* 2.SessionFactory:负责生产session对象

* openSession():创建一个session

Session session = factory.openSession(); 用SessionFactory中的openSession方法创建Session对象,Session:这个是主要的类,负责增删改查,开启事务

* 3.Session:这个是主要的类,负责增删改查,开启事务等

* beginTransaction():产生一个事务对象(Transaction)

Transaction transaction = session.beginTransaction(); 

Session中的beginTransaction()方法返回Transaction对象,用于管理事务

* save():增加相当于操作sql中的insert语句

Employee employee = new Employee();//设置Employee里面的对象

employee.setId(2);

employee.setName("tom");

employee.setGender("male")

        session.save(employee); // 将employee对象插入

transaction.commit();  //提交

session.close();//关闭资源

* 4.Transaction:负责管理事务的

* commit():提交一个事务

*/

package com.briup.hibernate.chap1;

import org.hibernate.SessionFactory;

import org.hibernate.Transaction;

import org.hibernate.cfg.Configuration;

import org.hibernate.classic.Session;

public class EmployeeTest {

public static void main(String[] args) {

// 构建configuration用来读取hibernate.cfg.xml文件

Configuration configuration = new Configuration();

// 启动configuration方法

configuration.configure();

// 构建SeeionFActory工厂,用来创建session对象

SessionFactory  factory = configuration.buildSessionFactory();

// 构建session对象用来创建transaction对象

Session session = factory.openSession();

// 创建事务对象hibernate中事务并没有自动开启

// jdbc中的事务是自动开启的所以每次执行sql语句都不需要执行commit操作

// hibernate需要执行commit操作,数据才能够真正被写入到数据库中,所以要构建

// 事务,用户调用事务,手动进行commit操作

Transaction transaction = session.beginTransaction();

Employee employee = new Employee();

employee.setId(2);

employee.setName("tom");

employee.setGender("male");

// 通过save方法将Employee对象传给session对象

session.save(employee);

transaction.commit();

session.close();

}

}

1.assigned:

主键由外部程序负责生成,无需Hibernate参与。----如果要由程序代码来指定主键,就采有这种

<id name="id" column="id" type="string">

    <generator class="assigned" />

</id>

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD/EN"

  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<!-- 注释标签

配置pojo文件和表之间的映射关系

class name 指定类名称

-->

<class name ="com.briup.hibernate.chap1.Employee" table="employee">

<!-- 配置主键关联关系 column表示表中的列 -->

<id name="id" column ="id"></id>

<!-- 配置一般属性关联关系

如果属性名称和列的名称相同可以省略-->

<property name ="name"></property>

    <property name="gender"></property>

</class>

</hibernate-mapping>

 

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD/EN"

  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class name ="com.briup.hibernate.chap1.Employee" table="employee">

<id name="id" column ="id">

<generator class="assigned"></generator></id>

<!-- 配置一般属性关联关系

如果属性名称和列的名称相同可以省略-->

<property name ="name"></property>

    <property name="gender"></property>

</class>

</hibernate-mapping>

<generator class="increment"></generator> 不需要手动添加id,写的id还是按照原来的顺序执行 increment会产生两条sql语句,如果手动赋值无效

        employee.setId(10);  //语句无效 不是10

employee.setName("tom");

session.save(employee);

 

   ID NAME                 GENDER

----- -------------------- ----------

    1 tom                  male

    2 tom                  male

    3 tom                  male

 

SQL> drop sequence employee_id;

 

序列已删除。

SQL> create sequence employee_id

  2  start with 10

  3  increment by 2;

 

序列已创建。

<generator class="sequence">

<param name="sequence">employee_id</param>

</generator>

employee.setGender("male");

employee.setName("tom");

---------- -------------------- ---------

         1 tom                  male

         2 tom                  male

         3 tom                  male

        10 tom                  male

        12 tom                  male

        14 tom                  male

以2增加

Sequence会产生两个sql语句(select序列的下一个值,insert)

如果手动赋值id无效

 

Hilo只会产生一条sql语句效率高,

id值由hilo(高位值)*max_lo+lo(低位值)构成

<generator class="hilo">

<param name="table">hibernate_hilo</param>

<param name="colunm">next_id</param>

<param name="max_lo">100</param>

</generator>

 

<generator class="uuid"></generator>

 

SQL> select * from employee;

 

ID

------------------------------------------

NAME                 GENDER

-------------------- --------------------

4028f081547bbb1101547bbb12190000

tom                  male

 

4028f081547bbcfa01547bbcfb670000

tom                  male

 

 

 create table wife(

    id number(7) constraint  wife_id_pk primary key,

    name varchar2(10) constraint wife_name_nn not null,

    hus_id number(7) constraint wife_hus_id_fk references husband(id));

 

2.increment:

long 、short int 的数据列生成自动增长主键。increment主键生成方式的特点是与底层数据库无关性,大部分数据库如 MysqlMSSQL ORACLE等都支持increament生成方式。此方式的实现机制为在当前应用实例中维持一个变量,以保存着当前的最大值,之后每次需要生成主键的时候将此值加1作为主键。increment方式的不足之处是当多个线程并发对数据库表进行写操作时,可能出现相同的主键值,发生主键重复的冲突,因此多线程并发操作时,不应该使用此方法。

<id name="id" column="id">

    <generator class="increment" />

</id>

3.identity:

如果数据列的类型是 longshort int ,可使用主键生成器生成自动增长Hibernate主键。

与底层数据库有关,要求数据库支持identify,MySQL中是auto_increment,SQL Server中是Identify.

支持的数据库有MySQL,SQL Server,DB2,SybaseHypersonicSQL.(好像不支持oracle) 无需Hibernate和用户的干涉,

使用较为方便,但不便于在不同的数据库之间移植程序。identity的优点是不会发生 increment方式的并发错做问题。

数据库涉及到的表要设置自动增长。

<id name="id" column="id" type="long">

    <generator class="identity" />

</id>

4sequence:

ORACLE等数据库中使用sequence生成主键。sequence的特点是于数据库的相关性,seqhio要求底层能支持sequence,例如Oracle

数据库中的语法如下:

Oracle

create sequence seq_name

increment by 1

start with 1;

需要主键值时可以调用seq_name.nextval或者seq_name.curval得到,数据库会帮助我们维护这个sequence序列,保证每次取到的值唯一,如:

insert into tbl_name(id, name) values(seq_name.nextval, terry ren);

<id name="id" column="id" type="long">

    <generator class="sequence">

       <param name="sequence">seq_name</param>

   </generator>

</id>

5hilo:

HIbernate主键详解------Hilo

Hilo使用高低位算法生成主键,高低位算法使用一个高位值和一个低位值,然后把算法得到的两个值拼接起来作为数据库中的唯一主键。Hilo方式需要额外的数据库表和字段提供高位值来源。默认请况下使用的表是通过hi/lo 算法实现的主键生成机制,需要额外的数据库表保存主键生成历史状态。hibernate_unique_key,默认字段叫作next_hinext_hi必须有一条记录否则会出现错误。

特点:需要额外的数据库表的支持,能保证同一个数据库中主键的唯一性,但不能保证多个数据库之间主键的唯一性。Hilo主键生成方式由Hibernate维护,所以Hilo方式与底层数据库无关,但不应该手动修改hi/lo算法使用的表的值,否则会引起主键重复的异常

create table hi_value(next_hi number not null);

insert into hi_value(next_hi) values(1);

commit

<id name="id" column="id">

    <generator class="hilo">

       <param name="table">hi_value</param>

       <param name="column">next_hi</param>

       <param name="max_lo">100</param>

   </generator>

</id>

6seqhio:

hilo 类似,通过hi/lo 算法实现的主键生成机制,只是主键历史状态保存在Sequence中,适用于支持Sequence的数据库,

Oracle。如果数据列的类型是 longshort int可使用该主键生成器。

<id name="id" column="id">

   <generator class="seqhilo">

      <param name="sequence">seq_name</param>

      <param name="max_lo">100</param>

   </generator>

</id>

7native:

Hibernate根据不同的数据库方言,自行判断采用identityhilosequence其中一种作为Hibernate主键生成方式,

native的 优点是与底层性无关,便于不同数据库之间的移植,由Hibernate根据不同数据库选择主键的生成方式。

oracle中需要创建叫 Hibernate_sequence名字的sequence,如果设置了Hibernate.hbm2ddl.auto属性,

不需要手动建立序列,前提 是数据库帐号必须有Create Sequence这种高级权限。mysql等数据库则不用建立sequence

<id name="id" column="id">

    <generator class="native" />

</id>

8uuid.hex:

采用基于128位的算法生成唯一值,并编制成32位长度的唯一字符串作为主键值,uuid.hex的优点是支持大部分数据库,

缺点就是要占用较大的存储空间。对于并发Insert要求较高的系统,推荐采用uuid.hex 作为主键生成机制。

<id name="id" column="id">

    <generator class="uuid.hex" />

</id>

9uuid.string:

使用UUID算法,UUID被编码为一个16个字符长的任意ASCII字符组成的字符串。不能在PostgreSQL数据库中使用。uuid.stringuuid.hex类似,

需要占很大的存储空间。

10foreign:

使用外部表的字段作为Hibernate主键。

一般而言,利用uuid.hex方式生成Hibernate主键将提供最好的性能和数据库平台适应性。

11select

使用触发器生成主键(主要用于早期的数据库主键生成机制,少用)

另外由于常用的数据库,如OracleDB2SQLServerMySql 等,都提供了易用的主键生成机制(Auto-Increase 字段或者Sequence)。

我们可以在数据库提供的主键生成机制上采用generator-class=native的主键生成方式。不过值得注意的是,一些数据库提供的主键生成机制在效率上未必最佳,大量并发insert数据时可能会引起表之间的互锁。数据库提供的主键生成机制,往往是通过在一个内部表中保存当前主键状态(如对于自增型主键而言,此内部表中就维护着当前的最大值和递增量),之后每次插入数据会读取这个最大值,然后加上递增量作为新记 录的主键,之后再把这个新的最大值更新回内部表中,这样,一次Insert操作可能导致数据库内部多次表读写操作,同时伴随的还有数据的加锁解锁操作,这对性能产生了较大影响。因此,对于并发Insert要求较高的系统,推荐采用uuid作为主键生成机制。

7hibernate tags

    <hibernate-mapping  

             schema="schemaName"                          (1)  

             catalog="catalogName"                        (2)  

             default-cascade="cascade_style"              (3)  

             default-access="field|property|ClassName"    (4)  

             default-lazy="true|false"                    (5)  

             auto-import="true|false"                     (6)  

             package="package.name"                       (7)  

     />  

(1)  schema (可选): 数据库schema的名称。

(2)  catalog (可选): 数据库catalog的名称。

(3)  default-cascade (可选 - 默认为 none): 默认的级联风格。

(4)  default-access (可选 - 默认为 property): Hibernate用来访问所有属性的策略。可以通过实现PropertyAccessor接口 自定义。

(5)  default-lazy (可选 - 默认为 true): 指定了未明确注明lazy属性的Java属性和集合类, Hibernate会采取什么样的默认加载风格。

(6)  auto-import (可选 - 默认为 true): 指定我们是否可以在查询语言中使用非全限定的类名(仅限于本映射文件中的类)。

(7)  package (可选): 指定一个包前缀,如果在映射文档中没有指定全限定的类名, 就使用这个作为包名。

假若你有两个持久化类,它们的非全限定名是一样的(就是两个类的名字一样,所在的包不一样--译者注),

你应该设置auto-import="false"。如果你把一个“import过”的名字同时对应两个类, Hibernate会抛出一个异常。

 ==================

 

<class  

            name="ClassName"                              (1)  

            table="tableName"                             (2)  

            discriminator-value="discriminator_value"     (3)  

            mutable="true|false"                          (4)  

            schema="owner"                                (5)  

            catalog="catalog"                             (6)  

            proxy="ProxyInterface"                        (7)  

            dynamic-update="true|false"                   (8)  

            dynamic-insert="true|false"                   (9)  

            select-before-update="true|false"             (10)  

            polymorphism="implicit|explicit"              (11)  

            where="arbitrary sql where condition"         (12)  

            persister="PersisterClass"                    (13)  

            batch-size="N"                                (14)  

            optimistic-lock="none|version|dirty|all"      (15)  

            lazy="true|false"                             (16)  

            entity-name="EntityName"                      (17)  

            check="arbitrary sql check condition"         (18)  

            rowid="rowid"                                 (19)  

            subselect="SQL expression"                    (20)  

            abstract="true|false"                         (21)  

            node="element-name"  

    />  

(1) name (可选): 持久化类(或者接口)的Java全限定名。 如果这个属性不存在,Hibernate将假定这是一个非POJO的实体映射。

(2) table (可选 - 默认是类的非全限定名): 对应的数据库表名,生成DDL时数据表名,如果省略,则名称同持久化类名称。

(3) discriminator-value (可选 - 默认和类名一样): 一个用于区分不同的子类的值,在多态行为时使用.它可以接受的值包括 null not null

    (4) mutable (可选,默认值为true): 表明该类的实例是可变的或者不可变的。

    (5) schema (可选): 覆盖在根<hibernate-mapping>元素中指定的schema名字。

    (6) catalog (可选): 覆盖在根<hibernate-mapping>元素中指定的catalog名字。

    (7) proxy (可选): 指定一个接口,在延迟装载时作为代理使用。 你可以在这里使用该类自己的名字。

    (8) dynamic-update (可选, 默认为 false): 指定用于UPDATE SQL将会在运行时动态生成,并且只更新那些改变过的字段

    (只更新修改的字段,没有修改的字段不进行更新)

    (9) dynamic-insert (可选, 默认为 false): 指定用于INSERTSQL 将会在运行时动态生成,并且只包含那些非空值字段

    (在添加记录时,只添加非null的字段)

    (10) select-before-update (可选, 默认为 false): 指定Hibernate除非确定对象真正被修改了(如果该值为true-译注),

    否则不会执行SQL UPDATE操作。在特定场合(实际上,它只在一个瞬时对象(transient object)关联到一个 新的session中时

    执行的update()中生效),这说明Hibernate会在UPDATE 之前执行一次额外的SQL SELECT操作,来决定是否应该执行 UPDATE

    (11) polymorphism(多态) (可选, 默认值为 implicit (隐式) ): 界定是隐式还是显式的使用多态查询

    (这只在Hibernate的具体表继承策略中用到-译注)。

    (12) where (可选) 指定一个附加的SQLWHERE 条件, 在抓取这个类的对象时会一直增加这个条件。

    (13) persister (可选): 指定一个定制的ClassPersister

    (14) batch-size (可选,默认是1) 指定一个用于 根据标识符(identifier)抓取实例时使用的"batch size"(批次抓取数量)。

    (15) optimistic-lock(乐观锁定) (可选,默认是version): 决定乐观锁定的策略。

    (16) lazy (可选): 通过设置lazy="false", 所有的延迟加载(Lazy fetching)功能将被全部禁用(disabled)。

    (17) entity-name (可选,默认为类名): Hibernate3允许一个类进行多次映射( 前提是映射到不同的表),并且允许使用MapsXML代替Java层次的实体映射 (也就是实现动态领域模型,不用写持久化类-译注)。     (18) check (可选): 这是一个SQL表达式, 用于为自动生成的schema添加多行(multi-row)约束检查。

    (19) rowid (可选): Hibernate可以使用数据库支持的所谓的ROWIDs,例如: Oracle数据库,如果你设置这个可选的rowidHibernate可以使用额外的字段rowid实现快速更新。ROWID是这个功能实现的重点, 它代表了一个存储元组(tuple)的物理位置。

    (20) subselect (可选): 它将一个不可变(immutable)并且只读的实体映射到一个数据库的 子查询中。当你想用视图代替一张基本表的时候,这是有用的,但最好不要这样做。更多的介绍请看下面内容。

    (21)abstract (可选): 用于在<union-subclass>的继承结构 (hierarchies)中标识抽象超类。

 

若指明的持久化类实际上是一个接口,这也是完全可以接受的。 之后你可以用元素<subclass>来指定该接口的实际实现类。

 你可以持久化任何static(静态的)内部类。 你应该使用标准的类名格式来指定类名,比如:Foo$Bar

不可变类,mutable="false"不可以被应用程序更新或者删除。 这可以让Hibernate做一些小小的性能优化。

可选的proxy属性允许延迟加载类的持久化实例。 Hibernate开始会返回实现了这个命名接口的CGLIB代理。当代理的某个方法被实际调用的时候,真实的持久化对象才会被装载。参见下面的“用于延迟装载的代理”。

Implicit (隐式)的多态是指,如果查询时给出的是任何超类、该类实现的接口或者该类的 名字,都会返回这个类的实例;

如果查询中给出的是子类的名字,则会返回子类的实例。 Explicit (显式)的多态是指,只有在查询时给出明确的该类名字时才会

返回这个类的实例; 同时只有在这个<class>的定义中作为<subclass> 或者<joined-subclass>出现的子类,才会可能返回。

在大多数情况下,默认的polymorphism="implicit"都是合适的。 显式的多态在有两个不同的类映射到同一个表的时候很有用。

(允许一个“轻型”的类,只包含部分表字段)。

persister属性可以让你定制这个类使用的持久化策略。 你可以指定你自己实现 org.hibernate.persister.EntityPersister的子类,

你甚至可以完全从头开始编写一个 org.hibernate.persister.ClassPersister接口的实现, 比如是用储存过程调用、序列化到文件

或者LDAP数据库来实现。 参阅org.hibernate.test.CustomPersister,这是一个简单的例子 (“持久化”到一个Hashtable)。

 

请注意dynamic-updatedynamic-insert的设置并不会继承到子类, 所以在<subclass>或者<joined-subclass>元素中可能 需要再次设置。

这些设置是否能够提高效率要视情形而定。请用你的智慧决定是否使用。

使用select-before-update通常会降低性能。如果你重新连接一个脱管(detache)对象实例 到一个Session中时,

它可以防止数据库不必要的触发update。 这就很有用了。

如果你打开了dynamic-update,你可以选择几种乐观锁定的策略:

    version(版本检查) 检查version/timestamp字段

    all(全部) 检查全部字段

    dirty(脏检查)只检察修改过的字段

    none(不检查)不使用乐观锁定

我们非常强烈建议你在Hibernate中使用version/timestamp字段来进行乐观锁定。 对性能来说,这是最好的选择,

并且这也是唯一能够处理在session外进行操作的策略(例如: 在使用Session.merge()的时候)。

Hibernate映射来说视图和表是没有区别的,这是因为它们在数据层都是透明的( 注意:一些数据库不支持视图属性,特别是更新的时候)。

有时你想使用视图,但却不能在数据库 中创建它(例如:在遗留的schema中)。这样的话,你可以映射一个不可变的(immutable

并且是 只读的实体到一个给定的SQL子查询表达式:

 java代码:

    <class name="Summary">  

        <subselect>  

            select item.name, max(bid.amount), count(*)  

            from item  

            join bid on bid.item_id = item.id  

            group by item.name  

        </subselect>  

        <synchronize table="item"/>  

        <synchronize table="bid"/>  

        <id name="name"/>  

        ...  

    </class>  

定义这个实体用到的表为同步(synchronize),确保自动刷新(auto-flush)正确执行, 并且依赖原实体的查询不会返回过期数据。<subselect>在属性元素 和一个嵌套映射元素中都可见。

=========================

<id

       name="propertyName"                      

       type="typename"                          

       column="column_name"                     

       unsaved-value="any|none|null|id_value"   

       access="field|property|ClassName">       

       <generator class="generatorClass"/>

</id>

name (可选): 标识属性的名字。

type (可选): 标识Hibernate类型的名字。

column (可选 - 默认为属性名): 主键字段的名字。

unsaved-value (可选 - 默认为null): 一个特定的标识属性值,用来标志该实例是刚刚创建的,尚未保存。这可以把这种实例和从以前的session中装载过(可能又做过修改--译者注)但未再次持久化的实例区分开来。

access (可选 - 默认为property): Hibernate用来访问属性值的策略。

如果 name属性不存在,会认为这个类没有标识属性。

unsaved-value 属性很重要!如果你的类的标识属性不是默认为null的,你应该指定正确的默认值。

还有一个另外的<composite-id>声明可以访问旧式的多主键数据。我们强烈不鼓励使用这种方式。

1. generator

必须声明的<generator>子元素是一个Java类的名字,用来为该持久化类的实例生成唯一的标识。如果这个生成器实例需要某些配置值或者初始化参数,用<param>元素来传递。

 

<id name="id" type="long" column="uid" unsaved-value="0">

       <generator class="net.sf.hibernate.id.TableHiLoGenerator">

               <param name="table">uid_table</param>

               <param name="column">next_hi_value_column</param>

       </generator>

</id>

所有的生成器都实现net.sf.hibernate.id.IdentifierGenerator接口。这是一个非常简单的接口;某些应用程序可以选择提供他们自己特定的实现。当然,Hibernate提供了很多内置的实现。下面是一些内置生成器的快捷名字:

increment(递增)

用于为long, short或者int类型生成唯一标识。只有在没有其他进程往同一张表中插入数据时才能使用。 在集群下不要使用。

identity

DB2,MySQL, MS SQL Server, SybaseHypersonicSQL的内置标识字段提供支持。返回的标识符是long, short 或者int类型的。

sequence (序列)

DB2,PostgreSQL, Oracle, SAP DB, McKoi中使用序列(sequence),而在Interbase中使用生成器(generator)。返回的标识符是long, short或者 int类型的。

hilo (高低位)

使用一个高/低位算法来高效的生成long, short或者 int类型的标识符。给定一个表和字段(默认分别是是hibernate_unique_key next)作为高位值得来源。高/低位算法生成的标识符只在一个特定的数据库中是唯一的。在使用JTA获得的连接或者用户自行提供的连接中,不要使用这种生成器。

seqhilo(使用序列的高低位)

使用一个高/低位算法来高效的生成long, short或者 int类型的标识符,给定一个数据库序列(sequence)的名字。

uuid.hex

用一个128-bitUUID算法生成字符串类型的标识符。在一个网络中唯一(使用了IP地址)。UUID被编码为一个3216进制数字的字符串。

 

uuid.string

使用同样的UUID算法。UUID被编码为一个16个字符长的任意ASCII字符组成的字符串。不能使用在PostgreSQL数据库中

native(本地)

根据底层数据库的能力选择identity, sequence 或者hilo中的一个。

assigned(程序设置)

让应用程序在save()之前为对象分配一个标示符。

foreign(外部引用)

使用另外一个相关联的对象的标识符。和<one-to-one>联合一起使用。

2. /低位算法(Hi/Lo Algorithm

hilo seqhilo生成器给出了两种hi/lo算法的实现,这是一种很令人满意的标识符生成算法。第一种实现需要一个“特殊”的数据库表来保存下一个可用的“hi”值。第二种实现使用一个Oracle风格的序列(在被支持的情况下)。

<id name="id" type="long" column="cat_id">

       <generator class="hilo">

               <param name="table">hi_value</param>

               <param name="column">next_value</param>

               <param name="max_lo">100</param>

       </generator>

</id>

<id name="id" type="long" column="cat_id">

       <generator class="seqhilo">

               <param name="sequence">hi_value</param>

               <param name="max_lo">100</param>

       </generator>

</id>

很不幸,你在为Hibernate自行提供Connection,或者Hibernate使用JTA获取应用服务器的数据源连接的时候无法使用hilo 。Hibernate必须能够在一个新的事务中得到一个"hi"值。在EJB环境中实现hi/lo算法的标准方法是使用一个无状态的session bean

 

3. UUID算法(UUID Algorithm

UUID包含:IP地址,JVM的启动时间(精确到1/4秒),系统时间和一个计数器值(在JVM中唯一)。在Java代码中不可能获得MAC地址或者内存地址,所以这已经是我们在不使用JNI的前提下的能做的最好实现了。

不要试图在PostgreSQL中使用uuid.string

4. 标识字段和序列(Identity Columns and Sequences

对于内部支持标识字段的数据库(DB2,MySQL,Sybase,MS SQL),你可以使用identity关键字生成。对于内部支持序列的数据库(DB2,Oracle, PostgreSQL, Interbase, McKoi,SAP DB),你可以使用sequence风格的关键字生成。这两种方式对于插入一个新的对象都需要两次SQL查询。

<id name="id" type="long" column="uid">

       <generator class="sequence">

               <param name="sequence">uid_sequence</param>

       </generator>

</id>

<id name="id" type="long" column="uid" unsaved-value="0">

       <generator class="identity"/>

</id>

     对于跨平台开发,native策略会从identity, sequence hilo中进行选择,取决于底层数据库的支持能力。

下面再给个简单例子:

<id name="id" type="long" column="uid">

   <generator class="sequence">

       <param name="sequence">uid_sequence</param>

   </genarator>

</id>

注意:

<generator class=""> 里面可以选啊!推荐Oraclesequenceseqhilo

================

<property>元素为类定义了一个持久化的,JavaBean风格的属性。   

<property  

        name="propertyName"                                          (1)  

        column="column_name"                                         (2)  

        type="typename"                                              (3)  

        update="true|false"                                          (4)  

        insert="true|false"                                          (4)  

        formula="arbitrary SQL expression"                           (5)  

        access="field|property|ClassName"                            (6)  

        lazy="true|false"                                            (7)  

        unique="true|false"                                          (8)  

        not-null="true|false"                                        (9)  

        optimistic-lock="true|false"                                 (10)  

        generated="never|insert|always"                              (11)  

        node="element-name|@attribute-name|element/@attribute|."  

  

        index="index_name"  

        unique_key="unique_key_id"  

        length="L"  

        precision="P"  

   scale="S"  

/>  

(1) name: 实体类属性的名字,以小写字母开头。

(2) column (可选 - 默认为属性名字): 对应的数据库字段名。 也可以通过嵌套的<column>元素指定。(如果省略则使用,则使用name所指定的名称为字段名)

(3) type (可选): 一个Hibernate类型的名字(省略则使用hibernate默认类型),也可以自己配置其它hbernate类型(integer, long, short, float, double, character, byte, boolean, yes_no, true_false)

(4) update, insert (可选 - 默认为 true) : 表明用于UPDATE /INSERT SQL语句中是否包含这个被映射了的字段。这二者如果都设置为false 则表明这是一个“外源性(derived)”的属性,它的值来源于映射到同一个(或多个) 字段的某些其他属性,或者通过一个trigger(触发器)或其他程序生成。

(5) formula (可选): 一个SQL表达式,定义了这个计算 (computed) 属性的值。计算属性没有和它对应的数据库字段。

(6) access (可选 - 默认值为 property): Hibernate用来访问属性值的策略。

(7) lazy (可选 - 默认为 false): 指定 指定实例变量第一次被访问时,这个属性是否延迟抓取(fetched lazily)( 需要运行时字节码增强)。

(8) unique (可选): 使用DDL为该字段添加唯一的约束。 同样,允许它作为property-ref引用的目标。

(9) not-null (可选): 使用DDL为该字段添加可否为空(nullability)的约束。

(9) length(可选):typevarchar时,设置字段长度

(10) optimistic-lock (可选 - 默认为 true): 指定这个属性在做更新时是否需要获得乐观锁定(optimistic lock)。 换句话说,它决定这个属性发生脏数据时版本(version)的值是否增长。

(11) generated (可选 - 默认为 never): 表明此属性值是否实际上是由数据库生成的。

typename可以是如下几种:

Hibernate基本类型名(比如:integer, string, character,date, timestamp, float, binary, serializable, object, blob)。

一个Java类的名字,这个类属于一种默认基础类型 (比如: int, float,char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob)

一个可以序列化的Java类的名字。

一个自定义类型的类的名字。(比如: com.illflow.type.MyCustomType)

如果你没有指定类型,Hibernarte会使用反射来得到这个名字的属性,以此来猜测正确的Hibernate类型。 Hibernate会按照规则2,3,4的顺序对属性读取器(getter方法)的返回类进行解释。然而,这还不够。 在某些情况下你仍然需要type属性。(比如,为了区别Hibernate.DATE Hibernate.TIMESTAMP,或者为了指定一个自定义类型。)

access属性用来让你控制Hibernate如何在运行时访问属性。在默认情况下, Hibernate会使用属性的get/set方法对(pair)。如果你指明access="field", Hibernate会忽略get/set方法对,直接使用反射来访问成员变量。你也可以指定你自己的策略, 这就需要你自己实现org.hibernate.property.PropertyAccessor接口, 再在access中设置你自定义策略类的名字。

衍生属性(derive propertie)是一个特别强大的特征。这些属性应该定义为只读,属性值在装载时计算生成。 你用一个SQL表达式生成计算的结果,它会在这个实例转载时翻译成一个SQL查询的SELECT 子查询语句。

java代码:

    <property name="totalPrice"  

              formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p  

                          WHERE li.productId = p.productId  

                          AND li.customerId = customerId  

                          AND li.orderNumber = orderNumber )"/>  

注意,你可以使用实体自己的表,而不用为这个特别的列定义别名( 上面例子中的customerId)。同时注意,如果你不喜欢使用属性, 你可以使用嵌套的<formula>映射元素。

注意:如果实体类和实体类中的属性和SQL中的关键重复,必须采用tablecolumn重新命名。

 

posted @ 2016-07-17 11:27  雪呢_sherry  阅读(340)  评论(0编辑  收藏  举报