第3章Hibernate中基本的数据库操作实现_第1页
第3章Hibernate中基本的数据库操作实现_第2页
第3章Hibernate中基本的数据库操作实现_第3页
第3章Hibernate中基本的数据库操作实现_第4页
第3章Hibernate中基本的数据库操作实现_第5页
已阅读5页,还剩53页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、hibernate技术内幕深入解析hibernate架构设计与实现原理第1章第3章 hibernate中基本的数据库操作实现3.1 概述 hibernate主要是解决实体-关系映射问题的。这其中实体po(persistent object)的持久化、数据库事务、对数据库的操作等都是在session环境下完成的。但是session不是线程安全的。同一个session不能被多个线程使用,否则把会引起存取数据逻辑上的混乱。而sessionfactory是线程安全的,多个线程可以访问同一个sessionfactory,获取不同的session从而保证了hibernate的安全性。3.2 持久化器ent

2、itypersisterentitypersister类是用于实体的持久化的,我们称之为实体持久化器。它有数据库插入、更新与删除等功能。hibernate给出了三个实现类:singletableentitypersister、joinedsubclassentitypersister、unionsubclassentitypersister。其中singletableentitypersister是对应的是单张表的持久化器。3.2.1创建entitypersister实体持久化器是在创建sessionfactory时,hibernate把为每一个实体关系映射建立一个实体持久化器实例,然后放入到

3、一个map中,以实体名为键名。以后就可以十分方便地根据实体名获得与之对应的持久器。如代码清单3-1所示。代码清单3-1 创建entitypersisterentitypersister cp = persisterfactory.createclasspersister( model, accessstrategy, this, mapping );entitypersisters.put( model.getentityname(), cp );实体持久化器是是一个class类。它可以在实体关系映像文件中指定。如在代码清单3-2中。这是一个为实体student配置的实体关系映射文件。我们为它

4、的class元素的persister属性指定了一个持久化器。这里指定的是“org.hibernate.persister.entity.singletableentitypersister”。即是一个单表实体持久化器。指定了该属性后,persisterfactory在为student实体创建entitypersister实例时,就为实体student创建一个singletableentitypersister类型的实体持久化器。代码清单3-2 student的实体关系映射文件 我们平时在配置实体关系映像文件时,很少为实体指定persister。那么,persisterfactory把会为这些没

5、有指定persister的实体创建什么样的entitypersister呢?带着这样的问题我们去persisterfactory中看看。在peristerfactory中,创建entitypersister 的方法是createclasspersister。如代码清单3-3粗体部分所示,我们可以看出当没有为一个实体指定persister时,persisterfactory把会为它创建一个singletableentitypersister,即单表持久化器。码清单3-3 创建entitypersisterpublic static entitypersister createclasspersi

6、ster(persistentclass model,entityregionaccessstrategy cacheaccessstrategy,sessionfactoryimplementor factory,mapping cfg) throws hibernateexception class persisterclass = model.getentitypersisterclass();if ( persisterclass = null | persisterclass = singletableentitypersister.class ) return new single

7、tableentitypersister( model, cacheaccessstrategy, factory, cfg );else if ( persisterclass = joinedsubclassentitypersister.class ) return new joinedsubclassentitypersister( model, cacheaccessstrategy, factory, cfg );else if ( persisterclass = unionsubclassentitypersister.class ) return new unionsubcl

8、assentitypersister( model, cacheaccessstrategy, factory, cfg );else return create( persisterclass, model, cacheaccessstrategy, factory, cfg );3.2.2 entitypersister操作实体entitypersister是用于把实体持久化到数据库中的。包括插入实体、修改实体、删除实体等基本的数据库操作。与这些功能对应的方法分别是insert、update、delete。它们的定义如代码清单3-4所示。代码清单3-4 insert、update、dele

9、te方法定义/插入方法public serializable insert(object fields, object object, sessionimplementor session)throws hibernateexception public void insert(serializable id, object fields, object object, sessionimplementor session)throws hibernateexception ;/修改方法public void update(final serializable id, final object

10、 fields, final int dirtyfields, final boolean hasdirtycollection, final object oldfields, final object oldversion, final object object, final object rowid, final sessionimplementor session) throws hibernateexception;/删除一个实体public void delete(serializable id, object version, object object, sessionimp

11、lementor session) throws hibernateexception以下我们以insert方法为例,看看实体是如何插入到数据库的。在这之前我们先了解实体映射文件中的两个属性。我们以第一章节中的students工程为例演示这两个属性的作用。第一个是属性是class元素的dynamic-insert属性。该属性为true,表示insert对象的时候,生成动态的insert语句,该动态insert语句中只包含属性不为空的字段。即如果本实体实例中的某个属性的值是null就不会加入到insert语句当中。该属性的默认false,表示对所有字段进行插入。我们做一个实验,验证class的d

