Hibernate的一些相关信息
在没有学习Hibernate之前,我们一直都是用jdbc来连接数据库和操纵数据库。所以在刚接触Hibernate时,我们都有一个疑问,为什么要学Hibernate,jdbc不是挺好的吗?那么接下来就来讲讲jdbc的优缺点与为什么要用Hibernate吧。
JDBC
长处:
直接底层操作,提供了非常easy、便捷的訪问数据库的方法,跨平台性比較强。灵活性比較强,能够写非常复杂的SQL语句。
缺点:
- 由于JAVA时面向对象的,JDBC没有做到使数据可以面向对象的编程,是程序猿的是靠仍然停留在SQL语句上。
- 操作比較频繁,非常多代码须要反复写非常多次。
- 假设遇到批量操作,频繁与数据库进行交互,easy造成效率的下降。
为什么要用Hibernate
- Hibernate实现了面向对象的数据库编程
- Hibernate比起JDBC,在代码的书写上比較简单化
- Hibernate提出了缓存机制,这样能够使訪问数据的效率提高非常多
Hibernate项目所需的lib包
Hibernate配置文件里name里面的一些信息
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时创建,退出时删除
- Cnfiguration 类负责管理 Hibernate 的配置信息。包含例如以下内容:
- Hibernate执行的底层信息:数据库的URL、username、password、JDBC驱动类,数据库Dialect,数据库连接池等(相应 hibernate.cfg.xml 文件)。
- 持久化类与数据表的映射关系(*.hbm.xml 文件)
- 创建 Configuration 的两种方式
- 属性文件(hibernate.properties):
- Configuration cfg = new Configuration();
- Xml文件(hibernate.cfg.xml)
- Configuration cfg = new Configuration().configure();
- 属性文件(hibernate.properties):
也能够利用config.config方法来指定配置文件所在的文件夹。
- Configuration对象依据当前的配置信息生成 SessionFactory 对象。SessionFactory 对象一旦构造完成,即被赋予特定的配置信息(SessionFactory 对象中保存了当前的数据库配置信息和全部映射关系以及提前定义的SQL语句。同一时候,SessionFactory还负责维护Hibernate的二级缓存)。
- Configuration cfg = new Configuration().configure();
- SessionFactory sf = cfg.buildSessionFactory();
- 是线程安全的。
- SessionFactory是生成Session的工厂:
- Session session = sf.openSession();
- 构造 SessionFactory 非常消耗资源,普通情况下一个应用中仅仅初始化一个 SessionFactory 对象。
- 在Hibernate中,Transaction tx = session.beginTransaction()相当于给数据库操作起事务。Session.commit()则为提交事务。
- l Hibernate的整个执行步骤例如以下:
- 应用程序先调用Configuration类,该类读取Hibernate配置文件及映射文件里的信息,
- 并用这些信息生成一个SessionFactory对象,
- 然后从SessionFactory对象生成一个Session对象,
- 并用Session对象生成Transaction对象;
- 可通过Session对象的get(),load(),save(),update(),delete()和saveOrUpdate()等方法对PO进行载入、保存、更新、删除、等操作;
- 在查询的情况下,可通过Session对象生成一个Query对象,然后利用Query对象运行查询操作;假设没有异常,Transaction对象将提交这些操作到数据库中。
接下来具体介绍Hibernate
ORM框架 ------hibernate
- 开源的持久层框架.
- ORM(Object/Relational Mapping)映射工具,建立面向对象的域模型和关系数据模型之间的映射.
- 连接java应用和数据库的中间件.
- 对JDBC进行封装,负责java对象的持久化.
- 在分层结构中处于持久化层,封装对数据库的訪问细节,使业务逻辑层更专注于实现业务逻辑
Hibernate的长处:
- Hibernate对JDBC訪问数据库的代码做了封装,大大简化了数据訪问层繁琐的反复性代码。
- Hibernate是一个基于jdbc的主流持久化框架,是一个优秀的orm实现,它非常大程度的简化了dao层编码工作。
- Hibernate使用java的反射机制,而不是字节码增强程序类实现透明性
- Hibernate的性能非常好,由于它是一个轻量级框架。映射的灵活性非常出色。它支持非常多关系型数据库,从一对一到多对多的各种复杂关系。
- Hibernate使数据库的操作全然面向对象。而不是从前的面向关系进行操作。
对象关系映射(Object/Relation Mapping)提供了概念性的、易于理解的模型化数据的方法。ORM方法论基于三个核心原则: 简单:以最主要的形式建模数据。 传达性:数据库结构被不论什么人都能理解的语言文档化。
精确性:基于数据模型创建正确标准化了的结构。 典型地,建模者通过收集来自那些熟悉应用程序但不熟练的数据建模者的人的信息开发信息模型。建模者必须可以用非技术企业专家可以理解的术语在概念层次上与数据结构进行通讯。建模者也必须能以简单的单元分析信息,对样本数据进行处理。ORM专门被设计为改进这样的联系。
Hibernate的主键生成机制:
表示符生成器 |
描写叙述 |
Increment |
由hibernate自己主动以递增的方式生成表识符,每次增量为1 |
Identity |
由底层数据库生成表识符。条件是数据库支持自己主动增长数据类型。 |
Sequence |
Hibernate依据底层数据库序列生成标识符。条件是数据库支持序列。 |
Native |
依据底层数据库对自己主动生成表示符的能力来选择identity、sequence、hilo |
Uuid.hex |
Hibernate採用128位的UUID算法来生成标识符。该算法 可以在网络环境中生成唯一的字符串标识符,这样的策略并不流行,由于字符串类型的主键比整数类型的主键占用很多其它的数据库空间。 假设主键用字符类型,而且不代表不论什么含义。 |
assigned |
适用于自然主键。由java程序负责生成标识符。不能把setID()方法声明为 Private的。尽量避免使用自然主键。 |
increment 标识符生成器
- increment 标识符生成器由 Hibernate 以递增的方式为代理主键赋值
- Hibernate 会先读取 NEWS 表中的主键的最大值, 而接下来向 NEWS 表中插入记录时, 就在 max(id) 的基础上递增, 增量为 1.(带走+1)
- 适用范围:
- 因为 increment 生存标识符机制不依赖于底层数据库系统, 因此它适合全部的数据库系统
- 适用于仅仅有单个 Hibernate 应用进程訪问同一个数据库的场合
- OID 必须为 long, int 或 short 类型, 假设把 OID 定义为 byte 类型, 在执行时会抛出异常
identity 标识符生成器
- identity 标识符生成器由底层数据库来负责生成标识符, 它要求底层数据库把主键定义为自己主动增长字段类型(加1带走)
- 适用范围:
- 因为 identity 生成标识符的机制依赖于底层数据库系统, 因此, 要求底层数据库系统必须支持自己主动增长字段类型. 支持自己主动增长字段类型的数据库包含: DB2, Mysql, MSSQLServer, Sybase 等
- OID 必须为 long, int 或 short 类型, 假设把 OID 定义为 byte 类型, 在执行时会抛出异常
sequence 标识符生成器
- sequence 标识符生成器利用底层数据库提供的序列来生成标识符.
- Hibernate 在持久化一个 News 对象时, 先从底层数据库的 news_seq 序列中获得一个唯一的标识号, 再把它作为主键值
- 适用范围:
- 因为 sequence 生成标识符的机制依赖于底层数据库系统的序列, 因此, 要求底层数据库系统必须支持序列. 支持序列的数据库包含: DB2 Oracle 等
- OID 必须为 long, int 或 short 类型, 假设把 OID 定义为 byte 类型, 在执行时会抛出异常
native 标识符生成器
- native 标识符生成器根据底层数据库对自己主动生成标识符的支持能力, 来选择使用 identity, sequence 或 hilo 标识符生成器.
- 适用范围:
- 因为 native 能依据底层数据库系统的类型, 自己主动选择合适的标识符生成器, 因此非常适合于跨数据库平台开发
- OID 必须为 long, int 或 short 类型, 假设把 OID 定义为 byte 类型, 在执行时会抛出异常
assigned 标识符生成器
- hibernate和底层数据库都不帮助你生成主键,也就是说得自己在程序中手动的设置主键的值。
- 适用范围:
- 主键有一定的含义,须要依据业务产生的情况。
Uuid标识符生成器
- Hibernate採用128位的UUID算法来生成标识符。该算法可以在网络环境中生成唯一的字符串标识符,这样的策略并不流行,由于字符串类型的主键比整数类型的主键占用很多其它的数据库空间
- 使用范围:
- 主键是字符串,并且必须是唯一
持久化对象的状态
持久化对象有3种状态:
- 持久化状态
- 暂时状态
- 游离状态
Session 的特定方法能使对象从一个状态转换到还有一个状态
暂时对象(transient)
- 在使用代理主键的情况下, OID 通常为 null
- 不处于 Session 的缓存中
- 在数据库中没有相应的记录
- 当通过new语句刚创建了一个java对象,它处于暂时对象,此时不和数据库中的不论什么记录相应。
持久化对象(也叫”托管”)(Persist)
- OID 不为 null
- 位于 Session 缓存中
- 持久化对象和数据库中的相关记录相应
- Session 在清理缓存时, 会依据持久化对象的属性变化, 来同步更新数据库
- 在同一个 Session 实例的缓存中, 数据库表中的每条记录仅仅相应唯一的持久化对象
- Session的save()方法把暂时对象转变为持久化对象。
- Session的load()或get()方法返回的对象总是处于持久化对象。
- Session的update()、saveOrUpdate()和lock()方法使游离对象转变为持久化对象。
- 当一个持久化对象关联一个暂时对象,在同意级联保存的情况下,Session在清理缓存时会把这个暂时对象也转变为赤计划对象。
游离对象(也叫”脱管”)(Detached)
- OID 不为 null
- 不再处于 Session 的缓存中
- 普通情况需下, 游离对象是由持久化对象转变过来的, 因此在数据库中可能还存在与它相应的记录
Session使用下面方法能够使持久化对象转变成游离对象:
- 当调用Session的close()方法时,Session的缓存被清空,缓存中的全部持久化对象都变为游离对象。假设在应用程序中没有引用变量引用这些游离对象,它们就会结束生命周期。
- Session的evict()方法可以从缓存中删除一个持久化对象,时它比哪位游离状态。当Session的缓存中保存了大量的持久化对象,会消耗很多内存空间,为了提高性能,可以考虑调用evict()方法,从缓存中删除一些持久化对象。
測试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()
- Session 的 save() 方法使一个暂时对象转变为持久化对象
- Session 的 save() 方法完毕下面操作:
- 把 News 对象增加到 Session 缓存中, 使它进入持久化状态
- 选用映射文件指定的标识符生成器, 为持久化对象分配唯一的 OID. 在使用代理主键的情况下, setId() 方法为 News 对象设置 OID 使无效的.
- 计划运行一条 insert 语句,把Customer对象当前的属性值组装到insert语句中
- Hibernate 通过持久化对象的 OID 来维持它和数据库相关记录的相应关系. 当 News 对象处于持久化状态时, 不同意程序任意改动它的 ID
操纵持久化对象-update()
- Session 的 update() 方法使一个游离对象转变为持久化对象, 而且计划运行一条 update 语句.
操纵持久化对象-saveOrupdate()
saveOrUpdate:
该方法同一时候包括save和update方法,假设參数是暂时对象就用save方
法,假设是游离对象就用update方法,假设是持久化对象就直接返回。
假设參数是暂时对象就用save方法
假设是游离对象就用update方法
假设是持久化对象就直接返回,不运行操作
映射一对多关联关系
单向关联
只建立从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> 元素来映射多对一关联关系
保存操作
级联保存和更新
- 当hibernate持久化一个暂时对象时,在默认情况下,他不会自己主动持久化所关联的其它暂时对象,会抛出TransientObjectException.假设设定many-to-one元素的cascade属性为save-update的话,可实现自己主动持久化所关联的对象。
双向关联
双向 1-n 与 双向 n-1 是全然同样的两种情形
双向 1-n 须要在 1 的一端能够訪问 n 的一端, 反之依旧.
域模型:
从 Order 到 Customer 的多对一单向关联须要在Order 类中定义一个 Customer 属性, 而在 Customer 类中需定义存放 Order 对象的集合属性
关系数据模型:
ORDERS 表中的 CUSTOMER_ID 參照 CUSTOMER 表的主键
建立一对多的双向关联关系
Hibernate使用set元素来映射一对多关联关系
级联保存和更新
当hibernate持久化一个暂时对象时,在默认情况下,他不会自己主动持久化所关联的其它暂时对象,会抛出TransientObjectException.假设设定set元素的cascade属性为save-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);
级联删除
cascade属性
在数据库中对集合进行排序
<set> 元素有一个 order-by 属性, 假设设置了该属性, 当 Hibernate 通过 select 语句到数据库中检索集合对象时, 利用 order by 子句进行排序
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。