hibernate框架学习笔记
第一天1
Hibernate框架的作用,优点:1
Hibernate设计原理:2
Hibernate主要API:2
Hibernate使用步骤:3
插入一条数据的过程:3
第二天3
Hibernate映射类型:3
2.Hibernate主键生成方式4
3.Hibernate框架的基本特性(默认的情况下采用的是批处理)5
1.一级缓存:5
2.对象持久性:6
3.延迟加载:7
如何使用同一个Session8
第三天9
1.一对多关系映射9
2.多对一关系映射9
2.Inverse属性10
第四天10
1.如何利用MyEclipse根据数据库生成实体类和映射描述文件10
2.多对多关系映射11
3.继承关系映射11
第五天11
---------总结---------11
1)继承关系映射12
2)Hibernate查询13
第六天-14
1.Hibernate高级特性14
1)二级缓存技术14
2)查询缓存技术14
*3)悲观锁和乐观锁15
第一天
Hibernate框架的作用,优点:
主要是用于负责对数据库的操作(增删改查的操作),使用该框架可以简化数据操作代码量,要程序员将更多的精力放在业务的编写上。业务复杂的情况下对数据的操作就不单纯只是DAO的操作了。本质上是对JDBC技术的封装。封装了很多智能的功能。原有的JDBC方式访问数据库的时候的不足之处有:a.需要编写大量复杂的SQL语句。
B.需要做大量的对象和记录之间关系的转换。c.数据库之间的转换使用的时候(也就是数据库的移植),要更换的SQL语句。需要变更的是分页语句,使用数据库函数的语句。
使用了Hibernate框架可以解决上面的三个问题。
Hibernate设计原理:
Hibernate框架是一款ORM工具。基于ORM设计思想开发出来的。ORM(Object—Relation--Mapping)基于ORM思想设计出来的还有:Hibernate,IBATIS,JPA等。他们都是需要文件信息进行操作,文件信息是必不可少的。
对象:指的就是Java的entity对象,
关系:指的是关系数据库,
映射:就是对象和数据库的对应关系。
思想是:将程序中对象和数据库中数据记录自动映射转换。利用ORM工具,在查询的时候,可以自动将记录封装成Java对象返回,在更新,插入操作时,可以将对象自动写入数据表。向中间的SQL+JDBC操作细节,完全封装在工具底层。要做框架的话都要学JAVA反射技术:通过反射技术可以获取类的所有信息,包括类的结构和字段属性,方法等。
Hibernate框架的主要结构:a.java实体类(n个)用于封装数据表记录的java对象类型。b.hibernate.cfg.xml(1个)Hibernate的主配置文件,里面主要定义数据库的连接参数。还可以定义框架的参数。刚启动的时候就会加载进去的。c.文件名.hbm.xml(),Hibernate映射描述文件,里面定义了实体类和数据库之间的对应关系,比如:哪类和哪个表,属性和表字段之间的对应关系。
Hibernate主要API:
使用的时候,需要使用Hibernate提供的API,他们将sql+jdbc操作细节封装起来了。a.Configuration:主要用于加载配置文件Hibernate.cfg.xmlb.SessionFactory:通过Configuratioin获取,主要用于创建hibernate中的session对象。和servelt里面的session是一点关系都没有的,servlet里面的是客户和服务器的会话。Hibernate中的是程序和数据中的会话。c.Session:代表java程序与数据库之间的一次连接。负责对数据库进行增删改查操作。提供的方法有:save(),update(),load(),get(),list(),load()和get()是对主键进行触发。d.Transaction:负责事务管理。Hibernate是没有自动提交的。注意的是:每次做增删查改操作必须要显示提交事务,因为:Hibernate将默认提交功能关闭。e.Query:负责执行Hibernate查询语句。
Hibernate使用步骤:
a.创建工程,引入hibernate和驱动开发包,b.在src下追加hibernate.cfg.xml主配置方言设置:diarect:用于封装指定数据库的SQL方言加载映射描述文件:c.根据数据表创建entity实体类。d.编写实体类和数据表的映射文件hbm.xml<calss>属性里面有name:类名,属性名,,,table:对应的表名。Class里面有一个<id>是定义的主键映射,属性有name:属性名,column:对应表中的字段名,type:属性类型,要全部小写,如果是写成java的话要写成包名点类名点属性类型这种形式的方式写。可以指定主键的生成方式,<genderatioin>class:生成方式,非主键的用<property>来写,属性也是一样的。e.利用hibernateAPI实现增删改查操作
插入一条数据的过程:
1.创建一个实体类对象,2.调用hibernate的API用于装载配置文件,Configurationconf=newConfiguration();如果是默认的配置文件hibernate.cfg.xml则直接调用,conf.configure();如果不是的话则conf.configure(newFile(“abc.xml”));3.创建SessionFactory:SessionFactoryfactory=conf.buildSessionFactory();4.创建Session:Sessionsession=factory.openSession();5.获得事务:Transactiontx=session.getTransaction();6.开启事务:tx.begin();7.插入数据:session.save(user);8.提交事务:tx.commit();9.关闭session:session.close();
----------------课后练习------------------
1.基于Cost表做增删改查练习
2.重构资费管理模块的添加、开启、删除功能
第二天
Hibernate映射类型:
在hbm.xml中,描述属性和字段之间映射的时候,可以使用type属性指定映射类型。Type属性可以指定java类型和hibernate类型,主要作用是指定属性值和字段值之间转换的时候,采用的转换类型。这里建议使用hibernate映射类型。hibernate映射类型主要有下面的几种:a.整数类型:byte,short,integer,long;b.浮点数类型:float,double;c.字符串类型:string;d.日期类型:date:只取年月日,time时分秒把年月日忽略,timestamp:年月日时分秒。e.boolean类型:yes_no.将true/false转换成Y/Ntrue_false;将true/false转换成T/F;;有些数据库没有boolean类型。可以通过和字符类型的转换。
f.其他:big_decimal:----Bigdecimal,big_integer—Biginteger,colb:比较大的字符信息。Blob:字节信息的存储
2.---------------------------------------------------案例------------------------------------------------------
createtablet_foo(
t_idnumberprimarykey,
t_namevarchar2(50),
t_salarynumber(8,2),
t_marrychar(1),
t_hiredatedate,
t_last_login_timedate
)
-------------mysql----------------
createtablet_foo(
t_idintauto_incrementprimarykey,
t_namevarchar(50),
t_salarydouble,
t_marrychar(1),
t_hiredatedate,
t_last_login_timetimestamp
)defaultcharset=utf8;
2.Hibernate主键生成方式
在hbm.xml中,可以为主键指定生成方式。
具体如下:
*a.sequence:采用指定序列生成,适用于Oracle数据库。使用格式
<generatorclass="sequence">
<paramname="sequence">
foo_seq
</param>
</generator>
*b.identity:采用数据库自增涨机制生成。适用于MySQL,SQLServer数据库。
<generatorclass="identity">
</generator>
*c.native:根据方言自动选择identity,
sequence等生成方式。
<generatorclass="native">
</generator>
*d.increment:首先获取最大主键值,然后加1,再执行插入操作。适用于各种数据库。
先执行selectmax(id)fromt_foo;
再执行insertinto...
<generatorclass="increment">
</generator>
e.assigned:Hibernate忽略主键生成,不负责管理。需要程序员在程序中指定主键值
<generatorclass="assigned">
</generator>
f.其他
uuid:采用UUID算法生成一个字符串主键值
hilo:采用高地位算法生成一个数值主键值
3.Hibernate框架的基本特性(默认的情况下采用的是批处理)
1.一级缓存:
(session级别缓存,默认情况开启)持久态:每次创建一个Session对象,会为这个session对象提供一个缓存区,用于缓存该session查询出来的单个对象。Session关闭的时候它就会消失。一级缓存主要是针对单个对象的。不同的session访问同一个对象的时候,要访问数据库两次,每个session只能访问自己的缓存区的对象,同一个session不同的结果对象,会对数据库访问两次。
(session要负责将持久态对像的变化更新到数据库,在flush()的时候更新,tx在提交的时候会自动调用session的flush()).
一级缓存区的管理方法:游离态:session.evict(obj);将obj从一级缓存移除。session.clear();
如果session被查询,session将先到缓存中查找是否有被查询的对象,找到则直接取出,找不到则访问数据库。
Session需要负责实时维护在缓存中的数据,保证缓存中的数据与数据库中的数据的一致性,一旦用户对缓存中的数据做了修改,当commit提交事务或者执行flush()时候session会立刻将数据更新到数据库中。Commit()方法默认调用flush,然后提交事务,而flush()是将缓存区的数据同步到数据库。
一级缓存的优点:
当利用同一个session对象多次查询同一个数据对象时,仅第一次从数据库查询,后续几次从缓冲区中取。如果缓存的对象过多会造成溢出,通过下面的方法处理。
Sessionsession=
HibernateUtil.getSession();
Transactiontx=
session.beginTransaction();
for(inti=1;i<100000;i++){
Useruser=newUser();
//......
session.save(user);
//20条调用一次flush
if(i%20==0){
session.flush();//同步到数据库
session.clear();//清空缓存
}
}
tx.commit;
HibernateUtil.close();
2.对象持久性:
Hibernate框架用于实现对数据库的操作,为应用程序构建一个持久层,(由持久对象构成)
在hibernate使用中,实体对象有三种状态:
临时状态:new
采用session对象查询出来的,受session对象管理的对象。比如:load,get,save,update方法后的对象,处在持久性的对象的特点:数据状态可以更新到数据库;对象不能被垃圾回收器回收;对象会一直在一级缓存区存放,由session管理。
游离/脱管状态:脱离了session的管理,如:调用了session.evict(),session.clear();
3.延迟加载:
Hibernate提供一些方法,利用这些方法返回的对象,并没有立刻加载数据库的数据,而是在调用对象的gertter方法时才触发数据库查询,加载数据记录。
使用延迟加载的好处是;可以降低并发量,减少资源占用,如果同步查询的数量很多,session会溢出,如果是延迟加载,可以让程序支持更多的用户。
哪些方法具有延迟加载:session.load();query.iterator(),关联属性。这些方法返回的对象里面没有数据,数据在使用的时候(调用getXXX方法时)才取。他们返回的不是实体类,而是该实体类动态子类对象,该子类重写了getXXX方法。在这个方法中触发了对数据库的访问。当调用load(),iterator()方法时,具体hibernate调用了GBLIB的功能实现了动态生成子类。Get方法查询的时候没有记录返回Null,load()方法没有记录时会异常。
Query.iterator()这个方法是和query.list()这个方法是对应的一个是返回实体类,一个是延时机制返回动态子类对象。get()和load()方法的区别:相同点:按照主键ID当条件查询某个对象。不同点:load()采用了延迟加载机制,get()为立刻加载;load如果没有符合记录会抛出异常,get方法会返回null;load方法返回的是动态子类对象,get方法返回的是实体类。
使用延时加载方法的时候要注意避免出现nosession的异常。
动态生成子类对象的原理:具体的说是动态代理技术。注意:在自定义的类的时候不要做成final类型的,因为在很多框架中会有类似的动态生成机制
d)延迟加载实现原理(动态代理技术)--采用延迟加载方法后,Hibernate会在底层动态的创建一个新的实体类,动态编译成class.publicclassFoo$$CGLIB...extendsFoo{
//重写foo中属性的getter方法
publicStringgetName(){
//判断是否有name值,没有查询DB
returnname;
}
}
--Hibernate采用了cglib.jar和asm.jar两个开发包。实现了动态生成新类和编译操作
课堂补充注解:如果不是主键查询的时候用hql:from类名where属性名。Query.setstring(0,);?号是从0开始,不是从1开始。
分页查询的时候:设置分页查询的参数:query.setFisrtResult(begin);设置抓取记录起点;query.setMaxResult(pageSize);设置最大抓取记录。结束点它会自己计算。
如果是在响应jsp之后要关闭session的话可以通过拦截器或者过滤器来在最后进行关闭
=========案例练习==========
1.重构资费列表显示示例
为了支持延迟加载方法,需要在项目中采用OpenSessionInView思想。可以利用Filter和Interceptor技术实现。
*.action-->拦截器前期(无)
-->Action-->DAO-->Result
-->JSP(通过标签和EL获取对象数据)
-->拦截器后期(关闭Session)
-->将HTML结果响应
如何使用同一个Session
处理的情况下:拦截器中使用的session一定要是同一个session这样对于事务的处理才是同一个事务。要使用线程池技术来获取同一个session。
方案一:利用ThreadLocal机制,实现Session与当前线程绑定ThreadLocal<Session>sessionLocal=newThreadLocal<Session>();
获取session的时候要先判断session是不是存在,然后再创建新的session。
方案二:利用Hibernate框架封装的机制,实现Session与当前线程绑定
返回当前线程绑定的session,需要在hibernate.cfg.xml增加配置
//如果没有的新建一个,然后和线程绑定
//该Session对象在事务结束自动关闭
//该Session对象必须在一个事务中使用
returnsf.getCurrentSession();
//创建一个新的Session对象,
//必须手动关闭
第三天
Hibernate关系映射的作用:利用关联映射,Hibernate可以帮着查询加载对象相关的数据,可以简化查询代码,此外还可以基于关系进行增删查改操作。
一对多关系映射:
由一条字段找到多条记录。要设成set<>的属性a.确定1的一方和多的一方,1的一般是主键,多的一般是外键,b.由1的一方对象查询出多的一方的记录。c.首先在1的那方实体类中添加集合属性setd.然后在1的那方的hbm.xml中定义一对多关系映射的描述<setname="关系属性">
<keycolumn="关联条件的外键字段"/>
<one-to-manyclass="关联的另一方类型,即n方类型"/>
</set>e.使用的时候,通过1的那方对象.关系属性获取多的那方的数据
多对一关系映射:
a.需要由多方对象查询1放对象信息。b.在多方实体类中添加属性,属性类为1方类型c.在多方hbm.xml文件中,添加属性的映射描述信息。d.清楚多方的实体类中外键字段描述信息和属性。就是重复出现的字段描述e.使用时,通过多方对象.关联属性获取相关信息。
关联操作注意事项:要避免频繁使用,默认情况下,
A.在hbm.xml中为属性添加lazy=”false”(关联属性数据在主对象加载的时候加载)在为这个属性追加fetch=”join”(指定关联属性加载方式,可以指定为select,join,subselect)默认的是select表示的是需要的时候加载,jion表示的是同时加载使用的是表连接的语句加载。
写一个HQL,采用joinfetch关键字加载关联属性,需要自己写一个sql语句,这样可以自己来决定是什么加载注意:a方案会影响所有service对象操作,不推荐使用,如果需要关联属性随着主对象加载而加载推荐使用b方案实现。
5.级联查询:
6.级联添加:先插入数据在添加级联关系。
7.级联删除:
删除的时候不能用new出来的的对象,要使用缓存的形式进行查询了再session.ldelete();
对主对象做删除操作的时候,关联属性电视剧也做相应的删除操作。先解除关联关系然后再删除。a.需要在hbm.xml中的关联属性开启级联删除操作。b.在执行session.delete(obj)操作时,删除的obj对象时龙session先查询出来。不要使用new出来的对象,因为不具有关联的数据,hibernate找不到相关数据。
缺点:级联删除采用n+1个delete删除数据,因此关联数据对象n过多的时候,不推荐使用,而是采用hql语句进行批量删除。
Inverse属性:可以控制关系字段值维护的操作是由哪一方负责的,也就是两个表的关联条件字段。默认情况下由具有关系的对象双方负责,也就是不管是哪个做了操作都要对字段进行维护,让哪一方负责维护就在哪一方添加这个属性就额可以。一般是在1方关联属性中使用inverse=true,意思是要1方放弃关系维护操作,不会出现update维护关系的这种语句。只要是一对多的情况下建议使用inverse=true这个属性,
第四天
1.如何利用MyEclipse根据数据库生成实体类和映射描述文件
1)在DBBrowser中建立一个与数据库的连接
2)新建一个WebProject工程
3)为工程添加Hibernate开发框架
(导入包,添加主配置及其参数设置)
选中工程-->右键-->MyEclipse-->AddHibernateCapabilities...
4)按MyEclipse向导添加Hibernate框架开发包,添加主配置文件,设置连接参数,创建一个HibernateUtil工具类.
----------生成实体类和hbm.xml-------------
5)进入DBBrowser,选中要操作的数据表,右键-->HibernateReverseEngineering.按向导生成实体类和hbm.xml.
6)向导界面1:选择存放实体类和hbm文件的工程和package。
选择要生成文件:hbm.xml,pojo,dao
7)向导界面2:将TypeMapping选中为HibernateTypes
向导界面3:点击Finish完成
2.多对多关系映射
多对多关系在数据库中需要3张表表示。
例如AdminInfo-->Admin_Role<--Role
如果需要根据Admin查找Role,可以建立Admin到Role的多对多关系映射。具体过程如下:
a.在Admin实体类中追加一个集合属性,用于存储相关联的Role对象信息
b.在Admin的hbm.xml中描述集合属性映射
<setname="关系属性"table="关系表">
<keycolumn="与当前类型联的关系表字段">
</key>
<many-to-manyclass="关联的另一方类型"
column="与另一方类型关联的关系表字段">
</many-to-many>
</set>
3.继承关系映射
第五天
---------总结---------
1.第一天
理论:Hibernate作用和原理
应用:Hibernate对单表的基本操作
2.第二天
理论:了解什么是一级缓存,对象持久性,延迟加载
应用:掌握OpenSessionInView模式控制Session关闭。将Session与请求处理线程绑定。使用ThreadLocal自己封装,也可以使用Hibernate3封装的getCurrentSession();
3.第三天
理论:关联映射的作用
应用:掌握一对多,多对一基本映射
基于关系*查询,添加,*删除等操作
4.第四天
理论:利用Myeclipse生成实体类和映射描述
应用:掌握多对多基本映射和操作
掌握继承基本映射和操作
5.第五天
理论:了解其他的查询方式,高级特性
应用:Hibernate的HQL查询
==============================
1)继承关系映射
a.父类一张表,每个子类一个表,主键对等
b.可以采用<joined-subclass>进行继承关系映射,具体如下
--在子类追加extends父类
--在子类hbm.xml中定义
<joined-subclassname="子类类型"
extends="父类类型"table="子类表">
<keycolumn="子类哪个字段与父类关联">
</key>
//子类中属性的property映射
</joined-subclass>
######示例表Oracle######
CREATETABLEPRODUCT
(
IDNUMBER(5)CONSTRAINTPRODUCT_ID_PKPRIMARYKEY,
NAMEVARCHAR2(20),
PRICENUMBER(15,2),
PRODUCT_PICVARCHAR2(100)
);
CREATESEQUENCEproduct_seq;
CREATETABLEBOOK
(
IDNUMBER(5)CONSTRAINTBOOK_ID_PKPRIMARYKEY,
AUTHORVARCHAR2(20),
PUBLISHINGVARCHAR2(50),
WORD_NUMBERVARCHAR2(20),
TOTAL_PAGEVARCHAR2(20)
);
CREATETABLECAR
(
IDNUMBER(5)CONSTRAINTCAR_ID_PKPRIMARYKEY,
BRANDVARCHAR2(20),
TYPEVARCHAR2(1),
COLORVARCHAR2(50),
DISPLACEMENTVARCHAR2(20)
);
##############################
2)Hibernate查询
*a.HQL查询
HibernateQueryLanguage
HQL与SQL语句结构相似,SQL语句是面向数据表和字段进行查询,而HQL语句是面向Hibernate映射过来的对象和属性进行查询,因此HQL被称为是一种面向对象查询语言
HQL和SQL共同点:
--都支持select,from,where,orderby,
having,groupby等子句。
--都支持运算符表达式,例如+,-,*,/,>,<等
--都支持in,notin,betweenand,like等过滤条件关键字
--都支持分组函max,min,sum,avg,count
HQL和SQL不同点:
--HQL是大小写敏感的,类名和属性名严格区分大小写
--HQL不支持select*写法
--HQL不支持join...on...中的on子句
--HQL不支持表名和字段名
HQL案例:
--查询所有:fromAccount
--参数查询:fromAccountwherestatus=?
fromAccountwherestatus=:stat
--查询部分字段:
selectid,osUsernamefromService
返回ist<Object[]>
selectnewService(id,osUsername)fromService
返回List<Service>
--在hbm.xml中定义hql:
Queryquery=session.getNamedQuery("标识符")
--分页查询用法:
query.setFirstResult(抓取起点从0开始计算)
query.setMaxResult(抓取最大数量);
Listlist=query.list();
b.Criteria查询(QBC)
了解,参考示例和Hibernate帮助文档
c.NativeSQL查询
了解,参考示例和Hibernate帮助文档
第六天-
1.Hibernate高级特性
1)二级缓存技术
SessionFactory级别的缓存,受SessionFactory管理,可以被不同Session访问和操作。默认是关闭。一般在使用时需要利用SessionFactory.evict()等方法显式的管理该缓存
a.什么情况可以考虑使用二级缓存
--该对象被多个不同用户频繁使用
--该对象更新操作不频繁
b.如何使用二级缓存
--添加ehcache.jar开发包和src/ehcache.xml配置
--在hibernate.cfg.xml中开启二级缓存,指定采用哪种二级缓存组件
--需要缓存哪个对象,就在hbm.xml中添加<cache>元素配置
<cacheusage="read-only或read-write"
region="采用ehcache.xml哪组参数缓存该对象"/>
c.二级缓存管理
sessionFactory.evict方法
2)查询缓存技术
一级和二级缓存只能缓存单个对象,查询缓存可以缓存一个select查询结果。
a.查询缓存的使用
--要对查询的目标对象开启二级缓存
--在hibernate.cfg.xml中开启查询缓存设置
--在执行query.list()查询之前,
调用query.setCacheable(true);
b.适合使用查询缓存的情况
--不同用户都执行相同的SQL查询和相同结果
--查询结果集不发生改变
注意:在使用关联映射时,关系属性数据默认不参与缓存,即使访问对象在缓存中存在,当访问该对象的关联属性数据时,还得去数据库查询。如果需要缓存关联属性数据,需要对关联属性和hbm.xml都设置<cache>元素
*3)悲观锁和乐观锁
当出现多个用户同时执行更新等操作时,会出现事务交叉更新操作的冲突,会破坏业务和数据的完整性。可以使用悲观锁和乐观锁解决这类问题。
a.悲观锁机制:在进行数据查询时追加一个锁机制,进行业务操作,此时其他用户不能进行增删改操作,在事务结束时会自动将锁释放,其他用户可以继续执行此类操作。
悲观锁特点:将用户操作一个一个处理,可以解决更新并发问题,缺点是处理效率比较低。
Hibernate悲观锁机制一般是借助于数据库锁机制。
session.load(Train.class,1,);
session.get(Train.class,1);
b.乐观锁机制:多个不同用户都可以同时对数据库记录进行查看和更新操作,但是最先commit提交的用户会执行成功,后续用户会以异常形式提示失败。
乐观锁是借助于一个版本字段进行控制,当并发操作中一个用户成功提交了,版本字段值会自动加1,后续提交的对象版本信息小于数据库版本字段值会被hibernate阻止掉。
乐观锁特点:允许多个用户同时操作,处理效率相对较高。
乐观所使用步骤:
--将原有数据表追加一列版本字段,初始值0
--在实体类中添加版本属性
--在映射描述文件中采用<version>元素定义版本属性和版本字段的映射
--当发生多个事务并行交叉执行时,第一个提交的成功,后续提交的会抛出异常。可以异常捕获给用户一个友善的提示。
==============示例表=================
createtabletrain(
t_idnumberprimarykey,
t_valuenumber,
t_versionnumber);
insertintotrainvalues(1,100,0);