Hibernate
Spring 框架提供了对 Hibernate、JDO 和 iBATIS SQL Maps 的集成支持。Spring 对 Hibernate 的支持是第一级的,整合了许多 IOC 的方便特性,解决了许多典型的 Hibernate 集成问题。框架对 Hibernate 的支持符合 Spring 通用的事务和数据访问对象(DAO)异常层次结构。
Spring 为使用选择的 OR 映射层来创建数据访问应用程序提供了支持。因为所有东西都设计成一组可重用 JavaBean,所以不管选择什么技术,都能以库的格式访问大多数 Spring 的 OR 映射支持。 ApplicationContext
或 BeanFactory
内部的 OR 映射的好处是简化了配置和部署。
Hibernate 是 Java 平台上一个功能全面的、开源的 OR 映射框架。Hibernate 支持开发符合常规 Java 理念的持久性类 —— 包括关联、继承、多态、复合以及 Java 集合框架。Hibernate 查询语言(HQL)被设计成 SQL 的一个微型面向对象扩展,它是对象和关系世界之间的桥梁。Hibernate 也支持用原始 SQL 或基于 Java 的标准和示例查询表达查询。Hibernate 使用 XML(*.hbm.xml) 文件把 Java 类映射到表,把 JavaBean 属性映射到数据库表。
通过 JDBC 技术,支持所有的 SQL 数据库管理系统。Hibernate 与所有流行的 J2EE 应用程序服务器和 Web 容器都很好地集成。
实际示例
一个银行应用程序示例可以让您自己看到 Spring AOP 和 Hibernate 一起工作有多么好。银行帐户用例允许用户 (Customer
) 在一个事务中打开一个或多个银行帐户。用户可以申请多个银行帐户,可以选择是支票帐户类型或者是储蓄帐户类型。
应用程序数据库(Cloudscape™)容纳所有客户和帐户信息。在这个例子中,假设在 Customer
和 Account
类之间存在 1:N 的关联。在实际生活场景中,关联可能需要按 m:n 建模,才能支持联合帐户。
由于用户必须可以在一个事务中申请多个帐户,所以首先要为数据库交互实现一个 DOA 模式。然后要设置 Spring AOP 的TransactionProxyFactoryBean
,让它拦截方法调用并声明性地把事务上下文应用到 DOA。
Hibernate 实践
在 Spring 框架中,像 JDBC DataSource
或 Hibernate SessionFactory
这样的资源,在应用程序上下文中可以用 bean 实现。需要访问资源的应用程序对象只需通过 bean 引用得到这类预先定义好的实例的引用即可(这方面的更多内容在 下一节中)。在清单 1 中,可以看到示例银行应用程序的一段摘录:XML 应用程序上下文定义显示了如何设置 JDBC DataSource
,并在上面放一个 Hibernate SessionFactory
。
清单 1. JDBC DataSource 和 HibernateSessionFactory 连接
<!-- DataSource Property --> <bean id="exampleDataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>org.apache.derby.jdbc.EmbeddedDriver</value> </property> <property name="url"> <value>jdbc:derby:springexample;create=true</value> </property> </bean> <!-- Database Property --> <bean id="exampleHibernateProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="properties"> <props> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.dialect">net.sf.hibernate.dialect.DerbyDialect</prop> <prop key="hibernate.query.substitutions">true 'T', false 'F'</prop> <prop key="hibernate.show_sql">false</prop> <prop key="hibernate.c3p0.minPoolSize">5</prop> <prop key="hibernate.c3p0.maxPoolSize">20</prop> <prop key="hibernate.c3p0.timeout">600</prop> <prop key="hibernate.c3p0.max_statement">50</prop> <prop key="hibernate.c3p0.testConnectionOnCheckout">false</prop> </props> </property> </bean> <!-- Hibernate SessionFactory --> <bean id="exampleSessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"> <property name="dataSource"> <ref local="exampleDataSource"/> </property> <property name="hibernateProperties"> <ref bean="exampleHibernateProperties" /> </property> <!-- OR mapping files. --> <property name="mappingResources"> <list> <value>Customer.hbm.xml</value> <value>Account.hbm.xml</value> </list> </property> </bean>
清单 1 显示了如何为示例应用程序数据库(是 Cloudscape)配置数据源 bean (exampleDataSource
)。exampleDatasource
被连接到 Spring Hibernate 的 SessionFactory
。请注意 *.hbm.xml 指定了示例应用程序的 OR 映射文件。
数据源和会话工厂设置好之后,下一步就是在 DAO 中连接,在 CustomerDAOImpl
示例中,要使用 SessionFactory
。接下来,插入 Spring 的 TransactionProxyFactoryBean
,它会拦截对应用程序的 CustomerDAOImpl
对象的方法调用,并声明性地在它上面应用事务。
在 清单 2 的这个示例中,CustomerDAOImpl
类的 addCustomer
方法是作为事务的一部分执行的,有一个事务属性PROPAGATION_REQUIRED
。这个属性等价于 EJB 容器的 TX_REQUIRED
。如果想让这个方法一直在事务中运行,可以使用PROPAGATION_REQUIRED
。如果事务已经在运行,那么 bean 方法会加入事务,否则 Spring 的轻量级事务管理器会启动一个事务。如果想在调用组件服务时总是启动新事务,可以使用 PROPAGATION_REQUIRES_NEW
属性。
应用程序的连接完成之后,现在来进一步查看源代码。
分析这个!
如果以前没这么做过,那么请 下载这篇文章的源代码。把源 zip 文件释放到计算机中的任何位置上,例如 c:\。会创建一个叫作SpringProjectPart2 的文件夹。src\spring 文件夹包含示例应用程序的 Hibernate 映射文件和 Spring 配置文件。src\springexample\hibernate 文件包含应用程序的源代码。
在这里会发现两个类,即 Customer
和 Account
,它们用 Hibernate 映射文件映射到两个表。Customer
类代表客户信息,Account
代表客户的帐户信息。正如前面提到的,我把这两个类按照 1: N 关系进行建模,即一个 Customer
可以拥有多个 Account
。清单 3 显示了Customer
对象的 Hibernate 映射文件。
清单 3. Customer 对象的 Hibernate 映射文件
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="springexample.hibernate.Customer" table="TBL_CUSTOMER" dynamic-update="false" dynamic-insert="false"> <id name="id" column="CUSTOMER_ID" type="java.lang.Long" unsaved-value="-1" > <generator class="native"> </generator> </id> <set name ="accounts" inverse = "true" cascade="all-delete-orphan"> <key column ="CUSTOMER_ID"/> <one-to-many class="springexample.hibernate.Account"/> </set> <property name="email" type="string" update="false" insert="true" column="CUSTOMER_EMAIL" length="82" not-null="true" /> <property name="password" type="string" update="false" insert="true" column="CUSTOMER_PASSWORD" length="10" not-null="true" /> <property name="userId" type="string" update="false" insert="true" column="CUSTOMER_USERID" length="12" not-null="true" unique="true" /> <property name="firstName" type="string" update="false" insert="true" column="CUSTOMER_FIRSTNAME" length="25" not-null="true" /> <property name="lastName" type="string" update="false" insert="true" column="CUSTOMER_LASTTNAME" length="25" not-null="true" /> </class> </hibernate-mapping>
set name="accounts"
和一对多类标签指定了 Customer
和 Account
之间的关系。我还在 Account.hbm.xml 文件中定义了 Account
对象的映射。
CustomerDAOImpl.java
代表应用程序的 DAO,它在应用程序数据库中插入客户和帐户信息。CustomerDAOImpl
扩展了 Spring 的HibernateDaoSupport
,它用 Spring HibernateTemplate 简化了会话管理。这样,可以通过 getHibernateTemplate()
方法保存或检索数据。下面显示的 getCustomerAccountInfo()
对 Customer
进行 查找,通过 getHibernateTemplate().find
方法用 HQL 得到客户的帐户信息,如清单 4 所示。
清单 4. DAO 实现
public class CustomerDAOImpl extends HibernateDaoSupport implements CustomerDAO{ public void addCustomer(Customer customer) { getHibernateTemplate().save(customer); // TODO Auto-generated method stub } public Customer getCustomerAccountInfo(Customer customer) { Customer cust = null; List list = getHibernateTemplate().find("from Customer customer " + "where customer.userId = ?" , customer.getUserId(),Hibernate.STRING); if(list.size() > 0){ cust = (Customer) list.get(0); } return cust; }
转载地址:http://www.ibm.com/developerworks/cn/java/wa-spring2/index.html