hibernate总结一

来源:互联网 发布:mac机ae cc2014序列号 编辑:程序博客网 时间:2024/06/06 23:54

1. Hibernate

            Hibernate提出了缓存机制,这样可以使访问数据的效率提高

 

 

 

 

 

 

 

 

 

配置文件:

 

Hibernate.connection.url  表示要链接的数据库地址

Hibernate.connection.driver_class    表示要链接的数据库的驱动类

Hibernate.connection.username     要连接的数据库的用户名

Hibernate.connection.password      要连接的数据库的密码

Hibernate.dialect   表示要使用的数据库的类型

          org.hibernate.dialect.MySQL5Dialect       mysql数据库

          org.hibernate.dialect.Oracle9Dialect        oracle数据库

          org.hibernate.dialect.SQLServerDialect    SQLServer数据库

hibernate.hbm2ddl.auto

          validate:加载hibernate时验证创建表结构

          update:加载hibernate时自动更新数据库结构,如果表存在不用创建,如果不存在就创建。

          create:每一次加载hibernate时都创建表结构

          create-drop:加载hibernate时创建,退出时删除

l Cnfiguration 类负责管理 Hibernate的配置信息。包括如下内容:

• Hibernate运行的底层信息:数据库的URL、用户名、密码、JDBC驱动类,数据库Dialect,数据库连接池等(对应hibernate.cfg.xml 文件)。

• 持久化类与数据表的映射关系(*.hbm.xml 文件)

创建 Configuration 的两种方式

