已阅读5页,还剩8页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
12.2. Hibernate我们将首先从Hibernate3 (/)开始,通过讲解Hibernate在Spring环境中的使用来阐述Spring框架对于O/R Mapping工具的整合方式。本章节将涉及到许多细节问题,并向你展示各种不同的DAO实现方式和事务划分。这其中的绝大多数模式能够被Spring支持的其他O/R Mapping工具所使用。这一章节的其他部分将为你讲述其他的O/R Mapping技术,并给出一些简短的例子。注意:Spring2.5版本需要Hibernate3.1或更高版本,不再提供对Hibernate2.1与Hibernate3.0版本的支持。12.2.1. 资源管理典型的业务程序经常会被重复的资源管理代码搞得混乱。很多项目都试图创建自己的方案来解决这个问题,有时会为了编程方便而牺牲恰当的错误处理。对于恰当的资源管理,Spring提倡一种瞩目而又简洁的解决方案:使用模板化的IoC,诸如基础构建类、回调接口以及使用AOP拦截器。基础构建类负责恰当的资源处理,以及将特定的异常代码转换为unchecked exception体系。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下会与application Context整合的更好。在典型的Spring应用程序中,很多重要的对象都是JavaBeans:数据访问template、数据访问对象(使用template)、事务管理器、业务逻辑对象(使用数据访问对象和事务管理器)、web视图解析器、web控制器(使用业务服务)等等。12.2.2. 在Spring容器中创建 SessionFactory为了避免硬编码的资源查找与应用程序对象紧密耦合,Spring允许你在Spring容器中以bean的方式定义诸如JDBC DataSource或者Hibernate SessionFactory 的数据访问资源。任何需要进行资源访问的应用程序对象只需要持有这些事先定义好的实例的引用(DAO定义在下一章节介绍),下面的代码演示如何创建一个JDBC DataSource 和Hibernate SessionFactory product.hbm.xml hibernate.dialect=org.hibernate.dialect.HSQLDialect 将一个本地定义的,如Jakarta Commons DBCP的 BasicDataSource 切换为一个JNDI定位的DataSource(通常由应用程序服务器管理),仅仅需要改变配置: 通过使用Spring的 JndiObjectFactoryBean 来暴露和获,你也可以访问一个JNDI定位的Hibernate SessionFactory。 当然,如果在EJB上下文之外,这是不必要的。12.2.3. The HibernateTemplate对于特定的数据访问对象或业务对象的方法,基本的模板编程模型看起来像下面所示的代码那样。 对于这些外部对象来说,没有任何实现特定接口的约束,仅仅要求提供一个Hibernate SessionFactory。 它可以从任何地方得到,不过比较适宜的方法是从Spring的IoC容器中取得bean的引用:通过简单的 setSessionFactory(.) 这个bean的setter方法。 下面的代码片段展示了在Spring容器中一个DAO的定义,它引用了上面定义的 SessionFactory,同时展示了一个DAO方法的具体实现。 public class ProductDaoImpl implements ProductDao private HibernateTemplate hibernateTemplate; public void setSessionFactory(SessionFactory sessionFactory) this.hibernateTemplate = new HibernateTemplate(sessionFactory); public Collection loadProductsByCategory(String category) throws DataAccessException return this.hibernateTemplate.find(from test.Product product where product.category=?, category); 除了很多类似上例中易用的方法外,HibernateTemplate类提供了大量方法对应Hibernate Session接口中暴露的方法。当你需要使用的Session方法没有在HibernateTemplate中提供时,可以通过下面提供的基于回调的方案来实现。public class ProductDaoImpl implements ProductDao private HibernateTemplate hibernateTemplate; public void setSessionFactory(SessionFactory sessionFactory) this.hibernateTemplate = new HibernateTemplate(sessionFactory); public Collection loadProductsByCategory(final String category) throws DataAccessException return this.hibernateTemplate.execute(new HibernateCallback() public Object doInHibernate(Session session) Criteria criteria = session.createCriteria(Product.class); criteria.add(Expression.eq(category, category); criteria.setMaxResults(6); return criteria.list(); ; 一个回调实现能够有效地在任何Hibernate数据访问中使用。HibernateTemplate 会确保当前Hibernate的 Session 实例的正确打开和关闭,并直接参与到事务管理中去。 Template实例不仅是线程安全的,同时它也是可重用的。因而他们可以作为外部对象的实例变量而被持有。对于那些简单的诸如find、load、saveOrUpdate或者delete操作的调用,HibernateTemplate 提供可选择的快捷函数来替换这种回调的实现。 不仅如此,Spring还提供了一个简便的 HibernateDaoSupport 基类,这个类提供了 setSessionFactory(.) 方法来接受一个 SessionFactory 对象,同时提供了 getSessionFactory() 和 getHibernateTemplate() 方法给子类使用。 综合了这些,对于那些典型的业务需求,就有了一个非常简单的DAO实现:public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao public Collection loadProductsByCategory(String category) throws DataAccessException return this.getHibernateTemplate().find( from test.Product product where product.category=?, category); 12.2.4. 不使用回调的基于Spring的DAO实现作为不使用Spring的 HibernateTemplate 来实现DAO的替代解决方案,你依然可以用传统的编程风格来编写你的数据访问代码。 无需将你的Hibernate访问代码包装在一个回调中,只需符合Spring的通用的 DataAccessException 异常体系。 HibernateDaoSupport 基类提供了访问与当前事务绑定的 Session 对象的函数,因而能保证在这种情况下异常的正确转化。 类似的函数同样可以在 SessionFactoryUtils 类中找到,但他们以静态方法的形式出现。 值得注意的是,通常将 false 作为参数值(表示是否允许创建)传递给 getSession(.) 方法进行调用。 此时,整个调用将在同一个事务内完成(它的整个生命周期由事务控制,避免了关闭返回的 Session 的需要)。public class HibernateProductDao extends HibernateDaoSupport implements ProductDao public Collection loadProductsByCategory(String category) throws DataAccessException, MyException Session session = getSession(false); try Query query = session.createQuery(from test.Product product where product.category=?); query.setString(0, category); List result = query.list(); if (result = null) throw new MyException(No search results.); return result; catch (HibernateException ex) throw convertHibernateAccessException(ex); 这种直接使用Hibernate访问代码的好处在于它允许你在数据访问代码中抛出 任何 checked exception,而 HibernateTemplate 却受限于回调中的unchecked exception。 注意,你通常可以将这些应用程序的异常处理推迟到回调函数之后,这样,你依然可以正常使用 HibernateTemplate。 一般来说,HibernateTemplate 类所提供的许多方法在许多情况下看上去更简单和便捷。12.2.5. 基于Hibernate3的原生API实现DAOHibernate3 引入了一个新的特性:“带上下文环境的Session”。 这一特性使得Hibernate自身具备了每个事务绑定当前 Session 对象的功能。 这与Spring中每个Hibernate的 Session 与事务同步的功能大致相同。一个相应的基于原生的Hibernate API的DAO实现正如下例所示:public class ProductDaoImpl implements ProductDao private SessionFactory sessionFactory; public void setSessionFactory(SessionFactory sessionFactory) this.sessionFactory = sessionFactory; public Collection loadProductsByCategory(String category) return this.sessionFactory.getCurrentSession() .createQuery(from test.Product product where product.category=?) .setParameter(0, category) .list(); 这种风格与你在Hibernate文档和示例中见到的非常类似,除了DAO实现类中持有了一个 SessionFactory 的实例变量。 我们强烈推荐这种基于实例变量的DAO构建方式,而不是使用那种过去由Hibernate的示例程序中提到的 静态的 HibernateUtil 类。 (通常来说,不要在静态变量中保存任何资源信息除非 确实 有这个必要)。上述DAO遵循依赖注入模式:它如同使用Spring的 HibernateTemplate 进行编程那样,适合在Spring IoC容器中进行配置。 当然,这样的DAO还可以建立在一个普通的Java类中(诸如在Unit Test中): 仅仅需要初始化这个类, 调用 setSessionFactory(.) 方法设置你所期望的工厂资源。 以Spring的bean的定义方式,它看上去就像这样: 这种DAO访问方式的主要优势在于它仅仅依赖于Hibernate API本身而无需引入任何Spring的类。 从无入侵性的角度来看,这一点非常吸引人。对于Hibernate开发人员来说也无疑更加自然。然而,这样的DAO访问方式会抛出原生 HibernateException (这是一个无需声明或捕获的unchecked exception), 这意味着,DAO的调用者只能以致命的错误来处理这些异常,除非完全依赖Hibernate自身的异常体系。 因而,除非你将DAO的调用者绑定到具体的实现策略上去,否则你将无法捕获特定的异常原因,诸如乐观锁异常。 这种折中平衡或许可以被接受,如果你的应用完全基于Hibernate或者无需进行特殊的异常处理。幸运的是,Spring的 LocalSessionFactoryBean 可以在任何Spring的事务管理策略下, 提供对Hibernate的 SessionFactory.getCurrentSession() 方法的支持,它将返回当前受Spring事务管理(甚至是 HibernateTransactionManager 管理的)的 Session 对象。 当然,该函数的标准行为依然有效:返回当前与正在进行的JTA事务(无论是Spring的 JtaTransactionManager、EJB CMT或者普通的JTA)绑定的 Session 对象。总体来说,DAO可以基于Hibernate3的原生API实现,同时,它依旧需要能够参与到Spring的事务管理中。12.2.6. 编程式的事务划分我们可以在这些低层次的数据访问服务之上的应用程序进行更高层次的事务划分,从而让事务能够横跨多个操作。 这里对于相关的业务逻辑对象同样没有实现接口的限制,它只需要一个Spring的 PlatformTransactionManager。 同SessionFactory一样,它可以来自任何地方,但是最好是一个经由 setTransactionManager(.) 方法注入的bean的引用,正如使用 setProductDao 方法来设置 productDAO 一样。 下面演示了在Spring的application context中定义一个事务管理器和一个业务对象,以及具体的业务方法实现: public class ProductServiceImpl implements ProductService private TransactionTemplate transactionTemplate; private ProductDao productDao; public void setTransactionManager(PlatformTransactionManager transactionManager) this.transactionTemplate = new TransactionTemplate(transactionManager); public void setProductDao(ProductDao productDao) ductDao = productDao; public void increasePriceOfAllProductsInCategory(final String category) this.transactionTemplate.execute(new TransactionCallbackWithoutResult() public void doInTransactionWithoutResult(TransactionStatus status) List productsToChange = ductDao.loadProductsByCategory(category); / do the price increase. ); 12.2.7. 声明式的事务划分作为可选方案,我们可以使用Spring声明式的事务支持。声明式的事务支持通过配置Spring容器中的AOP Transaction Interceptor来替换事务划分的硬编码。 这将使你可以从每个业务方法中重复的事务划分代码中解放出来,真正专注于为你的应用添加有价值的业务逻辑代码。此外,类似传播行为和隔离级别等事务语义能够在配置文件中改变,而不会影响具体的业务对象实现。 myTxInterceptor public class ProductServiceImpl implements ProductService private ProductDao productDao; public void setProductDao(ProductDao productDao) ductDao = productDao; / notice the absence of transaction demarcation code in this method / Springs declarative transaction infrastructure will be demarcating transactions on your behalf public void increasePriceOfAllProductsInCategory(final String category) List productsToChange = ductDao.loadProductsByCategory(category); / . Spring的 TransactionInterceptor 允许任何应用程序的checked exception在回调代码中抛出,而 TransactionTemplate 在回调中则严格要求被封装成unchecked exception。 TransactionTemplate 会在一个unchecked exception抛出时,或者当事务被应用程序通过 TransactionStatus 标记为rollback-only时触发一个数据库回滚操作。 TransactionInterceptor 默认进行同样的操作,但是它允许对每个方法配置自己的rollback策略。下面列出的高级别的声明式的事务管理方案并没有使用 ProxyFactoryBean,它将使那些大量的业务对象需要被纳入到事务管理中时的配置变得非常简单。注意在你打算继续阅读下一部分之前,我们 强烈 推荐你想去阅读 第 9.5 节 “声明式事务管理” 这一章节。 12.2.8. 事务管理策略TransactionTemplate 和 TransactionInterceptor 都将真正的事务处理委托给一个 PlatformTransactionManager 实例来处理。在Hibernate应用中,它可以是一个 HibernateTransactionManager(对于单独一个的Hibernate SessionFactory 使用一个 ThreadLocal 的 Session)或一个 JtaTransactionManager(代理给容器的JTA子系统)。你甚至可以使用自定义的 PlatformTransactionManager 的实现。因而,在你的应用碰到了特定的分布式事务的部署需求时(类似将原来的Hibernate事务管理转变为JTA),仅仅需要改变配置而已:简单将Hibernate的事务管理器替换成JTA事务实现。任何的事务划分和数据访问的代码都无需因此而改变,因为他们仅仅使用了通用的事务管理API。对于横跨多个Hibernate SessionFacotry的分布式事务,只需简单地将 JtaTransactionManager 同多个 LocalSessionFactoryBean 的定义结合起来作为事务策略。你的每一个DAO通过bean属性得到各自的 SessionFactory 引用。如果所有的底层JDBC数据源都是支持事务的容器,那么只要业务对象使用了 JtaTransactionManager 作为事务策略,它就可以横跨多个DAO和多个session factories来划分事务,而不需要做任何特殊处理。 product.hbm.xml hibernate.dialect=org.hibernate.dialect.MySQLDialect hibernate.show_sql=true inventory.hbm.xml hibernate.dialect=org.hibernate.dialect.OracleDialect PROPAGATION_REQUIRED PROPAGATION_REQUIRES_NEW PROPAGATION_SUPPORTS,readOnly HibernateTransactionManager 和 JtaTransactionManager 都允许恰当的JVM级别的Hibernate缓存处理,而无需使用与容器相关的事务管理器或JCA连接器。(只要不是由EJB发起的事务)对于特定的 DataSource,HibernateTransactionManager 能够为普通的JDBC访问代码提供Hibernate所使用的 Connection。 这一功能允许你可以完全混和使用Hibernate/JDBC进行数据访问而无需依赖JTA在高层次代码中进行事务划分,只要你依然访问的是同一个数据库! HibernateTransactionManager 能够自动地将Hibernate事务暴露为JDBC事务,如果你通过设置 DataSource来建立SessionFactory 对象(通过设置 LocalSessionFactoryBean 中的“dataSource”属性)。 另外一种配置方法是通过设置 HibernateTransactionManager 的“dataSource”属性,明确指定事务需要暴露的 DataSource。12.2.9. 容器资源 vs 本地资源Spring的资源管理允许你简单地在一个JNDI的 SessionFactory 和一个本地的 SessionFactory 之间切换而无需更改任何一行应用程序代码。 把资源定义放在容器中还是放在应用程序本地中主要是由使用的事务策略决定的。与Spring定义的本地 SessionFactory 相比,一个手工注册的JNDI SessionFactory 并没有体现出多大的优势。 通过Hibernate的JCA连接器来部署一个 SessionFactory 提供了能使之参与到J2EE服务器管理架构的增值服务,不过除此之外也并没有增加实际的价值。Spring对事务管理的支持有一个非常重要的好处:它不依赖于任何容器。使用非JTA的任何其他事务策略的配置,程序也能在独立的测试环境下正常工作。 尤其对于那些典型的单数据库事务情况下,这将是一个非常轻量级而又强大的JTA替代方案。当你使用一个本地的EJB SLSB来驱动事务时,即时你可能只访问一个数据库而且仅仅通过CMT使用SLSB的声明性事务,你仍然要依赖于EJB容器和JTA。 使用编程式JTA替换方案依然需要J2EE环境,JTA不仅对于JTA本身,还对于JNDI的 DataSource 实例引入了容器依赖。 对于非Spring环境的JTA驱动的Hibernate事务,你必须使用Hibernate JCA连接器或者额外的Hibernate事务代码及 TransactionManagerLookup 配置,来恰当地处理JVM级别的缓存。Spring驱动的事务管理与本地定义的 SessionFactory 能够工作得非常好,就像使用本地的JDBC DataSource 一样,当然前提必须是访问单个数据库。 因此当你真正面对分布式事务的需求时,可以马上回到Spring的JTA事务。必须要注意,一个JCA连接器需要特定容器的部署步骤,而且首先容器要支持JCA。 这要比使用本地资源定义和Spring驱动事务来部署一个简单的Web应用麻烦得多。而且你通常需要特定企业版本的容器,但是像类似WebLogic的Express版本并不提供JCA。 一个仅使用本地资源并且针对一个数据库的事务操作的Spring应用将可以在任何一种J2EE的Web容器中工作(不需要JTA、JCA或者EJB),比如Tomcat、Resin甚至普通的Jetty。 除此之外,这样的中间层可以在桌面应用或测试用例中被简单地重用。考虑一下所有的情况:如果你不使用EJB,坚持使用本地 SessionFactory 以及Spring的 HibernateTransactionManager 或者 JtaTransactionManager, 你将获得包括适当的JVM级别上的缓存以及分布式事务在内的所有好处,而不会有任何容器部署的麻烦。通过JCA连接器的Hibernate的 SessionFactory 的JNDI注册仅仅在EJB中使用会带来好处。12.2.10. 在应用服务器中使用Hibernate的注意事项在一些具有非常严格的 XADataSource 实现的JTA环境中(目前来说只是WebL
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026银行常识面试题及答案
- 2026银行矛盾面试题目及答案
- 2026应急类面试题目及答案
- 2026澄清类的面试题及答案
- (2026版)关于我市发展循环经济的调研报告
- (2026年)初中道德与法治学期教学工作总结
- 度减盐活动总结
- 高三语文一轮复习教学设计:补写句子语境建构与逻辑推演
- 初中信息科技八年级全册 教学设计 物联网时代的感知与实践
- 九年级语文《我爱这土地》情境化教学设计
- 《汉江临泛》课件
- 摩托置换合同协议书模板
- DBJT15-63-2019 预应力混凝土管桩啮合式机械连接技术规程
- 浦东新区2024-2025学年六年级上学期期中考试数学试卷及答案(上海新教材)
- 红山文化艺术中心设计规划方案
- 中职高教版(2023)语文职业模块-第五单元:走近大国工匠(二)学习工匠事迹 领略工匠风采【课件】
- 艾媒咨询|赵一鸣零食店消费行为洞察及行业趋势报告2024
- QGW17991-2025《电力安全工作规程变电部分》
- JB∕T 7946.4-2017 铸造铝合金金相 第4部分:铸造铝铜合金晶粒度
- GA 2093-2023公安机关警务辅助人员工作证内卡技术规范
- 服务采购项目-大学生“云成长”一体化大数据招投标书范本
评论
0/150
提交评论