hibernate框架学习笔记

thunderstorm 2013-11-24

第一天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);

相关推荐

LetonLIU / 0评论 2020-05-29
东方咖啡屋 / 0评论 2020-01-06