• 属性文件(hibernate.properties:

    Configuration cfg = new Configuration();

• Xml文件(hibernate.cfg.xml

    Configuration cfg = new Configuration().configure(); 

第二种创建方式较为常见。Hibernate.cfg.xml文件默认的目录为系统的根目录。

(展示源代码以得到证实)

也可以利用config.config方法来指定配置文件所在的目录。

l Configuration对象根据当前的配置信息生成 SessionFactory对象。SessionFactory对象一旦构造完毕,即被赋予特定的配置信息(SessionFactory对象中保存了当前的数据库配置信息和所有映射关系以及预定义的SQL语句。同时,SessionFactory还负责维护Hibernate的二级缓存)

   Configuration cfg = new Configuration().configure();

   SessionFactory sf = cfg.buildSessionFactory(); 

是线程安全的。

l SessionFactory是生成Session的工厂: 

    Session session = sf.openSession();

构造 SessionFactory 很消耗资源,一般情况下一个应用中只初始化一个 SessionFactory 对象。

Hibernate中,Transaction tx = session.beginTransaction()相当于给数据库操作起事务。Session.commit()则为提交事务。

l Hibernate的整个运行过程如下:

1、应用程序先调用Configuration,该类读取Hibernate配置文件及映射文件中的信息,

2、并用这些信息生成一个SessionFactory对象,

3、然后从SessionFactory对象生成一个Session对象,

4、并用Session对象生成Transaction对象;

    A、可通过Session对象的get(),load(),save(),update(),delete()saveOrUpdate()等方法对PO进行加载、保存、更新、删除、等操作;

B、在查询的情况下,可通过Session对象生成一个Query对象,然后利用Query对象执行查询操作;如果没有异常,Transaction对象将提交这些操作到数据库中。

 

 

 

2. 主键生成机制

表示符生成器 

描述

Increment

由hibernate自动以递增的方式生成表识符,每次增量为1

Identity

由底层数据库生成表识符。条件是数据库支持自动增长数据类型。

Sequence

Hibernate根据底层数据库序列生成标识符。条件是数据库支持序列。

Native

根据底层数据库对自动生成表示符的能力来选择identity、sequence、hilo

Uuid.hex

Hibernate采用128位的UUID算法来生成标识符。该算法

能够在网络环境中生成唯一的字符串标识符,这种策略并不流行,因为字符串类型的主键比整数类型的主键占用更多的数据库空间。

如果主键用字符类型,并且不代表任何含义。

assigned

适用于自然主键。由java程序负责生成标识符。不能把setID()方法声明为

Private的。尽量避免使用自然主键。

 

increment 标识符生成器

l increment 标识符生成器 Hibernate 以递增的方式为代理主键赋值

l Hibernate 会先读取 NEWS表中的主键的最大值,而接下来向 NEWS表中插入记录时,就在 max(id)的基础上递增,增量为 1.(带走+1)

适用范围:

• 由于 increment 生存标识符机制不依赖于底层数据库系统, 因此它适合所有的数据库系统

• 适用于只有单个 Hibernate 应用进程访问同一个数据库的场合

• OID 必须为 long, intshort类型,如果把 OID定义为 byte类型,在运行时会抛出异常

identity 标识符生成器

l identity 标识符生成器由底层数据库来负责生成标识符,它要求底层数据库把主键定义为自动增长字段类型(加1带走)

适用范围:

• 由于 identity 生成标识符的机制依赖于底层数据库系统, 因此,要求底层数据库系统必须支持自动增长字段类型.支持自动增长字段类型的数据库包括: DB2, Mysql, MSSQLServer, Sybase

• OID 必须为 long, intshort类型,如果把 OID定义为 byte类型,在运行时会抛出异常

sequence 标识符生成器

l sequence  标识符生成器利用底层数据库提供的序列来生成标识符.

l Hibernate 在持久化一个 News对象时,先从底层数据库的 news_seq序列中获得一个唯一的标识号,再把它作为主键值

适用范围:

• 由于 sequence 生成标识符的机制依赖于底层数据库系统的序列, 因此,要求底层数据库系统必须支持序列.支持序列的数据库包括: DB2 Oracle

• OID 必须为 long, intshort类型,如果把 OID定义为 byte类型,在运行时会抛出异常

native 标识符生成器

l native 标识符生成器依据底层数据库对自动生成标识符的支持能力,来选择使用 identity, sequencehilo标识符生成器.

适用范围:

• 由于 native 能根据底层数据库系统的类型, 自动选择合适的标识符生成器,因此很适合于跨数据库平台开发

• OID 必须为 long, intshort类型,如果把 OID定义为 byte类型,在运行时会抛出异常

assigned 标识符生成器

l hibernate和底层数据库都不帮助你生成主键,也就是说得自己在程序中手动的设置主键的值。

l 适用范围:

       主键有一定的含义,需要根据业务产生的情况。

Uuid标识符生成器

l Hibernate采用128位的UUID算法来生成标识符。该算法能够在网络环境中生成唯一的字符串标识符,这种策略并不流行,因为字符串类型的主键比整数类型的主键占用更多的数据库空间

l 使用范围:

       主键是字符串,而且必须是唯一

HibernateSessionFactory

 

利用ThreadLocal类保证了Session的线程安全。具体内容看代码是怎么样形成的。

3. 持久化对象的状态

持久化对象有3种状态:

持久化状态

临时状态 

游离状态

Session 的特定方法能使对象从一个状态转换到另一个状态

临时对象(transient)

• 在使用代理主键的情况下, OID 通常为 null

• 不处于 Session 的缓存中

• 在数据库中没有对应的记录

 

持久化对象(也叫”托管”)Persist

• OID 不为 null

• 位于 Session 缓存中

• 持久化对象和数据库中的相关记录对应

• Session 在清理缓存时,会根据持久化对象的属性变化,来同步更新数据库

• 在同一个 Session 实例的缓存中, 数据库表中的每条记录只对应唯一的持久化对象

 

游离对象(也叫”脱管”)(Detached)

• OID 不为 null

• 不再处于 Session 的缓存中

• 一般情况需下, 游离对象是由持久化对象转变过来的, 因此在数据库中可能还存在与它对应的记录

Session使用以下方法可以使持久化对象转变成游离对象:

 

测试hibernate中对象变化的状态:

程序代码 

生命周期 

状态

tx = session.beginTransaction();

Customer c = new Customer);

开始生命周期 

临时状态 

Session.save(c)

处于生命周期中 

转变为持久化状态

Long id=c.getId();

c = null;

Customer c2 = (Customer)session.load(Customer.class,id);

tx.commit();

处于生命周期中

处于持久化状态

session.close();

处于生命周期中

转变为游离态

c2.getName();

处于生命周期中

处于游离态

c2 = null;

结束生命周期 

结束生命周期

 

对象状态转化图

 

 

 

对象状态的总结

 

操纵持久化对象-save()

l Session save() 方法使一个临时对象转变为持久化对象

l Session save() 方法完成以下操作:

News 对象加入到 Session 缓存中, 使它进入持久化状态

l 选用映射文件指定的标识符生成器, 为持久化对象分配唯一的 OID. 在使用代理主键的情况下, setId()方法为 News 对象设置 OID 使无效的.

计划执行一条 insert 语句,把Customer对象当前的属性值组装到insert语句中

l Hibernate 通过持久化对象的 OID 来维持它和数据库相关记录的对应关系. News 对象处于持久化状态时, 不允许程序随意修改它的 ID

操纵持久化对象-update()

l Session update()方法使一个游离对象转变为持久化对象,并且计划执行一条 update语句.

 

操纵持久化对象-saveOrupdate()

saveOrUpdate:

  该方法同时包含saveupdate方法,如果参数是临时对象就用save

   法,如果是游离对象就用update方法,如果是持久化对象就直接返回。

如果参数是临时对象就用save方法

 

如果是游离对象就用update方法

 

如果是持久化对象就直接返回,不执行操作

 

 

4. 映射一对多关联关系

6.1单向关联

仅仅建立从Order到Customer的多对一关联,即仅仅在Order类中定义customer属性。或者仅仅建立从Customer到Order的一对多关联,即仅仅Customer类中定义orders集合。

 

单向 n-1 关联只需从n 的一端可以访问1 的一端

域模型: Order Customer 的多对一单向关联需要在Order类中定义一个 Customer属性,而在 Customer类中无需定义存放 Order对象的集合属性

 

关系数据模型:ORDERS 表中的 CUSTOMER_ID 参照CUSTOMER 表的主键 

 

Hibernate 使用 <many-to-one> 元素来映射多对一关联关系

 

 

6.1.1保存操作

实验1

先保存订单,再保存客户

 

从这里可以看出执行了两条insert语句,一条update语句

先保存客户,再保存订单

 

可以看出这种情况程序是执行了两条insert语句,而没有执行update语句。

查询订单

 

先保存客户,再保存订单,在下面的代码中注释掉session.save(c),会有什么后果

 

级联保存和更新

当hibernate持久化一个临时对象时,在默认情况下,他不会自动持久化所关联的其他临时对象,会抛出TransientObjectException.如果设定many-to-one元素的cascade属性为save-update的话,可实现自动持久化所关联的对象。 

 

 

 

6.2双向关联

双向 1-n 与 双向n-1 是完全相同的两种情形

双向 1-n 需要在1 的一端可以访问n 的一端,反之依然.

域模型:

Order Customer 的多对一单向关联需要在Order类中定义一个 Customer属性,而在 Customer类中需定义存放 Order对象的集合属性

 

关系数据模型:

ORDERS 表中的 CUSTOMER_ID参照 CUSTOMER表的主键

 

建立一对多的双向关联关系

 

Hibernate使用set元素来映射一对多关联关系

 

保存客户和订单(客户和订单建立双向关联)

 

保存客户和不保存订单

在下面的代码中注释掉session.save(order1),会有什么后果

 

级联保存和更新

当hibernate持久化一个临时对象时,在默认情况下,他不会自动持久化所关联的其他临时对象,会抛出TransientObjectException.如果设定set元素的cascade属性为save-update的话,可实现自动持久化所关联的对象。

 

查询客户和订单

 

查询客户和订单(图)

 

 

保存客户或订单的区别

保存订单时会发出两条insert语句。

Hibernate: select max(id) from customers

Hibernate: insert into customers (name, id) values (?, ?)

Hibernate: insert into orders (order_number, price, customer_id) values (?, ?, ?)

而保存客户时会发出两条insert语句和一条update语句

Hibernate: select max(id) from customers

Hibernate: insert into customers (name, id) values (?, ?)

Hibernate: insert into orders (order_number, price, customer_id) values (?, ?, ?)

Hibernate: update orders set customer_id=? where id=?

因为订单是多的一方,而客户是一的一方,所以在多对一的关系中,应该使用一的一方进行操作,这样效率更高。

订单变更客户

 

上述例子产生了两条update语句:

Hibernate: update orders set order_number=?, price=?, customer_id=? where id=?

Hibernate: update orders set customer_id=? where id=?

原因为:

Hibernate会自动清理缓存中的所有持久化对象,按照持久化对象的改变来同步更新数据库,因此执行了上述的两条更新语句所以会产生两条update语句

c4.getOrders().add(o6)执行了一条update语句

o6.setCustomer(c4)执行了一条update语句

级联删除

inverse属性

Inverse来源

在hibernate中通过对 inverse 属性的值决定是由双向关联的哪一方来维护表和表之间的关系. inverse=false 的为主动方,inverse=true 的为被动方, 由主动方负责维护关联关系

Inverse设值

在没有设置 inverse=true 的情况下,父子两边都维护父子关系

Inverse设值原则

1-n 关系中,将 n 方设为主控方将有助于性能改善(如果要国家元首记住全国人民的名字,不是太可能,但要让全国人民知道国家元首,就容易的多)

1-N 关系中,若将 1方设为主控方 会额外多出 update 语句

 

在一的一方设值inverseTRUE表明一的一方不维护其关系,这样就会发出一条update语句,这样效率也就提高了。

Inverse结论

1.在映射一对多的双向关联关系时,应该在one方把inverse属性设为true,

  这可以提高性能。

2.在建立两个对象的关联时,应该同时修改关联两端的相应属性:

   customer.getOrders().add(order);

   order.setCustomer(customer);

这样才会使程序更加健壮,提高业务逻辑层的独立性,使业务逻辑层的程序代码

不受Hibernate实现类的影响。同理,当删除双向关联的关系时,也应该修改

关联两端的对象的相应属性:

Customer.getOrders().remove(order);

Order.setCustomer(null);

解除关联关系

解除某个订单与某个客户的关系

 

这样在order表中,ID6的相应的外键为3的那行的外键会置为null;

级联删除

 

 

 

 

 

cascade属性

 

在数据库中对集合进行排序

<set> 元素有一个 order-by 属性, 如果设置了该属性, Hibernate 通过 select 语句到数据库中检索集合对象时,利用 order by 子句进行排序

 

 

5. 映射多对多关联关系

 

6. 深入Session

session概述

Session 接口是 Hibernate向应用程序提供的操纵对数据库的最主要的接口,它提供了基本的保存,更新,删除和加载Java对象的方法.

理解session的缓存

Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存. 只要 Session 实例没有结束生命周期, 存放在它缓存中的对象也不会结束生命周期 

l     session的save()方法持久化一个对象时,该对象被载入缓存,以后即使程序中不再引用该对象,只要缓存不清空,该对象仍然处于生命周期中。当试图load()对象时,会判断缓存中是否存在该对象,有则返回。没有在查询数据库

清理session的缓存

l Session 具有一个缓存,位于缓存中的对象称为持久化对象, 它和数据库中的相关记录对应. Session能够在某些时间点,按照缓存中对象的变化来执行相关的 SQL语句,来同步更新数据库,这一过程被称为清理缓存(flush)

默认情况下 Session 在以下时间点清理缓存:

• 当应用程序调用 Transaction commit()方法的时,该方法先清理缓存(session.flush()),然后在向数据库提交事务(tx.commit())

• 当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生了变化,会先清理缓存,以保证查询结果能够反映持久化对象的最新状态

• 显式调用 Session flush() 方法.

区别:

     flush: 进行清理缓存(此时缓存中的数据并不丢失)的操作,让缓存和数据库同步 执行一些列sql语句,但不提交事务,

     commit:先调用flush() 方法,然后提交事务. 则意味着提交事务意味着对数据库操作永久保存下来。

     reresh:刷新,session和数据库同步,执行查询,把数据库的最新信息显示出来,更新本地缓存的对象状态.

     clear:清空缓存,等价于list.removeAll(); 

利用Session缓存读取持久化对象的数据

1   Customer c = new Customer(“TOM”,new HashSet());

2   session.save(c); //customer对象被持久化,并且加入到session的缓存中 

3   Long id = c.getId();

4   c = null; //c变量不再引用customer对象 

5   //从session缓存中读取customer对象,使c2变量引用customer对象

6   Customer c2 = (Customer)session.load(Customer.class,id);

7   tx.commit();  //缓存中的对象和数据库同步

8   session.close(); //关闭session 清空缓存

9   System.out.println(c2.getName()); //访问customer对象

10 C2 = null; //C2对象不再引用customer对象,customer对象结束生命周期 

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

缓存的作用:

1。减少访问数据库的频率。

2。保证缓存中的对象与数据库中的相关记录保持同步。

Session执行批量操作

可以写一个for循环,Session可以批量插入上万条数据。如下面的代码:

             For(int i=0;i<10000;i++){

Session.save(object);

}

这样写的代码会产生一个什么问题?会使一万个对象的缓存全部存在于内存中,这样做加大了内存的压力。所以应该定期清理session的缓存,也就是flush一下,这样内存才能保证足够的空间。

 

 

7. Session.loadsession.get方法

不同场合的不同解决方案

       场合一:当用户要取数据库的一张表的一个字段,这个字段很可能就是一个字符,总而言之长度是比较短的。

       场合二:当用户要取数据库的一张表的一个字段的值,而这个值很可能是blob类型,也许存取的是一个很大的视频文件。

        两种场合的取数据的方法一样吗?是用load还是用get方法?

延迟加载

类的延迟加载

lazy true或者为false

集合的延迟加载

True   false   extra

extra为更进一步的延迟加载策略。

当调用getStudents()时不会加载hql语句,当加载student的属性的时候才会发出SQL语句

调用getStudents().size()方法的时候,会触发类似于:Hibernate: select count(id) from T_Student where classid =?这样的SQL查询语句(这是一种很聪明的做法,如果lazy=true”,getStudents().size()将会使得hibernate加载所有集合的数据到内存中)。

调用getStudents().contains()方法的时候(即判断是否包含某个对象),会触发类似于:select 1 from T_Student where classid =? and id =?这样的SQL查询语句。

单端关联

         False   proxy   no-proxy

proxy:当前对象的単值相关对象只有在调用它的主键外的其他属性的get方法时才加载它。

no-proxy:当前对象的単值相关对象只有在调用它的属性时才加载,需要字节码增强。

0 0