Hibernate in Action学习笔记.docx
《Hibernate in Action学习笔记.docx》由会员分享,可在线阅读,更多相关《Hibernate in Action学习笔记.docx(13页珍藏版)》请在冰豆网上搜索。
![Hibernate in Action学习笔记.docx](https://file1.bdocx.com/fileroot1/2023-1/2/4129a95e-66de-4c42-87f7-e9359a9ad756/4129a95e-66de-4c42-87f7-e9359a9ad7561.gif)
HibernateinAction学习笔记
HibernateinAction
学习笔记
[2015年3月1日]
目录
Q1.面向对象应用程序中的持久化问题1
1.1范式不匹配1
1.2粒度问题1
1.3子类型问题1
1.4同一性问题1
1.5与关联相关的问题1
1.6数据访问方式的问题1
Q2.如何解决这些持久化问题2
2.1为什么不使用分层架构,用DAO层解决。
2
2.2为什么不使用Java序列化2
2.3为什么不使用面向对象数据库系统2
2.4为什么不用XML持久化2
2.5使用ORM2
Q3.什么是ORM,包括哪些内容?
3
Q4.ORM质量等级3
Q5.一般的ORM问题3
Q6.Hibernate自由的开发过程4
Q7.HelloHibernate4
Q1.面向对象应用程序中的持久化问题
1.1范式不匹配
在电子商务系统中,用户与账单的关系为一对多关系。
●面向对象时设计为一个用户类与一个账单类。
可以为用户类添加集合属性(集合中存储账单),也可以为账单类添加用户属性。
但数据库表只能通过账单的外键来实现。
●假如用户信息中含有地址(国家、地区、省)等。
面向对象时一般会封装为一个街道类,在用户类中持有街道类的属性解决。
而数据库表中则不需要存在一个地址表。
1.2粒度问题
这里粒度是指正在使用的类型的相对大小。
面向对象允许我们无限的扩展类型,而SQL标准支持用户定义的数据类型却少的可怜。
面向对象允许对象的嵌套组合,而数据库表只有两种粒度:
表和列。
1.3子类型问题
由于继承带来的问题。
1.4同一性问题
Java中同一性通过a==b和equals()检查,数据库通过外键检查。
这样通常需要一个业务无关的代理键(UUID)来解决。
同一性对系统如何处理高速缓存和事务密切相关。
1.5与关联相关的问题
面向对象利用对象引用表示关联;但是在关系数据库中使用外键。
对象引用由固有的方向性,而外键没有(可以通过表的联结和投影创建任意关联)
1.6数据访问方式的问题
Java中可以使用aUser.getDetails().getAccountNumber()。
而数据库必须考虑性能,而进行连结查询。
也就是在你遍历对象网络之前要构建有效的连结查询!
另一方面:
懒加载机制总是期望在使用时在获得对象。
但会产生N+1问题:
如默认情况下,当Hibernate从数据库中加载Customer对象时,会同时加载所有关联的Order对象。
以Customer和Order类为例,假定ORDERS表的CUSTOMER_ID外键允许为null以下Session的find()方法用于到数据库中检索所有的Customer对象:
ListcustomerLists=session.find("fromCustomerasc");
运行以上find()方法时,Hibernate将先查询CUSTOMERS表中所有的记录,然后根据每条记录的ID,到ORDERS表中查询有参照关系的记录,Hibernate将依次执行以下select语句:
select*fromCUSTOMERS;
select*fromORDERSwhereCUSTOMER_ID=1;
select*fromORDERSwhereCUSTOMER_ID=2;
select*fromORDERSwhereCUSTOMER_ID=3;
select*fromORDERSwhereCUSTOMER_ID=4;
Q2.如何解决这些持久化问题
2.1为什么不使用分层架构,用DAO层解决。
DAO是个好模式,甚至经常推荐与ORM一起使用,然而,给每个领域模型类编写持久化代码的工作量非常大,特别当支持多个SQL方言的时候。
为什么不实现个简单映射框架呢?
因为有Hibernate。
(80000行代码,25000行测试代码)。
2.2为什么不使用Java序列化
序列化之后的关联对象网络只能被当做一个整体访问:
没有反序列化整个流,就不可能从流中获取任何数据。
(在依赖序列化的网络传输中,要考虑此问题)
2.3为什么不使用面向对象数据库系统
面向对象数据库系统没有流行起来。
2.4为什么不用XML持久化
XML是序列化得一个变体,同时你可能遭受对象/层次结构不匹配的危险。
2.5使用ORM
提高生产力
提高可维护性
性能损耗
供应商独立性
实现JPA标准
Q3.什么是ORM,包括哪些内容?
ORM就是利用描述对象和数据库之间映射的元数据,自动(且透明)的把Java应用程序中的对象持久化到关系数据库中的表。
本质是:
把数据从一种表示法(可逆)转换为另一种表示法进行工作。
ORM解决方案包含下面的4个部分:
●在持久化类的对象上执行基本的CRUD操作的一个API;
●用于指定引用类或者类属性的查询的一种语言或者API
●用于指定映射元数据的一种工具:
●用于实现ORM的一项技术,与事务对象交互,执行脏检查(dirtychecking)、延迟关联抓以及其他优化功能。
Q4.ORM质量等级
纯关系——整个应闸程序(包括用户界面)都围绕着关系模型和基于SQL的关系操作而设计
轻量对象映射——实体被表示为手工映射到关系表的类。
使用众所周知的设计模式,把手工编码的SQL/JDBC从业务逻辑中隐藏起来。
中等对象映射——这种应用程序围绕对象模型而设计。
SQL使用一个代码生成的工具在创建时产生,或者通过框架代码在运行时产生。
完全对象映射——完全的对象映射支持完善的对象模型:
组合、继承、多态和可达的持久化。
Q5.一般的ORM问题
●持久化类看起来什么样?
持久化工具有多透明?
●映射元数据如何定义?
●对象同一性和等同性如何与数据库(主键〉同一柱相关?
●应该如何映射类继承层次结构?
●持久化逻辑如何在运行时与业务领域的对象文互?
●什么是持久化对象的生命周期?
●提供什么工具用来排序、搜索和统计?
●如何利用关联有效地获取数据?
Q6.HibernateEJB3和JPA
6.1理解标准
新的EJB3.0规范有儿个部分给会话bean消息驱动bean以及部署规则等,定义新的EJB编程模型,规范的第二部分专门处理持久化实体、ORM元数据、持久化管理器接口和查询语言部分被称作JPA。
新标准中设计了两条重要的原则:
1、JPA引擎应该是可插拔的。
2、JPA引擎应该能够在EJB3.0(或者任何其他)运行时环境之外运行。
Hibernate实现了JavaPersistence。
6.1.1HibernateCore
它是持久化的基础服务,带有原生的API和它存储XML文件中的映射元数据。
它有种查询语称作HQL(与SQL几乎相同),以及用CriteriaExample查询的可编硬查询接口。
6.1.2HibernateAnnotations
JPA规范定义ORM元数据语法和语义,主要机制为JDK5.0注解Hibernateannotations般来说是实现JPA标准的组基础注解,它们也是更高级的和更奇异的Hibernate映射和调优所需的组扩展注解。
6.1.3HibernateEntityManager
JPA范也定义编程接口、持久化对象的生命周期规则和查询特。
JPA这部分的Hibemat实现可被用作HibernateEntyManage。
HibernateEntityManger是对提供JPA就容性的HibemateCore个小包装。
Q7.Hibernate自由的开发过程
我们先从总体上看看可用的工共、用作源输入的制品,以及生成的输出。
图2-1展现了Ant的各种导入和导出任务,所有功能对Eclipse的HibemateTools插件都可用.阅读本意时请参照这
Q8.HelloHibernate
//Firstunitofwork
Sessionsession=HibernateUtil.getSessionFactory().openSession();
Transactiontx=session.beginTransaction();
Foofoo=newFoo();
LongfooId=(Long)session.save(foo);
mit();
session.close();
//secondunitofwork
SessionnewSession=HibernateUtil.getSessionFactory().openSession();
TransactionnewTransaction=session.beginTransaction();
Listfoos=newSession.createQuery(“fromFoo”).list();
newTmit();
newSession.close();
//thirdunitofwork
SessionthirdSession=HibernateUtil.getSessionFactory().openSession();
TransactionthirdTransaction=session.beginTransaction();
FoofoothirdSession.get(Foo.class,fooid);
foo.setOneProperty(“somevalue”)
thirdTmit();//脏检查自动执行更新
thirdSession.close();
HibernateUtil.shutdown();
调用HibernateSession、Transaction和Query接口访问数据库:
Session(会话)——HibernateSession集多种功能于一身。
它是个单线程、非共享的对象,表示使用数据库的一个特定工作单元。
它有持久化管理器API,调用它来加载和存储对象。
(Session的内部由一列SQL语句组成,这些话句要与数据库在某个时点上进行同步,且托管持久化实例的一个映像由Session监控.)
Transaction(事务)——这个HibernateAPI可以用来编程式地设置事务范围,但它是可选的(事务范围不是可选的)。
其他的选择还有JDBC事务划分、JTA接口,或者带有EJB的容器托管事务。
Query(查询)——数据库查询可以写进Hibernate自己的面向对象的查询语言(HQL)或者简单的SQL中。
这个接口允许你创建查询、在查询中绑定参数给占优符,并以各种方式执行查询。
Q9.Hibernate配置
SessionFactory通过Configuration类提供配置信息。
Configuration默认(可通过Configuration的构造方法改变)读取在ClassPath根目录下搜索hibernate.properties
所有的Hibernate配置可以再org.hibernate.cfg.Environment中找到。
Q10.数据库连接池
连接地在非托管的应用程序运行时环境中的角色(即不要任何应用程序服务器)。
使用Hibernate,这个图就变了:
它充当JDBC连接池的一个客户端程序,如图2-3所示。
应用程序代码给持久化操作使用Hibemate的Session和QueryAPI,它(可能)用Hibernate的TransactionAPI管理数据库事务。
Q11.监控Hibernate
Statisticsstats=HibernateUtil.getSessionFactory().getStatistics();
stats.setStatisticsEnabled(true);
stats.getSessionOpenCount();
stats.logSummary();
EntityStatisticsitemStats=stats.getEntityStatistics(.auction.model.Item.);
itemStats.getFetchCount();
统计接口中,Statistics用于全局的信息,EntityStatistics用于有关一个特定实体的信息,CollectionStatistics用于一俨将定的集合任务,QueryStatistics用于SQL和HQL查询,SecondLevelCacheStatistics用于详细的关于可选的二级数据高速缓存中的一个特定区域的运行时信息。
一种方便的方法是logSummary(),它通过单个调用把一个完整的摘要打印到控制台.如果想要通过配置来启用统计绵合,并且不用编程,就设置hibernate.generate_statistics配置属性为true。
有关各种统计税取方法的更多信息请见API文挡。
Q12.JPAHelloWorld
12.1使用注解标注
使用javax.persistence.*中的注解@Entity@Table@Id@GeneratedValue@Column@ManyToOne注解标注实体。
12.2构键Persistenceunit
SessionFactory在hibernate应用程序中表示一个特定的逻辑数据存储配置.EntityManagerFactoryJPA应用程序中扮演着同样的角色,你用配置文件或者在应用程序代码中配置EtityManagerFactory(EMF),就像配置SessionFactory一样。
EMF的配置,与一组映射元数据(通常是被注解的类)一起,被称作持久化单元(persistenceunit).
编写persistence.xml提供必要的配置参数,并放入到META-INF目录下。
persistence.xml包括指定JPA的实现产品(hibernate),以及hibernate的各种属性。
12.3使用JPA编程接口
●javax.persistence.Persistence——给EntityManagerFactory的创建提供一种静态方法的一个启动类。
●javax.persistence.EntityManagerFactory——等同于HibemateSessionFactory这个运行时对象代表个特定的持久化单元它是钱安全的,通常被当作sìngleton)处理,并给EntityManage实例的创建提供方法。
●javax.persistence.EntityManager——等同于HibernateSession。
这个单线程、非共享的对象表示数据访问的个特定工作单元。
它提供方法去管理实例的命周期创建Query实例
●javax.persistence.Query——等同于HibemateQuery个对象是一种特定的JPA语言或者原生的SQL查询表示法,它允许参数安全绑定,并给查询的执行提供各种各样的方法。
●javax.persistence.EntityTransaction——等同于HibernateTransaction,在JavaSE环境中用于RESOURCE_LOCAL事务的划分。
在JavaEE中,依赖JPA标准的javax.transaction.UserTransaction接口进行编程式的事务划分。
//StartEntityManagerFactory
EntityManagerFactoryemf=Persistence.createEntityManagerFactory("helloworld");
//Firstunitofwork
EntityManagerem=emf.createEntityManager();
EntityTransactiontx=em.getTransaction();
tx.begin();
Messagemessage=newMessage("HelloWorld");
em.persist(message);
mit();
em.close();
//Secondunitofwork
EntityManagernewEm=emf.createEntityManager();
EntityTransactionnewTx=newEm.getTransaction();
newTx.begin();
Listmessages=
newEm.createQuery("selectmfromMessagemorderbym.textasc").getResultList();
System.out.println(messages.size()+"message(s)found");
for(Objectm:
messages){
MessageloadedMsg=(Message)m;
System.out.println(loadedMsg.getText());
}
newTmit();
newEm.close();
//Shuttingdowntheapplication
emf.close();
Q13.与JavaEE整合
Hibemate能够与JavaEE容器整合的三大关注点在:
JTA、JNDI、JMX。
JTA允许Hibernate参与托管资源(数据库连接)中的事务。
并且能够把自身当作一项服务绑定到JNDI上。
最后,Hibernate可以通过JMX被部署,然后通过JMX容器被当作服务来管理,并且使用标准的JMX户端程序在运行时被监控。
13.1与JTA整合
JTA是Java企业应用中事务控制的标准服务接口。
包括于事务划分的UserTransactionAPI和用于参与事务生命周期中的TransactionManagerAPI。
事务管理然能够协调跨资源的单个事务一。
JTA事务服务由所有JavaEE应用程序服务器提供。
需要在配置sessionFactory的hibernate.transaction.factory_class属性为JTATransactionFactory。
13.2JNDI绑定的SessionFactory
SessionFactory应该如何储,以及它在应用程序代码中应该如何访问?
一般的做法是编写一个在静态字段中存放SessionFactory的HibernateUtil类,并提供静态的getSessionFactory()方法。
然而,如果在个支持JNDI的部署应用程序,Hibrnate可以把SessionFactory绑定到JNDI.你需要时可以到那里查找。
hibernage.session_factory_narne属性设且为JNDI节点节点的名称,Hibemate的SessionFactory就会自动把自身绑定到JNDI。
13.3JMX服务部署
Java管理扩展(JavaManagementExtension.JMX).JMX是关子系统组件管理或者系统服务管理的。
Hibernage可以作为一项托管的JMX服务,被其他的服务依赖和使用。
Q14.HiberanteCore与JPA对照表
第三章领域模型和持久化
Q15.领域模型
15.1分析领域模型
按照面向对象的方式考虑:
抽象、封装、多态、继承
按照数据库模式考虑:
主、子表,约束等。
两者有较大差别。
例如:
报销单——报销明细。
15.2实现领域模型
领域模型分析结束后,还必须处理几个经典问题:
如何把业务关注点与横切点(例如事务和持久化)分离?
你需要自动的还是透明的持久化?
必须使用特定的编程模型来实现这点吗?
15.2.1横切关注分离
1、EJB个托管的组件EJB容器内部执行容器拦截别bean的调用并执行它自己的功能。
这种方法允许容器以一种普遍方式实现预设的横切关注点——安全性、并发性、持久化、事务和远程。
2、使用Spring的AOP事务管理机制来处理以上问题。
15.2.2透明和自动持久化
透明词,意味着领域模型的持久化类和持久化逻辑之间一个完整的关注点分离,在这里持久化类不知道且不依赖于持久化机制。
自动一词是指让你不用处理低级机械化细节的一种持久化解决方案。
体现在:
Hibernate的实体使用POJO;Hibernate使用很少的持久化接口Session、Query.
15.2.3编写POJO并制定元数据
15.3创建动态的应用程序
除最基本的POJO来表示实体外,Hibernate还允许通过Map和Dom4j来表示实体。
第四章映射持久化类
Q16.理解实体和值类型
16.1细粒度的领域模型
Hibernate主要目标是支持细粒度的领域模型,粗略地说,细粒度意味着类比表更多。
例如:
用户可能既有付款地址又有家庭住址。
16.2识别实体和值类型
考虑如下因素识别值对象:
1、是否有一个依赖的生命周期,如果此对象依赖于另一个对象的生灭,就认为他是有一个依赖的生命周期的——两个对象是聚合关系。
2、是否需要它们自己的同一性(java中体现为==和equals()方法,数据库中体现为主键是否相等),就是说你的代码中会不会去比较两个对象是否具有同一性,
3、是否需要支持共享引用。
如果一个对象有一个依赖的生命周期,不需要它们自己的同一性,并且不必支持共享引用的话它就是个值类型的对象。
16.3映射带有同一性的实体
16.3.1理解Java同一性和等同性
●如果对象在JVM占据着相同的内存位置,它们就是同一的。
这可以通过使用==操作符进行检查。
这个概念称作对象同一性。
●如果对象有着相同的值它们就是相等的,如equals(objecto)方法定义的。
这个概念叫做等同性。
●如果存储在一个关系数据库中的对象表示相同的行,或者它们共享相同的表和主键值它们就是同一的。
这个概念称作数据库同一性。
16.3.2处理数据库同一性
给实体添加标识符属性,并映射标识符属性。
16.4类映射选项
16.4.1动态的SQL生成
通过制定dynamicInsert及dynamicUpdate可以制定是否动态生成插入及更语句。
16.4.2使实体不可变
一个特定类的实例可以是不可变的,例如数据字典。
通过将mutable属性设为false来映射个不可变的类,就可以避免脏检。
16.4.3HQL中实体名称
默认情况下,所有的类都自动的“导入”到Hibernate查询语言(HQL)的命名空间,这意味着,你何以在HQL中使用更为简短的名称。
但如果有两个类具有同样的类名则会引起冲突。
解决方法一:
可通过autoimport=”false”属性,禁止自动导入,通过在xml中指定rename来手动导入如下:
或通过@Entity(name="Auctionltem")来指定别名。
解