12、ynamic-insert为true和false,对所生成sql语句的影响。我们先不设置student的number属性,确保number属性为null而是不是字符串长度为0的字符串。当class的dynamic-insert属性为true时,把生成如下sql语句:- insert into hibernate.student (clazz_id, name) values (?, ?)当dynamic-insert属性为false时,把生成如下sql语句:- insert into hibernate.student (clazz_id, number, name) values (?, ?

13、, ?)由此可见dynamic-insert属性为true时,把不插入为空的字段。第二个属性是property元素的insert属性。property元素的insert属性是指插入一个实体时,所生成的insert sql语句中是否包含该字段。如果是false把不会包含该字段,反之则反。以下是把age属性设置为false时,所生成的sql语句。不管class的dynamic-insert属性是true或是false均生成如下sql语句:- insert into hibernate.student (clazz_id, number, name) values (?, ?, ?)说明proper

14、ty元素的insert属性为false时,该字段把永远不会插入到数据库中。根据上述我们对dynamic-insert和property元素的insert的理解。我接着阅读hibernate源代码,看看以上所看到的现象在hibernate内部是怎么实现的。代码清单3-5是定义在基类abstractentitypersister中的插入方法。从代码中可以看出在插入时,首先判断实体是否需要动态插入。其判断依据就是实体映像文件中class元素的dynamic-insert属性。当dynamic-insert属性为true时:会调用getpropertiestoinsert方法计算出不为空的字段的数组n

15、otnull。数组的每个元素与fields中的每个元素对应。即notnulli=false,fieldsi把不会插入到数据库。generateinsertstring方法会生成一个预处理语句。这个预处理语句只含有不为空的字段。具体是如何生成预处理语句的,读者可以查看方法generateinsertstring了解其中的细节,在此不再解读。然后调用同名方法如代码清单3-6所示。代码清单3-5 abstractentitypersister类中的insert方法public serializable insert(object fields, object object, sessionimple

16、mentor session)throws hibernateexception final int span = gettablespan();final serializable id;/entitymetamodel.isdynamicinsert()与映像文件中的class元素的dynamic-insert属性对应。if ( entitymetamodel.isdynamicinsert() ) /如果在实体关系映像文件中指定dynamic-insert=true,则自动生成一个insert sql语句。boolean notnull = getpropertiestoinsert(

17、fields );id = insert( fields, notnull, generateinsertstring( true, notnull ), object, session );for ( int j = 1; j span; j+ ) insert( id, fields, notnull, j, generateinsertstring( notnull, j ), object, session );else /如果在实体关系映射文件中指定dynamic-insert=false,使用静态的insert sql语句。id = insert( fields, getprope

18、rtyinsertability(), getsqlidentityinsertstring(), object, session );for ( int j = 1; j span; j+ ) insert( id, fields, getpropertyinsertability(), j, getsqlinsertstrings()j, object, session );return id;protected boolean getpropertiestoinsert(object fields) boolean notnull = new booleanfields.length;b

19、oolean insertable = getpropertyinsertability();for ( int i = 0; i fields.length; i+ ) notnulli = insertablei & fieldsi != null;return notnull;在代码清单3-6的insert方法中,创建了一个binder对象,用于为上述创建的预处理语句绑定数值。然后由insertgeneratedidentifierdelegate执行插入。insertgeneratedidentifierdelegate能在插入数据时生成实体标识。在执行过程中,使用哪个insertge

20、neratedidentifierdelegate与实体关系配置文件中的id的生成策略有关。我们在student实体关系映像文件中配置的是,对应的是identitygenerator.getgeneratedkeysdelegate。在insert的最后调用insertgeneratedidentifierdelegate的performinsert方法。如代码清单3-7所示。代码清单3-6 插入方法insertprotected serializable insert(final object fields, final boolean notnull, string sql, final

21、object object, final sessionimplementor session) throws hibernateexception if ( log.istraceenabled() ) log.trace( inserting entity: + getentityname() + (native id) );if ( isversioned() ) log.trace( version: + versioning.getversion( fields, this ) );/创建一个binder,用于给预处理语句绑定数值。binder binder = new binder

