使用ORM访问数据库Hibernate.docx
- 文档编号:3506771
- 上传时间:2023-05-06
- 格式:DOCX
- 页数:20
- 大小:25.85KB
使用ORM访问数据库Hibernate.docx
《使用ORM访问数据库Hibernate.docx》由会员分享,可在线阅读,更多相关《使用ORM访问数据库Hibernate.docx(20页珍藏版)》请在冰点文库上搜索。
使用ORM访问数据库Hibernate
12.2.Hibernate
我们将首先从Hibernate3(http:
//www.hibernate.org/)开始,通过讲解Hibernate在Spring环境中的使用来阐述Spring框架对于O/RMapping工具的整合方式。
本章节将涉及到许多细节问题,并向你展示各种不同的DAO实现方式和事务划分。
这其中的绝大多数模式能够被Spring支持的其他O/RMapping工具所使用。
这一章节的其他部分将为你讲述其他的O/RMapping技术,并给出一些简短的例子。
注意:
Spring2.5版本需要Hibernate3.1或更高版本,不再提供对Hibernate2.1与Hibernate3.0版本的支持。
12.2.1.资源管理
典型的业务程序经常会被重复的资源管理代码搞得混乱。
很多项目都试图创建自己的方案来解决这个问题,有时会为了编程方便而牺牲恰当的错误处理。
对于恰当的资源管理,Spring提倡一种瞩目而又简洁的解决方案:
使用模板化的IoC,诸如基础构建类、回调接口以及使用AOP拦截器。
基础构建类负责恰当的资源处理,以及将特定的异常代码转换为uncheckedexception体系。
Spring引进了DAO异常体系,可适用于任何数据访问策略。
对于直接使用JDBC的情况,前面章节提到的JdbcTemplate类负责处理connection,并正确地把SQLException转换为DataAccessException体系,包括将与数据库相关的SQL错误代码变成有意义的异常类。
Spring同时通过它们各自的事务管理器支持JTA和JDBC事务。
Spring同样也提供了对Hibernate和JDO的支持,包括HibernateTemplate/JdoTemplate类似于JdbcTemplate,HibernateInterceptor/JdoInterceptor以及一个Hibernate/JDO事务管理器。
这样做的主要目的是为了能够清晰地划分应用程序层次而不管使用何种数据访问和事务管理技术,从而降低各个应用程序对象之间的耦合。
业务逻辑不再依赖于特定的数据访问与事务策略;不再有硬编码的资源查找、不再有难以替换的singletons、不再有用户自定义的服务注册。
Spring提供了一个简单且稳固的方案使得各种应用逻辑对象连接在一起,使这些对象可重用,并尽可能不依赖容器。
所有的数据访问技术都能独立使用,但是他们在Spring提供的基于XML配置且无需依赖Spring的普通JavaBean下会与applicationContext整合的更好。
在典型的Spring应用程序中,很多重要的对象都是JavaBeans:
数据访问template、数据访问对象(使用template)、事务管理器、业务逻辑对象(使用数据访问对象和事务管理器)、web视图解析器、web控制器(使用业务服务)等等。
12.2.2.在Spring容器中创建SessionFactory
为了避免硬编码的资源查找与应用程序对象紧密耦合,Spring允许你在Spring容器中以bean的方式定义诸如JDBCDataSource或者HibernateSessionFactory的数据访问资源。
任何需要进行资源访问的应用程序对象只需要持有这些事先定义好的实例的引用(DAO定义在下一章节介绍),下面的代码演示如何创建一个JDBCDataSource和HibernateSessionFactory
hsqldb: hsql: //localhost: 9001"/> hibernate.dialect=org.hibernate.dialect.HSQLDialect 将一个本地定义的,如JakartaCommonsDBCP的BasicDataSource切换为一个JNDI定位的DataSource(通常由应用程序服务器管理),仅仅需要改变配置: comp/env/jdbc/myds"/> 通过使用Spring的JndiObjectFactoryBean来暴露和获,你也可以访问一个JNDI定位的HibernateSessionFactory。 当然,如果在EJB上下文之外,这是不必要的。 12.2.3.TheHibernateTemplate 对于特定的数据访问对象或业务对象的方法,基本的模板编程模型看起来像下面所示的代码那样。 对于这些外部对象来说,没有任何实现特定接口的约束,仅仅要求提供一个HibernateSessionFactory。 它可以从任何地方得到,不过比较适宜的方法是从Spring的IoC容器中取得bean的引用: 通过简单的setSessionFactory(..)这个bean的setter方法。 下面的代码片段展示了在Spring容器中一个DAO的定义,它引用了上面定义的SessionFactory,同时展示了一个DAO方法的具体实现。 publicclassProductDaoImplimplementsProductDao{ privateHibernateTemplatehibernateTemplate; publicvoidsetSessionFactory(SessionFactorysessionFactory){ this.hibernateTemplate=newHibernateTemplate(sessionFactory); } publicCollectionloadProductsByCategory(Stringcategory)throwsDataAccessException{ returnthis.hibernateTemplate.find("fromtest.Productproductwhereproduct.category=? ",category); } } 除了很多类似上例中易用的方法外,HibernateTemplate类提供了大量方法对应HibernateSession接口中暴露的方法。 当你需要使用的Session方法没有在HibernateTemplate中提供时,可以通过下面提供的基于回调的方案来实现。 publicclassProductDaoImplimplementsProductDao{ privateHibernateTemplatehibernateTemplate; publicvoidsetSessionFactory(SessionFactorysessionFactory){ this.hibernateTemplate=newHibernateTemplate(sessionFactory); } publicCollectionloadProductsByCategory(finalStringcategory)throwsDataAccessException{ returnthis.hibernateTemplate.execute(newHibernateCallback(){ publicObjectdoInHibernate(Sessionsession){ Criteriacriteria=session.createCriteria(Product.class); criteria.add(Expression.eq("category",category)); criteria.setMaxResults(6); returncriteria.list(); } }; } } 一个回调实现能够有效地在任何Hibernate数据访问中使用。 HibernateTemplate会确保当前Hibernate的Session实例的正确打开和关闭,并直接参与到事务管理中去。 Template实例不仅是线程安全的,同时它也是可重用的。 因而他们可以作为外部对象的实例变量而被持有。 对于那些简单的诸如find、load、saveOrUpdate或者delete操作的调用,HibernateTemplate提供可选择的快捷函数来替换这种回调的实现。 不仅如此,Spring还提供了一个简便的HibernateDaoSupport基类,这个类提供了setSessionFactory(..)方法来接受一个SessionFactory对象,同时提供了getSessionFactory()和getHibernateTemplate()方法给子类使用。 综合了这些,对于那些典型的业务需求,就有了一个非常简单的DAO实现: publicclassProductDaoImplextendsHibernateDaoSupportimplementsProductDao{ publicCollectionloadProductsByCategory(Stringcategory)throwsDataAccessException{ returnthis.getHibernateTemplate().find( "fromtest.Productproductwhereproduct.category=? ",category); } } 12.2.4.不使用回调的基于Spring的DAO实现 作为不使用Spring的HibernateTemplate来实现DAO的替代解决方案,你依然可以用传统的编程风格来编写你的数据访问代码。 无需将你的Hibernate访问代码包装在一个回调中,只需符合Spring的通用的DataAccessException异常体系。 HibernateDaoSupport基类提供了访问与当前事务绑定的Session对象的函数,因而能保证在这种情况下异常的正确转化。 类似的函数同样可以在SessionFactoryUtils类中找到,但他们以静态方法的形式出现。 值得注意的是,通常将'false'作为参数值(表示是否允许创建)传递给getSession(..)方法进行调用。 此时,整个调用将在同一个事务内完成(它的整个生命周期由事务控制,避免了关闭返回的Session的需要)。 publicclassHibernateProductDaoextendsHibernateDaoSupportimplementsProductDao{ publicCollectionloadProductsByCategory(Stringcategory)throwsDataAccessException,MyException{ Sessionsession=getSession(false); try{ Queryquery=session.createQuery("fromtest.Productproductwhereproduct.category=? "); query.setString(0,category); Listresult=query.list(); if(result==null){ thrownewMyException("Nosearchresults."); } returnresult; } catch(HibernateExceptionex){ throwconvertHibernateAccessException(ex); } } } 这种直接使用Hibernate访问代码的好处在于它允许你在数据访问代码中抛出任何checkedexception,而HibernateTemplate却受限于回调中的uncheckedexception。 注意,你通常可以将这些应用程序的异常处理推迟到回调函数之后,这样,你依然可以正常使用HibernateTemplate。 一般来说,HibernateTemplate类所提供的许多方法在许多情况下看上去更简单和便捷。 12.2.5.基于Hibernate3的原生API实现DAO Hibernate3引入了一个新的特性: “带上下文环境的Session”。 这一特性使得Hibernate自身具备了每个事务绑定当前Session对象的功能。 这与Spring中每个Hibernate的Session与事务同步的功能大致相同。 一个相应的基于原生的HibernateAPI的DAO实现正如下例所示: publicclassProductDaoImplimplementsProductDao{ privateSessionFactorysessionFactory; publicvoidsetSessionFactory(SessionFactorysessionFactory){ this.sessionFactory=sessionFactory; } publicCollectionloadProductsByCategory(Stringcategory){ returnthis.sessionFactory.getCurrentSession() .createQuery("fromtest.Productproductwhereproduct.category=? ") .setParameter(0,category) .list(); } } 这种风格与你在Hibernate文档和示例中见到的非常类似,除了DAO实现类中持有了一个SessionFactory的实例变量。 我们强烈推荐这种基于实例变量的DAO构建方式,而不是使用那种过去由Hibernate的示例程序中提到的静态的HibernateUtil类。 (通常来说,不要在静态变量中保存任何资源信息除非确实有这个必要)。 上述DAO遵循依赖注入模式: 它如同使用Spring的HibernateTemplate进行编程那样,适合在SpringIoC容器中进行配置。 当然,这样的DAO还可以建立在一个普通的Java类中(诸如在UnitTest中): 仅仅需要初始化这个类,调用setSessionFactory(..)方法设置你所期望的工厂资源。 以Spring的bean的定义方式,它看上去就像这样: 这种DAO访问方式的主要优势在于它仅仅依赖于HibernateAPI本身而无需引入任何Spring的类。 从无入侵性的角度来看,这一点非常吸引人。 对于Hibernate开发人员来说也无疑更加自然。 然而,这样的DAO访问方式会抛出原生HibernateException(这是一个无需声明或捕获的uncheckedexception),这意味着,DAO的调用者只能以致命的错误来处理这些异常,除非完全依赖Hibernate自身的异常体系。 因而,除非你将DAO的调用者绑定到具体的实现策略上去,否则你将无法捕获特定的异常原因,诸如乐观锁异常。 这种折中平衡或许可以被接受,如果你的应用完全基于Hibernate或者无需进行特殊的异常处理。 幸运的是,Spring的LocalSessionFactoryBean可以在任何Spring的事务管理策略下,提供对Hibernate的SessionFactory.getCurrentSession()方法的支持,它将返回当前受Spring事务管理(甚至是HibernateTransactionManager管理的)的Session对象。 当然,该函数的标准行为依然有效: 返回当前与正在进行的JTA事务(无论是Spring的JtaTransactionManager、EJBCMT或者普通的JTA)绑定的Session对象。 总体来说,DAO可以基于Hibernate3的原生API实现,同时,它依旧需要能够参与到Spring的事务管理中。 12.2.6.编程式的事务划分 我们可以在这些低层次的数据访问服务之上的应用程序进行更高层次的事务划分,从而让事务能够横跨多个操作。 这里对于相关的业务逻辑对象同样没有实现接口的限制,它只需要一个Spring的PlatformTransactionManager。 同SessionFactory一样,它可以来自任何地方,但是最好是一个经由setTransactionManager(..)方法注入的bean的引用,正如使用setProductDao方法来设置productDAO一样。 下面演示了在Spring的applicationcontext中定义一个事务管理器和一个业务对象,以及具体的业务方法实现: publicclassProductServiceImplimplementsProductService{ privateTransactionTemplatetransactionTemplate; privateProductDaoproductDao; publicvoidsetTransactionManager(PlatformTransactionManagertransactionManager){ this.transactionTemplate=newTransactionTemplate(transactionManager); } publicvoidsetProductDao(ProductDaoproductDao){ this.productDao=productDao; } publicvoidincreasePriceOfAllProductsInCategory(finalStringcategory){ this.transactionTemplate.execute(newTransactionCallbackWithoutResult(){ publicvoiddoInTransactionWithoutResult(TransactionStatusstatus){ ListproductsToChange=this.productDao.loadProductsByCategory(category); //dothepriceincrease... } } ); } } 12.2.7.声明式的事务划分 作为可选方案,我们可以使用Spring声明式的事务支持。 声明式的事务支持通过配置Spring容器中的AOPTransactionInterceptor来替换事务划分的硬编码。 这将使你可以从每个业务方法中重复的事务划分代码中解放出来,真正专注于为你的应用添加有价值的业务逻辑代码。 此外,类似传播行为和隔离级别等事务语义能够在配置文件中改变,而不会影响具体的业务对象实现。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 使用 ORM 访问 数据库 Hibernate