该模块定义了两个简单的数据访问对象(DAO)。一个DAO是一个提供持久化操作接口的对象。在这个应用中我们使用了对象关系映射(ORM)框架Hibernate,DAO通常在对象旁边定义。在本项目中,我们定义两个DAO对象:WeatherDAO
和LocationDAO
。WeatherDAO
类允许我们保存一个Weather
对象至数据库,根据id
获取一个Weather
对象,获取匹配特定Location
的Weather
对象。LocationDAO
有一个方法允许我们根据邮政编码获取Location
对象。首先,让我们看一下Example 7.8, “simple-persist 的 POM”中的simple-persist
POM。
Example 7.8. simple-persist 的 POM
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook.ch07</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent> <artifactId>simple-persist</artifactId> <packaging>jar</packaging> <name>Simple Persistence API</name> <dependencies> <dependency> <groupId>org.sonatype.mavenbook.ch07</groupId> <artifactId>simple-model</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> <version>3.2.5.ga</version> <exclusions> <exclusion> <groupId>javax.transaction</groupId> <artifactId>jta</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.3.0.ga</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>3.3.0.ga</version> </dependency> <dependency> <groupId>org.apache.geronimo.specs</groupId> <artifactId>geronimo-jta_1.1_spec</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.0.7</version> </dependency> </dependencies> </project>
这个POM文件引用simple-parent
作为一个父POM,它定义了一些依赖。simple-persist
的POM中列出的依赖有:
org.sonatype.mavenbook.ch07:simple-model:1.0
-
就像
simple-weather
模块一样,这个持久化模块引用了simple-model
中定义的核心模型对象。 org.hibernate:hibernate:3.2.5.ga
-
我们定义了一个对HIbernate版本3.2.5ga的依赖,但注意我们排除了Hibernate的一个依赖。这么做是因为
javax.
transaction:
javax
依赖在公共Maven仓库中不可用。此依赖正好是Sun依赖中的一个,不能免费在中央Maven仓库中提供。为了避免烦人的信息告诉我们去下载非免费的依赖,我们简单的从Hibernate排除这个依赖然后添加一个geronimo-jta_1.1_spec依赖。 org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1
-
就像Servlet和JSP API,Apache Geronimo项目也根据Apache许可证友好的发布了一些认证过的企业级API。这意味着不管什么时候某个组件告诉你它依赖于JDBC,JNDI,和JTA API,你都可以查一下groupId为
org.apache.geronimo.specs
下的对应类库。 org.springframework:spring:2.0.7
-
这里包含了整个Spring Framework作为一个依赖。
Note
只依赖于你正使用的Spring组件是一个很好的实践。Spring Framework项目很友好的创建了一些有针对性的构件如
spring-hibernate3
。
为什么依赖于Spring呢?当和Hibernate集成的时候,Spring允许我们使用一些帮助类如HibernateDaoSupport
。作为一个HibernateDaoSupport
的样例,看一下Example 7.9, “simple-persist'的WeatherDAO类”中的WeatherDAO
代码。
Example 7.9. simple-persist'的WeatherDAO类
package org.sonatype.mavenbook.weather.persist; import java.util.ArrayList; import java.util.List; import org.hibernate.Query; import org.hibernate.Session; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.sonatype.mavenbook.weather.model.Location; import org.sonatype.mavenbook.weather.model.Weather; public class WeatherDAO extends HibernateDaoSupport { public WeatherDAO() {} public void save(Weather weather) { getHibernateTemplate().save( weather ); } public Weather load(Integer id) { return (Weather) getHibernateTemplate().load( Weather.class, id); } @SuppressWarnings("unchecked") public List<Weather> recentForLocation( final Location location ) { return (List<Weather>) getHibernateTemplate().execute( new HibernateCallback() { public Object doInHibernate(Session session) { Query query = getSession().getNamedQuery("Weather.byLocation"); query.setParameter("location", location); return new ArrayList<Weather>( query.list() ); } }); } }
就是这样。你已经编写了一个类,它能插入新的行,根据主键选取,以及能查找所有Weather表根据id连接Location表的结果。很显然,我们不能将书停在这里,然后花500页给你解释Hibernate的运作详情,但我们能做一些快速简单的解释:
现在是时候阐明一些情况了。HibernateDaoSupport
和HibernateTemplate
是来自于Spring
Framework的类。它们由Spring Framework创建,目的是减少编写Hibernate
DAO对象的痛苦。为了支持这个DAO,我们需要在simple-persist
的Spring
ApplicationContext
定义中做一些配置。Example 7.10, “simple-persist 的 Spring Application Context”中显示的XML文档存储在src/main/resources
,名为applicationContext-persist.xml
。
Example 7.10. simple-persist 的 Spring Application Context
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd" default-lazy-init="true"> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="annotatedClasses"> <list> <value>org.sonatype.mavenbook.weather.model.Atmosphere</value> <value>org.sonatype.mavenbook.weather.model.Condition</value> <value>org.sonatype.mavenbook.weather.model.Location</value> <value>org.sonatype.mavenbook.weather.model.Weather</value> <value>org.sonatype.mavenbook.weather.model.Wind</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.show_sql">false</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.transaction.factory_class"> org.hibernate.transaction.JDBCTransactionFactory </prop> <prop key="hibernate.dialect"> org.hibernate.dialect.HSQLDialect </prop> <prop key="hibernate.connection.pool_size">0</prop> <prop key="hibernate.connection.driver_class"> org.hsqldb.jdbcDriver </prop> <prop key="hibernate.connection.url"> jdbc:hsqldb:data/weather;shutdown=true </prop> <prop key="hibernate.connection.username">sa</prop> <prop key="hibernate.connection.password"></prop> <prop key="hibernate.connection.autocommit">true</prop> <prop key="hibernate.jdbc.batch_size">0</prop> </props> </property> </bean> <bean id="locationDAO" class="org.sonatype.mavenbook.weather.persist.LocationDAO"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <bean id="weatherDAO" class="org.sonatype.mavenbook.weather.persist.WeatherDAO"> <property name="sessionFactory" ref="sessionFactory"/> </bean> </beans>
在这个application
context中,我们完成了一些事情。DAO从sessionFactory
bean获取Hibernate
Session
对象。这个bean是一个AnnotationSessionFactoryBean
的实例,并由一列annotatedClasses
填充。注意这列标注类就是定义在我们simple-model
模块中的那些类。接下来,sessionFactory
通过一组Hibernate配置属性(hibernateProperties
)配置。该例中,我们的Hibernate属性定义了许多设置:
hibernate.dialect
-
该设置控制如何生成数据库的SQL。由于我们正在使用HSQLDB数据库,我们的数据库方言设置成
org.
hibernate.
dialect.
HSQLDialect
。Hibernate有所有主流数据库的方言,如Oracle,MySQL,Postgres和SQL Server。 hibernate.connection.*
-
该例中,我们从Spring配置中配置JDBC连接属性。我们的应用被配置成运行在
./data/weather
目录下的HSQLDB上。在实际的企业应用中,你更可能会使用如JNDI的东西以从你的应用程序代码中抽出数据库配置。
最后,在这个bean定义文件中,两个simple-persist
DAO对象被创建并给予了对于刚定义的sessionFactory
bean的引用。就像simple-weather
中的Spring application
context,这个applicationContext-persist.xml
文件定义了一个大型企业应用设计中一个子模块的架构。如果你曾经从事过大量持久化类的集合相关的工作,你可能会发现,这些与你应用程序独立的application
context文件,能帮助你快速的理解所有类之间的关系。
simple-persist
中还有最后一块不清楚的地方。本章后面,我们将看到如何使用Maven Hibernate3插件,根据标注的模型对象来生成数据库schema。为了使它正确工作,Maven
Hibernate3插件需要读取JDBC连接配置参数,那一列标注的类,以及src/main/resources
中名为hibernate.cfg.xml
文件的Hibernate配置。该文件(它重复了一些applicationContext-persist.xml
中的配置)的目的是能让Maven
Hibernate3插件能仅仅依靠标注就能生成数据定义语言(DDL)。如Example 7.11, “simple-persist 的 hibernate.cfg.xml”。
Example 7.11. simple-persist 的 hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.HSQLDialect</property> <!-- Database connection settings --> <property name="connection.driver_class">org.hsqldb.jdbcDriver</property> <property name="connection.url">jdbc:hsqldb:data/weather</property> <property name="connection.username">sa</property> <property name="connection.password"></property> <property name="connection.shutdown">true</property> <!-- JDBC connection pool (use the built-in one) --> <property name="connection.pool_size">1</property> <!-- Enable Hibernate's automatic session context management --> <property name="current_session_context_class">thread</property> <!-- Disable the second-level cache --> <property name="cache.provider_class"> org.hibernate.cache.NoCacheProvider </property> <!-- Echo all executed SQL to stdout --> <property name="show_sql">true</property> <!-- disable batching so HSQLDB will propagate errors correctly. --> <property name="jdbc.batch_size">0</property> <!-- List all the mapping documents we're using --> <mapping class="org.sonatype.mavenbook.weather.model.Atmosphere"/> <mapping class="org.sonatype.mavenbook.weather.model.Condition"/> <mapping class="org.sonatype.mavenbook.weather.model.Location"/> <mapping class="org.sonatype.mavenbook.weather.model.Weather"/> <mapping class="org.sonatype.mavenbook.weather.model.Wind"/> </session-factory> </hibernate-configuration>
Example 7.10, “simple-persist 的 Spring Application Context”和Example 7.1, “simple-parent 项目的 POM”的内容是冗余的。Spring Application
Context
XML是被web应用和命令行应用使用的,而hibernate.cfg.xml
的存在只是为了支持Maven
Hibernate3插件。本章的后面,我们将会看到如何使用hibernate.cfg.xml
和Maven
Hibernate3插件,根据simple-model
中定义的标注对象模型,来生成一个数据库schema。hibernate.cfg.xml
会配置JDBC连接属性并且为Maven
Hibernate3插件枚举标注模型类的列表。