22、() public void bindvalues(preparedstatement ps) throws sqlexception dehydrate( null, fields, notnull, propertycolumninsertable, 0, ps, session );public object getentity() return object;return identitydelegate.performinsert( sql, session, binder );在方法performinsert中,根据insertsql创建一个预处理语句,然后为预处理语句绑定数值,最

23、后是执行预处理语句,返回生成的id标识。代码清单3-7 performinsert方法public final serializable performinsert(string insertsql, sessionimplementor session, binder binder) try / 创建预处理语句preparedstatement insert = prepare( insertsql, session );try /绑定数值binder.bindvalues( insert );return executeandextract( insert );finally releas

24、estatement( insert, session );catch ( sqlexception sqle ) throw jdbcexceptionhelper.convert(session.getfactory().getsqlexceptionconverter(), sqle, could not insert: + messagehstring( persister ), insertsql);public serializable executeandextract(preparedstatement insert) throws sqlexception

25、 /执行预处理语句insert.executeupdate();resultset rs = null;try rs = insert.getgeneratedkeys();/返回idreturn identifiergeneratorhelper.getgeneratedidentity(rs,persister.getidentifiertype();finally if ( rs != null ) rs.close();3.3 实体活动entityaction与活动队列actionqueueentityaction执行某一具体操作的信息体,用于执行增删改等活动,在每个具体的entity

26、action类中,封装有session、实体的id、实体的实例、实体持久化器persister。而actionqueue是实体活动的集合,并且其中的活动是有次序的。3.3.1 实体活动entityactionentityaction实现了executable接口,在executeable中有一个重要的方法execute,用于执行一个活动。hibernate给出了以下几类entityaction :删除活动entitydeleteaction、标识id插入活动entityidentityinsertaction、实体插入活动entityinsertaction、实体更新活动entityupdat

27、eaction,这和数据库基本操作相对应。我们这里以entityinsertaction为例,看看enittyaction是如何工作的。一般来说,一个活动的执行是从execute方法开始的,我们了解entityinsertaction也从其execute方法开始。源码如代码清单3-8所示。首先在插入前调用preinsert方法发布事件,通知相关监听器要做插入操作了。hibernate有一个默认的插入前监听器jaccpreinserteventlistener,用于检查插入前的安全性。如果插入前没有问题,就使用实体持久化器进行插入操作。这在前一小节中已做说明。然后把实体标识为已经插入到数据库中。

28、代码清单3-8 entityinsertaction中的execute方法public void execute() throws hibernateexception entitypersister persister = getpersister();sessionimplementor session = getsession();object instance = getinstance();serializable id = getid();boolean veto = preinsert();/ dont need to lock the cache here, since if

29、someone/ else inserted the same pk first, the insert would failif ( !veto ) /插入实体persister.insert( id, state, instance, session );entityentry entry = session.getpersistencecontext().getentry( instance );if ( entry = null ) throw new assertionfailure( possible nonthreadsafe access to session );/标识实体已

30、插入到数据库中。entry.postinsert();/更新实体的versionif ( persister.hasinsertgeneratedproperties() ) cessinsertgeneratedproperties( id, instance, state, session );if ( persister.isversionpropertygenerated() ) version = versioning.getversion(state, persister);entry.postupdate(instance, state, version

31、);final sessionfactoryimplementor factory = getsession().getfactory();/缓存实体if ( iscacheputenabled( persister, session ) ) cacheentry ce = new cacheentry(state,persister, persister.hasuninitializedlazyproperties( instance, session.getentitymode() ),version,session,instance);cacheentry = persister.get

32、cacheentrystructure().structure(ce);final cachekey ck = new cachekey( id, persister.getidentifiertype(), persister.getrootentityname(), session.getentitymode(), session.getfactory() );boolean put = persister.getcacheaccessstrategy().insert( ck, cacheentry, version );if ( put & factory.getstatistics(

33、).isstatisticsenabled() ) /二级缓存factory.getstatisticsimplementor().secondlevelcacheput( getpersister().getcacheaccessstrategy().getregion().getname() );/发布插入完成事件postinsert();/统计插入if ( factory.getstatistics().isstatisticsenabled() & !veto ) factory.getstatisticsimplementor().insertentity( getpersister

34、().getentityname() );3.3.2 活动队列actionqueue活动队列是一系统活动的集合,可以执行一个单独的活动: execute(executable executable),也可以执行一批同类型的活动executeinserts,也可以执行所有的活动executeactions();种类监听器在处理用户的请求事件时,最终一般把请求数据组装一个action放入到actionqueue中等待执行。actioinqueue一般会在session执行flush、级联操作等时候执行。3.2 session接口中各种保存方法的用法与底层实现细节在hibernate中,sessio

35、n接口有两个子接口:一个是org.hibernate.event.eventsource;另一个是org.hibernate.classic.session。后者是为了兼容以前版本的hibernate的。session的实现类org.hibernate.impl.sessionimpl实现了以上两个接口,如代码清单3-9所示。图3-1 session接口继承关系图代码清单3-9 sessionimpl类实现的接口public final class sessionimpl extends abstractsessionimpl implements eventsource, org.hiber

36、nate.classic.session, jdbccontext.context, lobcreationcontext ;sessionimpl中的保存方法都是采用事件驱动机制,比如:用saveorupdate方法保存一个实体对象,不是直接把实体转化为sql后保存到数据中,而是发布一个saveorupdateevent事件,然后由与之相应的监听器处理。hibernate为每种事件提供了一个默认的监听器,比如与saveorupdateevent事件对应的默认监听器是defaultsaveorupdateeventlistener。当你在配置hibernate时没有给特定事件指定监听器,把会使

37、用hibernate提供的默认监听器。一般都使用默认的事件监听器,除非你有特殊的需求,通过配置hibernate使用自己定义的监听器处理指定的事件。监听器的配置方法详细见第二章。常见的保存方法采用的默认监听器及事件见表3-1。表3-1 常见的保存方法采用的默认监听器及事件一览表方法事件默认监听器监听器父类saveorupdatesaveorupdateeventdefaultsaveorupdateeventlistenerabstractsaveeventlistenersavesaveorupdateeventdefaultsaveeventlistenerdefaultsaveorupd

38、ateeventlistenerupdatesaveorupdateeventdefaultupdateeventlistenerdefaultsaveorupdateeventlistenermergemergeeventdefaultmergeeventlistenerabstractsaveeventlistenerpersistpersisteventdefaultpersisteventlistenerabstractsaveeventlistener事件类是sessionimpl各方法处理的信息载体,穿梭于各方法之间。session操作一个实体的过程一般是:封装数据到事件类中,发布

39、事件到监听器,监听器处理后返回,如果有返回值,就把返回值传给调用者。比如saveorupdateevent有result属性,在监听器处理完后,把返result返回给调用者。每个事件类中的属性各不相同,它们都是根据具体事件而定义的。比如saveorupdateevent类定义如代码清单1-12所示。在hibernate中使用entityentry封装一个实体,记录实体在session中的状态及其它信息。如代码清单3-10所示:代码清单3-10 entityentry中的属性private lockmode lockmode;private status status;private statu

40、s previousstatus;private final serializable id;private object loadedstate;private object deletedstate;private boolean existsindatabase;private object version;private transient entitypersister persister; / for convenience to save some lookupsprivate final entitymode entitymode;private final string en

41、tityname;private transient entitykey cachedentitykey; / cached entitykey (lazy-initialized)private boolean isbeingreplicated;private boolean loadedwithlazypropertiesunfetched; /note: this is not updated when properties are fetched lazily!private final transient object rowid;3.2.1 saveorupdate方法saveo

42、rupdate方法是session接口中的一个重要的方法,用于把实体持久化到数据库中或更新实体。saveorupdate方法兼有save和update方法的功能,这里之所以先分析saveorupdate方法,是因为save和update方法的监听器都是saveorupdate方法对应监听器的子类。saveorupdate在接口session中有两个重载方法,如代码清单3-11所示。我们接下来就是根据hibernate的源代码,从saveorupdate方法一步一步看看实体是如何保存或更新到数据库的。代码中加粗的部分是程序运行的路线。为了简明,省去了部分代码。省略部分用“”代替。代码清单3-11

43、 接口session中的saveorupdate方法定义public void saveorupdate(object object) throws hibernateexception saveorupdate(null, object);public void saveorupdate(string entityname, object obj) throws hibernateexception firesaveorupdate( new saveorupdateevent(entityname, obj, this) ); 事件类代码清单3-12 saveorupdate

44、eventprivate object object;/保存或要更新的对象。private serializable requestedid;/实体对象的idprivate string entityname;/实体名称。实体映像文件中class元素中/entityname指定的值,如果没有指定,将会取/class元素的name值private object entity;private entityentry entry;/实体,在hibernate中描述一个对象的状态等信息private serializable resultid; /实体持久化后的标识id发布事件sessi

45、on实现类sessionimpl中saveorupdate方法定义如代码清单3-13,可以看出saveorupdate方法实现十分简单,只是创建一个saveorupdateevent事件然后,调用firesaveorupdate方法发出事件。对于saveorupdate、save和update方法,hibernate发布的事件类型都是saveorupdateevent。代码清单3-13 saveorupdate方法的实现public void saveorupdate(object object) throws hibernateexception saveorupdate(null, obj

46、ect);public void saveorupdate(string entityname, object obj) throws hibernateexception firesaveorupdate( new saveorupdateevent(entityname, obj, this) );private void firesaveorupdate(saveorupdateevent event) /获得所有的saveorupdateeventlisteners监听器。然后把event发布到各个监听器。saveorupdateeventlistener saveorupdateev

47、entlistener = listeners.getsaveorupdateeventlisteners();for ( int i = 0; i saveorupdateeventlistener.length; i+ ) saveorupdateeventlisteneri.onsaveorupdate(event);从代码清单3-13中,我们可以看出在saveorupdate一个对象时,firesaveorupdate把saveorupdateevent事件发布到所有已注册并实现saveorupdateeventlistener接口的监听器中。该接口十分简单,只有一个抽象方法onsav

48、eorupdate,接收saveorupdateevent事件。hibernate对这个接口给出了几个实现类,在该接口上按f4即可看到该接口的继承关系结构图,如图3-2所示。从图可以看出它有三个实现类defaultsaveorupdateeventlistener、defaultsaveeventlistener、defaultupdateeventlistener。其中defaultsaveeventlistener、defaultupdateeventlistener是defaultsaveorupdateeventlistener的两个子类。其中saveorupdate方法对应的默认监听

49、器是defaultsaveorupdateeventlistener。图3-2 saveupdateeventlistener继承关系图 接收事件接下来我们去其默认监听器defaultsaveorupdateeventlistener中,看看监听器如何把实体保存到数据中的。defaultsaveorupdateeventlistener监听器中的onsaveorupdate方法接收saveorupdateevent事件,是监听器的入口。这正和之前代码清单3-13中的firesaveorupdate方法相呼应。firesaveorupdate方法发布事件,onsaveorupdat

50、e方法接收前者发布的事件。代码清单3-14 onsaveorupdate中的代码片段/初始化event的属性,如果session中存在其代理,从中取得对象。final object entity = source.getpersistencecontext().unproxyandreassociate( object );event.setentity( entity );/根据实体返回实体event.setentry( source.getpersistencecontext().getentry( entity ) );/执行保存方法,并返回事件中对象的idevent.setresult

51、id( performsaveorupdate( event ) );从代码清代3-14中我们可以看到,首先对event进行初始化,然后调用performsaveorupdate方法,最后把结果放入event的resultid中。 处理事件performsaveorupdate方法如代码清单3-15所示,它首先判断实体的状态,然后根据实体的状态分别处理。实体在hibernate中的三种状态:transient瞬时态(或自由态),实例没有与session关联。persistent持久化状态,实例与session关联,并在数据库中有与之对应的记录。detached脱管状态(或者游离态

52、 ),持久化状态的实例被删除或session关闭后就会成为脱管状态。代码清单3-15 performsaveorupdate方法protected serializable performsaveorupdate(saveorupdateevent event) /获得实体的状态int entitystate = getentitystate(event.getentity(),event.getentityname(),event.getentry(),event.getsession();switch ( entitystate ) case detached:/脱管状态entityisd

53、etached( event );return null;case persistent:/持久化状态return entityispersistent( event );default: /瞬时状态或删除状态return entityistransient( event );在更新或保存时,如果一个实体处于持久化状态只需返回其id。entityispersistent代码如代码清单3-16所示。其中对实体作了几次判定,以免发生因实体不是处于持久化状态,而没有保存实体。也就是说连续保存一个实体不会连续执插入数据库的操作。因为处于持久化的实体是与数据库中的记录是同步的。代码清单3-16 处理持久

54、化实体protected serializable entityispersistent(saveorupdateevent event) throws hibernateexception log.trace( ignoring persistent instance );entityentry entityentry = event.getentry();/持久化状态时,实体不能为空if ( entityentry = null ) throw new assertionfailure( entity was transient or detached );else /实体不能处于删除状态if ( entityentry.getstatus() = statu

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论