2.7 使用MyEclipse可视化开发Hibernate实例
2.7节的例子源代码在配套光盘sourcecode/workspace目录的chapter02_first项目中。
这个实例主要演示如何使用MyEclipse的可视化开发工具开发Hibernate应用,利用MyEclipse可以提高我们开发Java EE应用的效率。操作的数据库表还是guestbook表,所使用MyEclipse的版本为7.0,不同的MyEclipse版本之间对于开发Hibernate应用差异不大。
在7.0版本中,内置了对Hibernate 2.x、3.0、3.1和3.2等Hibernate版本的支持,没有提供对3.3版本的支持。我们可以修改MyEclipse的设置,把对Hibernate 3.2的支持,修改为对Hibernate 3.3的支持。为此启动Eclipse后,选中菜单栏的"Windows"→"Preference"→"MyEclipse Enterprise Workbench"→"Project Capabilities"→"Hibernate"→"Hibernate 3.2"选项,在Library Modules下拉列表框中选中Hibernate 3.2 Core Libray选项,把类库文件替换为Hibernate 3.3的类库文件。如图2 2所示。
2.7.1 设置MyEclipse连接Oracle数据库
为在MyEclipse中设置连接Oracle数据库,在Eclipse中选择Window→Show View→Other→MyEclipse Database→DB Browser选项。右击DB Browser视图的空白部分,选择New选项,如图2 3所示。
在弹出的窗口中,输入连接Oracle数据库所需要的相应参数,以及Oracle驱动类库的文件名与位置。单击Next按钮,如图2 4所示。
在Schema Details窗口中,选中Display Selected单选按钮。单击"Add"按钮,在弹出的Selection Needed窗口中选中SCOTT复选框。单击"OK"按钮,如图2 5所示。单击"Finish"按钮,关闭Schema Details窗口。
2.7.2 新建项目并增加Hibernate开发支持
在Eclipse中新建一个Java项目,名为"chapter02_first"。单击MyEclipse→Project Capabilities→Add Hibernate Capabilites选项,增加Hibernate的开发支持,如图2 6所示。
弹出Hibernate Support for MyEclipse窗口,在Hibernate Specification选项组中选中Hibernate 3.2单选按钮,选择MyEclipse Libraries和Hibernate 3.2 Core Libaries-<MyEclipse-Library>复选框选项,如图2 7所示,单击Next按钮。
其中的选项说明如表2-3所示。
表2-3 选项说明
选项
描述
Hibernate Specification
要添加到项目中的Hibernate具体版本,推荐选择Hibernate 3.2
Enable Hibernate Annotations Support
是否需要Hibernate Annotations的支持
MyEclipse Libraries/User Libraries
选择显示哪个位置的类库
Add checked Libraries to project build-path
选中的类库将会添加当前项目的构建路径中,但是相应的Jar文件将不会复制到项目中,这些Jar文件会在项目部署时复制
Copy checked Library Jars to project folder and add to build-path
选中的类库中的Jar文件将会被复制到项目并添加到构建路径中
Library Folder
一个相对于当前项目的路径,类库中的Jar会被复制到其中
在接下来的窗口中输入MyEclipse产生的Hibernate配置文件名及其路径。使用hibernate.cfg.xml文件名,路径保留默认值,如图2 8所示。
单击Next按钮,在DB Driver下拉列表框中选中已设置的oracledriver选项,其他选项保留默认值,如图2 9所示。
单击"Next"按钮,清除"Create SessionFactory Class"复选框,如图2 10所示,单击Finish按钮结束设置。
执行上述操作后,MyEclipse会在项目的构建路径中增加Hibernate的相关类库和Oracle的驱动类库。同时生成了开发Hibernate应用所需的hibernate.cfg.xml文件,整个项目的所有类库文件和配置文件如图2 11所示。
还需要修改MyEclipse自动生成的hibernate.cfg.xml文件,增加一些新的配置项并修改Oracle数据库方言类的名称。修改后的hibernate.cfg.xml的内容如下所示(加粗显示部分为需要修改处)。
SRC 2 2 hibernate.cfg.xml <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name= "dialect">org.hibernate.dialect.Oracle9iDialect</property> <property name= "connection.url">jdbc:oracle:thin:@localhost:1521:ora9</property> <property name="connection.username">scott</property> <property name="connection.password">tiger</property> <property name= "connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <property name="myeclipse.connection.profile">oracledriver</property> <property name="current_session_context_class">thread</property> <property name="show_sql">true</property> <property name="format_sql">true</property> </session-factory> </hibernate-configuration>
2.7.3 自动生成Guestbook类与映射文件
在Eclipse的DB Browser视图中,右击设置的oracledriver名。选择Open connection选项,如图2 12所示弹出Open Database Connection窗口,输入用户名及密码,如图2 13所示,单击OK按钮。
右击DB Browser视图中的guestbook表,选中"Hibernate Reverse Engineering"选项。如图2 14所示。
弹出"Hibernate Mapping and Application Generation"窗口,输入与生成持久化类(POJO)有关的参数值。在Java src folder文本框中输入生成持久化类的保存路径,在Java package文本框中输入持久化类所使用的包名。选择"Create POJO<>DB Table mapping information、Create a Hibernate mapping file (*.hbm.xml) for each database table"及"Java Data Object (POJO<> DB Table)"复选框,清除"Create abstract class"复选框,如图2 15所示。
单击Next按钮,在打开窗口中的Id Generator下拉列表框中选中sequence选项,其他选项保留默认值,如图2 16所示。
单击"Next"按钮,在打开如图2 17所示的窗口中单击"Finish"按钮。
经过上面的操作之后,MyEclipse会自动生成Guestbook.java和Guestbook.hbm.xml两个文件。Guestbook.hbm.xml文件的内容如下所示,需要修改008行~第010行的内容用来设置序列名。
SRC 2 3 Guestbook.hbm.xml 001 <?xml version="1.0" encoding="utf-8"?> 002 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 003 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 004 <hibernate-mapping> 005 <class name="com.v512.examples.Guestbook" table="GUESTBOOK" schema="SCOTT"> 006 <id name="id" type="java.lang.Integer"> 007 <column name="ID" precision="8" scale="0" /> 008 <generator class="sequence"> 009 <param name="sequence">gb_seq</param> 010 </generator> 011</id> 012<property name="name" type="java.lang.String"> 013 <column name="NAME" length="20" not-null="true" /> 014</property> 015<property name="phone" type="java.lang.String"> 016 <column name="PHONE" length="20" /> 017</property> 018<property name="email" type="java.lang.String"> 019 <column name="EMAIL" length="40" /> 020</property> 021<property name="title" type="java.lang.String"> 022 <column name="TITLE" length="80" not-null="true" /> 023</property> 024<property name="content" type="java.lang.String"> 025 <column name="CONTENT" length="2000" /> 026</property> 027<property name="createdTime" type="java.util.Date"> 028 <column name="CREATED_TIME" not-null="true" /> 029</property> 030 </class> 031 </hibernate-mapping>
第005行中<class>标签的schema属性设置当前表属于哪个schema,第007行和第013行中<column>标签的precision、scale及length属性设置表中字段的精度、小数点位数和长度,not-null属性设置该字段是否不允许为空。
2.7.4 编写HibernateSessionFactoryUtil.java文件
在Hibernate应用中,如果只使用一个数据库,则通常只需要一个SessionFactory对象。为了方便整个应用取得同一个SessionFactory对象,我们应用设计模式中的单态模式。编写一个SessionFactory的工具类HibernateSessionFactoryUtil,HibernateSessionFactoryUtil.java文件的内容如下:
SRC 2 4 HibernateSessionFactoryUtil.java 001 package com.v512.util; 002 003 import org.hibernate.SessionFactory; 004 import org.hibernate.cfg.Configuration; 005 006 public class HibernateSessionFactoryUtil { 007 private static final SessionFactory sessionFactory; 008 static { 009 try { 010 sessionFactory = new Configuration().configure(). buildSessionFactory(); 011 } catch (Throwable ex) { 012 /* 013 * 需要 捕获Throwable对象, 014 * 否则捕获不到 Error及其子类,以及NoClassDefFoundError类型的错误 015 */ 016 throw new ExceptionInInitializerError(ex); 017 } 018 } 019 020 private HibernateSessionFactoryUtil() { 021 022 } 023 024 public static SessionFactory getSessionFactory() { 025 return sessionFactory; 026 } 027 }
HibernateSessionFactoryUtil类在载入JVM后新建Configuration对象,读取hibernate.cfg.xml文件,创建SessionFactory对象,通过HibernateSessionFactoryUtil类所提供的getSessionFactory()静态方法获取SessionFactory对象。
2.7.5 编写HibernateTest.java
编写一个测试的HibernateTest.java文件,通过Hibernate实现对guestbook表中数据的CRUD操作,在其中定义addGuestbook()、updateGuestbook()、getGuestbook()、getGuestbooks()、deleteGuestbook()和printGuestbook()方法。该文件的内容如下:
SRC 2 5 HibernateTest.javaa 001 package com.v512.examples; 002 003 import java.util.List; 004 import org.hibernate.Query; 005 import org.hibernate.Session; 006 import org.hibernate.Transaction; 007 import com.v512.util.HibernateSessionFactoryUtil; 008 009 public class HibernateTest { 010 public void addGuestbook(Guestbook gb) { 011Session session = HibernateSessionFactoryUtil. getSessionFactory(). getCurrentSession(); 012 Transaction tx = session.beginTransaction(); 013 session.save(gb); 014 tx.commit(); 015 } 016 017 public Guestbook getGuestbook(Integer id) { 018 Session session = HibernateSessionFactoryUtil. getSessionFactory(). getCurrentSession(); 019 Transaction tx = session.beginTransaction(); 020 Guestbook gb = (Guestbook) session.get (Guestbook.class, id); 021 tx.commit(); 022 return gb; 023 } 024 025 public List<Guestbook> getGuestbooks() { 026 Session session = HibernateSessionFactoryUtil. getSessionFactory(). getCurrentSession(); 027 Transaction tx = session.beginTransaction(); 028 Query query = session.createQuery("from Guestbook"); 029 List<Guestbook> list = query.list(); 030 tx.commit(); 031 return list; 032 } 033 034 public void updateGuestbook(Guestbook gb) { 035 Session session = HibernateSessionFactoryUtil. getSessionFactory(). getCurrentSession(); 036 Transaction tx = session.beginTransaction(); 037 session.saveOrUpdate(gb); 038 tx.commit(); 039 } 040 041 public void deleteGuestbook(Integer id) { 042 Guestbook gb = getGuestbook(id); 043 Session session = HibernateSessionFactoryUtil. getSessionFactory(). getCurrentSession(); 044 Transaction tx = session.beginTransaction(); 045 session.delete(gb); 046 tx.commit(); 047 } 048 049 public void printGuestbook(Guestbook gb) { 050 System.out.print("id:" + gb.getId() + "\t"); 051 System.out.print("name:" + gb.getName() + "\t"); 052 System.out.print("title:" + gb.getTitle() + "\t"); 053 System.out.print("content:" + gb.getContent() + "\t"); 054 System.out.println("createdTime:" + gb.getCreatedTime()); 055 } 056 057 public static void main(String[] args) { 058 HibernateTest test = new HibernateTest(); 059 Guestbook gb = test.getGuestbook(new Integer(1)); 060 061 System.out.println("------------------------- 读取单一记录-----------------------------"); 062 test.printGuestbook(gb); 063 064 System.out.println("------------------------- 读取所有记录-----------------------------"); 065 List<Guestbook> list = test.getGuestbooks(); 066 for (Guestbook g : list) { 067 test.printGuestbook(g); 068 } 069 070 System.out.println("------------------------- 更新记录---------------------------------"); 071 gb.setName("关羽"); 072 test.updateGuestbook(gb); 073 test.printGuestbook(gb); 074 075 System.out.println("------------------------- 删除记录---------------------------------"); 076 test.deleteGuestbook(new Integer(1)); 077 078 HibernateSessionFactoryUtil.getSessionFactory().close(); 079 } 080 }
当使用HibernateTest类中getGuestbook()方法根据id值获取一条记录时,Hibernate找到数据库中这条记录,然后再生成这条记录所对应的持久化对象返回。updateGuestbook()方法更新一条记录时首先找到这条记录所对应的持久化对象,然后调用这个对象的setter方法修改属性值,并通过Hibernate完成数据库中数据的更新;deleteGuestbook()方法删除一条记录时首先找到这条记录所对应的持久化对象,然后通过Hibernate删除持久化对象删除进而数据库中所对应的数据。
2.7.6 程序运行结果
这个实例使用Hibernate完成对数据库中数据的CRUD操作,借助MyEclipse的帮助开发Hibernate应用,不需要手工编写持久化(POJO)类、Hibernate的配置和映射文件。Hibernate通过操作持久化对象完成对数据库数据的CRUD操作, HibernateTest.java运行结果如下:
-------------------------读取单一记录----------------------------- id:1 name:刘伟 title:大家好 content:欢迎大家学习Hibernate技术。 createdTime: 2009-03-12 06:17:59.0 -------------------------读取所有记录----------------------------- id:1 name:刘伟 title:大家好 content:欢迎大家学习Hibernate技术。 createdTime: 2009-03-12 06:17:59.0 -------------------------更新记录--------------------------------- id:1 name:关羽 title:大家好 content:欢迎大家学习Hibernate技术。 createdTime: 2009-03-12 06:17:59.0 -------------------------删除记录---------------------------------
2.7.7 使用 HQL 编辑器调试HQL语句
MyEclipse中包含一个Hibernate编辑器和多个相关视图,允许根据当前项目的配置来调试HQL语句。"Hibernate Dynamic Query Translator"视图显示当前HQL语句所对应的SQL语句;"Hibernate Query Result"视图查看HQL语句的执行结果,返回的持久化对象的属性值通过"Properties"视图显示;"Query Parameters"视图可以为调试的HQL语句输入需要的参数值。
右击Package Explorer视图中的chapter02_first项目,选中快捷菜单中的"MyEclipse→Open HQL Editor"选项,如图2 18所示。
打开HQL编辑器,输入"from Guestbook"。单击运行图标执行查询,并且通过相关视图查看查询结果,如图2 19所示。
还可以使用"Query Parameters视图输入需要绑定参数的HQL查询语句,如图2 20所示。
2.8 Hibernate应用的开发方式
2.8.1 自底向上,从数据库表到持久化类
采用自底向上的开发方式,采用手工或者MyEclipse等开发工具直接根据数据库中表的结构生成对应的映射文件和持久化类。这是实际开发中最常用的一种方式,也是本书所推荐的方式。通过这种方式最小化了手工编码,降低了出错的可能性。
2.8.2 自上向下,持久化类到数据库表
首先编写持久化类,然后根据持久化类的代码手工编写或者采用工具生成映射文件,进而生成数据库表结构。这种方式在实际开发中也经常使用,可能出现的问题是生成的数据库表结构与实际需要的数据库表结构之间的差异,需要手工调整。
2.8.3 从中间出发,向上与向下发展
首先编写持久化类与数据库表的映射文件,然后根据映射文件手工编码或者采用工具向上生成持久化类,向下生成数据库表结构。
2.9 设置Hibernate使用连接池
Hibernate默认使用一个功能简单的连接池,通常只用于开发阶段测试之用。为了更高效地使用Hibernate,可以设置Hibernate使用第三方C3P0或者应用服务器(容器)所带的数据库连接池。
2.9.1 设置使用Tomcat中的连接池
如果开发运行在应用服务器中的程序,建议其中配置的连接池,如允许Hibernate使用通过在Tomcat中所配置的连接池。为此修改Tomcat中的context.xml文件,该文件位于tomcat安装目录的conf子目录中,同时还需要将Oracle数据库的驱动类库ojdbc6.jar或者ojdbc14.jar添加到tomcat的lib目录下。修改后的context.xml文件内容如下:
SRC 2 6 context.xml <Context reloadable="true"> <WatchedResource>WEB-INF/web.xml</WatchedResource> <Resource name="jdbc/oracleds" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10 000" username="scott" password="tiger" driverClassName="oracle.jdbc.OracleDriver" url= "jdbc:oracle:thin:@localhost:1521:ora9" /> </Context>
设置Tomcat提供的连接池之后,要在Hibernate的配置文件(hibernate.cfg.xml)中添加connection.datasource属性,如下面的代码所示:
<property name="connection.datasource"> java:comp/env/jdbc/oracleds</property>
其中的java:comp/env/jdbc/oracleds是Tomcat中设置的数据源对象的JNDI名称。
2.9.2 使用C3P0连接池
如果让Hibernate使用第三方C3P0连接池,则在Hibernate的配置文件中添加如下的配置信息,还需要把C3P0类库添加到当前项目的构建路径下。
<property name="connection.provider_class"> org.hibernate.connection.C3P0ConnectionProvider </property> <property name="hibernate.c3p0.min_size">5</property> <property name="hibernate.c3p0.max_size">10</property> <property name="hibernate.c3p0.max_statements">50</property> <property name="hibernate.c3p0.timeout">3600</property> <property name="hibernate.c3p0.idle_test_period">120</property> <property name="hibernate.c3p0.acquire_increment">2</property>
- hibernate.c3p0.min_size:设置连接池的最小连接数。
- hibernate.c3p0.max_siz:设置连接池的最大连接数。
- hibernate.c3p0.timeout:设置连接池中的连接的最大空闲时间,超时后会被删除,单位为秒。
- hibernate.c3p0.max_statements:设置连接池中Statement对象的最大数量。
- hibernate.c3p0.idle_test_period:设置检查连接池中空闲连接的间隔时间,单位为秒。
- hibernate.c3p0.acquire_increment:设置连接池的连接用完后每次新建连接的数量。
2.9.3 使用自定义连接池
在Hibernate应用中还可以使用定义连接池,该连接池需要实现org.hibernate.connection.ConnectionProvider接口,并在Hibernate配置文件中设置hibernate.connection.provider_class属性,其值为这个实现类的名称。
2.10 使用C3P0连接池
2.10节的例子源代码在配套光盘sourcecode/workspace目录的chapter02_first项目中。
2.10.1 创建chapter02_c3p0项目
在这个实例中让Hibernate使用第三方C3P0连接池获取操作数据库的连接对象,通过复制chapter02_first项目创建chapter02_c3p0项目。同时还需要把C3P0连接池的类库(c3p0-*.*.*.jar)添加到当前项目的构建目录下。当前项目构建路径中的类库如图2 21所示。
2.10.2 编辑hibernate.cfg.xml文件
当前项目使用了C3P0的连接池技术,修改hibernate.cfg.xml文件以配置相应的参数,其内容如下:
SRC 2 7 hibernate.cfg.xml <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net /hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="connection.driver_class">oracle.jdbc.driver. OracleDriver</property> <property name="connection.url">jdbc:oracle:thin:@localhost: 1521:ora9</property> <property name="dialect">org.hibernate.dialect. Oracle9iDialect</property> <property name="connection.username">scott</property> <property name="connection.password">tiger</property> <!-- C3P0 连接池的配置 --> <property name="connection.provider_class"> org.hibernate.connection.C3P0ConnectionProvider </property> <property name="hibernate.c3p0.min_size">5</property> <property name="hibernate.c3p0.max_size">10</property> <property name="hibernate.c3p0.max_statements">50</property> <property name="hibernate.c3p0.timeout">3600</property> <property name="hibernate.c3p0.idle_test_period">120</property> <property name="hibernate.c3p0.acquire_increment">2</property> <property name="current_session_context_class">thread</property> <property name="show_sql">true</property> <property name="format_sql">true</property> <mapping resource="com/v512/examples/Guestbook.hbm.xml" /> </session-factory> </hibernate-configuration>
2.10.3 chapter02_c3p0项目的运行与输出
chapter02_c3p0项目中,其他文件都不需要修改,运行HibernateTest类输出的结果chapter02_first项目运行输出结果完全一样。