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 文件)
l 创建 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 是线程安全的。
l SessionFactory是生成Session的工厂:
Session session = sf.openSession();
l 构造 SessionFactory 很消耗资源,一般情况下一个应用中只初始化一个 SessionFactory 对象。
l 在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)
l 适用范围:
• 由于 increment 生存标识符机制不依赖于底层数据库系统, 因此它适合所有的数据库系统
• 适用于只有单个 Hibernate 应用进程访问同一个数据库的场合
• OID 必须为 long, int或 short类型,如果把 OID定义为 byte类型,在运行时会抛出异常
identity 标识符生成器
l identity 标识符生成器由底层数据库来负责生成标识符,它要求底层数据库把主键定义为自动增长字段类型(加1带走)
l 适用范围:
• 由于 identity 生成标识符的机制依赖于底层数据库系统, 因此,要求底层数据库系统必须支持自动增长字段类型.支持自动增长字段类型的数据库包括: DB2, Mysql, MSSQLServer, Sybase等
• OID 必须为 long, int或 short类型,如果把 OID定义为 byte类型,在运行时会抛出异常
sequence 标识符生成器
l sequence 标识符生成器利用底层数据库提供的序列来生成标识符.
l Hibernate 在持久化一个 News对象时,先从底层数据库的 news_seq序列中获得一个唯一的标识号,再把它作为主键值
l 适用范围:
• 由于 sequence 生成标识符的机制依赖于底层数据库系统的序列, 因此,要求底层数据库系统必须支持序列.支持序列的数据库包括: DB2 Oracle等
• OID 必须为 long, int或 short类型,如果把 OID定义为 byte类型,在运行时会抛出异常
native 标识符生成器
l native 标识符生成器依据底层数据库对自动生成标识符的支持能力,来选择使用 identity, sequence或 hilo标识符生成器.
l 适用范围:
• 由于 native 能根据底层数据库系统的类型, 自动选择合适的标识符生成器,因此很适合于跨数据库平台开发
• OID 必须为 long, int或 short类型,如果把 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() 方法完成以下操作:
l 把 News 对象加入到 Session 缓存中, 使它进入持久化状态
l 选用映射文件指定的标识符生成器, 为持久化对象分配唯一的 OID. 在使用代理主键的情况下, setId()方法为 News 对象设置 OID 使无效的.
l 计划执行一条 insert 语句,把Customer对象当前的属性值组装到insert语句中
l Hibernate 通过持久化对象的 OID 来维持它和数据库相关记录的对应关系.当 News 对象处于持久化状态时, 不允许程序随意修改它的 ID
操纵持久化对象-update()
l Session 的 update()方法使一个游离对象转变为持久化对象,并且计划执行一条 update语句.
操纵持久化对象-saveOrupdate()
saveOrUpdate:
该方法同时包含save和update方法,如果参数是临时对象就用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 语句
在一的一方设值inverse为TRUE表明一的一方不维护其关系,这样就会发出一条update语句,这样效率也就提高了。
Inverse结论
1.在映射一对多的双向关联关系时,应该在one方把inverse属性设为true,
这可以提高性能。
2.在建立两个对象的关联时,应该同时修改关联两端的相应属性:
customer.getOrders().add(order);
order.setCustomer(customer);
这样才会使程序更加健壮,提高业务逻辑层的独立性,使业务逻辑层的程序代码
不受Hibernate实现类的影响。同理,当删除双向关联的关系时,也应该修改
关联两端的对象的相应属性:
Customer.getOrders().remove(order);
Order.setCustomer(null);
解除关联关系
解除某个订单与某个客户的关系
这样在order表中,ID为6的相应的外键为3的那行的外键会置为null;
级联删除
cascade属性
在数据库中对集合进行排序
<set> 元素有一个 order-by 属性, 如果设置了该属性, 当 Hibernate 通过 select 语句到数据库中检索集合对象时,利用 order by 子句进行排序
5. 映射多对多关联关系
6. 深入Session
session概述
Session 接口是 Hibernate向应用程序提供的操纵对数据库的最主要的接口,它提供了基本的保存,更新,删除和加载Java对象的方法.
理解session的缓存
l 在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存. 只要 Session 实例没有结束生命周期, 存放在它缓存中的对象也不会结束生命周期
l 当session的save()方法持久化一个对象时,该对象被载入缓存,以后即使程序中不再引用该对象,只要缓存不清空,该对象仍然处于生命周期中。当试图load()对象时,会判断缓存中是否存在该对象,有则返回。没有在查询数据库
清理session的缓存
l Session 具有一个缓存,位于缓存中的对象称为持久化对象, 它和数据库中的相关记录对应. Session能够在某些时间点,按照缓存中对象的变化来执行相关的 SQL语句,来同步更新数据库,这一过程被称为清理缓存(flush)
l 默认情况下 Session 在以下时间点清理缓存:
• 当应用程序调用 Transaction 的 commit()方法的时,该方法先清理缓存(session.flush()),然后在向数据库提交事务(tx.commit())
• 当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生了变化,会先清理缓存,以保证查询结果能够反映持久化对象的最新状态
• 显式调用 Session 的 flush() 方法.
l 区别:
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.load与session.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:当前对象的単值相关对象只有在调用它的属性时才加载,需要字节码增强。
- Hibernate 总结(一)
- Hibernate总结(一)
- Hibernate总结(一)
- Hibernate总结(一)
- Hibernate学习总结(一)
- 总结Hibernate(一)
- Hibernate总结(一)
- Hibernate问题总结一
- hibernate总结一
- Hibernate总结(一)
- Hibernate学习总结(一)
- Hibernate总结(一)--之hibernate配置文件
- Hibernate关系映射总结(一)
- Hibernate 总结(一):HelloWorld
- Hibernate关系映射总结(一)
- Hibernate阶段性总结(一)
- Hibernate查询方式总结(一)
- Hibernate框架(一)总结介绍
- ACdream 1196 KIDx's Pagination
- 使用clang进行交叉编译
- Ant 打包 SSH框架
- QT开发之TCP协议
- 通过ip区分内网和外网
- hibernate总结一
- UIP移植到CC2530上
- 单片机学习第一章
- 拷贝构造和赋值构造
- java.lang.AbstractMethodError: org.mybatis.spring.transaction.SpringManagedTransaction.getTimeout()L
- nginx+lua+redis使用
- PAT--1122. Hamiltonian Cycle (25)
- HBase数据模型的一些概念
- 冒泡排序,插入排序,快速排序,归并排序,堆排序,选择排序,希尔排序