`
JAVA海洋
  • 浏览: 618182 次
  • 性别: Icon_minigender_1
  • 来自: 太原
社区版块
存档分类
最新评论

在JAVA SE中使用Hibernate

阅读更多
目前人们很容易发现Hibernate正迅速的成为流行的J2EE的O/R映射工具和数据集成框架(如果不是最流行的)。Hibernate为企业应用开发者操作关系数据库的提供了清晰明了而又强大的工具。然而如果你需要在外部访问那些包装在J2EE web应用里的实体,情况又怎样呢?你的开发跟应用独立分开,却又相同的实体以访问你的数据吗?又或者你得编写附加的web组件来管理对数据的内部访问吗?

在很多情况下,这些问题都会出现。我的情况是我的公司需要将来自多个供应商,有着多种文件格式的记录导入到数据库里。我想起我以前经常使用的方法,那就是编写Shell和SQL教本(甚至是存储过程)来导入数据。但是由于我们的数据模型太过复杂,我决定在web应用之外尽可能的利用现有的实体,Spring DAO以及服务并且开发一个自定义的J2SE命令行数据加载工具。

大问题:你该怎样呢?

现在很多Hibernate的文档和范例都是绑定在容器上。不管是web应用还是内部的大型应用,总会使用到容器的。人们有很好的理由去使用它。容器是设计来提供对各种特性的支持,例如事务处理,线程以及安全。现今,这些特性都是开发中等规模和企业应用所必需的工具。然而当你需要在容器之外访问实体时,你该怎样呢?你是使用现有的架构和代码呢,还是会从一个不同的角度来解决问题,比如说完全采用另一种开发语言?当然,我们没有正确答案。在本文的余下部分,我将说明我的方法:就是在Spring容器之外重用现有的实体/POJO。

起初,脚本语言,例如Perl,Python,Ruby甚至Tcl(是的,我以前也做过这个)看起来有很多优势。它们能省下很多时间,可以轻易得到初始结果,还能规避许多Hibernate潜在的复杂度。人们完全可能只用几行代码就可以连接数据库,查询结果,已经打印输出到终端屏幕或者日志文件。然而,取决于你的数据模型,事情也(总是)会变得相当复杂。譬如说你有一个表 person, 其中有一个外键属于表 address。当我们添加数据的时候,表address没有正确的插入数据,就会导致表person 也不能插入了。这是个很典型的事务处理方面的问题。也许有人会说在脚本语言中这个问题不难解决,就像在你的主程序里一样。可是问题仍然存在,为什么要这样做呢?业务逻辑不是已经在你的应用里面了吗?为什么要在写一遍代码呢?而且这并不是唯一的情况,你必须重复你的工作和业务逻辑,这样就会带来出错的可能。

然而,有些人会觉得这样也行,他们使用自己觉得最适合的工具。也许你已经因为程序之外的原因而有了某种独立的架构;也许你会在独立的数据库里加载和测试数据,然后在通过各种测试后再迁移到产品的数据库里;又也许你把数据库维护外包出去,你只需要把相关文件发给合作伙伴让他们去处理那些问题。总之,总会有很多理由不使用现有的Hibernate数据层。没有谁对谁错,只是如果你可以也愿意在你的应用之外使用现有的代码,请往下看。我会告诉你一些方法,这能解决你不少的烦恼噢。

配置

如果你觉得可以在容器之外使用现有的Hibernate对象的话,那你首先要做的事就是得自己手工管理所有的配置项,在本文余下部分我所采用的方法是使用一个基于命令行的JAVA程序。既然你已经配置了Hibernate XML配置文件,你应该知道需要提供的参数,例如JNDI DataSource名,实体映射文件,还有其他一些处理SQL日志的属性。如果你想使用命令行程序的话,你就得解决如何解析XML文件和把它添加到配置项中的这些问题。虽然解析XML文件也不难,但这本身并不是我们的重点。因此,我建议使用propetries文件,properties文件比较直观而且容易加载并从中读取数据。下面是配置Hibernate所需要的最小属性集(不包括任何实体映射)。

清单1:
hibernate.dialect=net.sf.hibernate.dialect.PostgreSQLDialect
hibernate.connection.driver_class=org.postgresql.Driver
hibernate.connection.url=jdbc:postgresql://devserver/devdb
hibernate.connection.username=dbuser
hibernate.connection.password=dbpassword
hibernate.query.substitutions yes 'Y'


正如你所看到的,上面的属性值指定了数据库方言,JDBC驱动,数据库url,用户名,用户密码,以及是否使用查找替换。只要定义以上几项数值并保存在文件hibernate.properties里(要放置在你的类路径里面哦),就能很轻松的加载,填充到Hibernate Configuation类里面。

清单2:
Properties props = new Properties();
try {
props.load(props.getClass().getResourceAsStream("hibernate.properties"));
}catch(Exception e){
System.out.println("Error loading hibernate properties.");
e.printStackTrace();
System.exit(0);
}

String driver = props.getProperty("hibernate.connection.driver_class");
String connUrl = props.getProperty("hibernate.connection.url");
String username = props.getProperty("hibernate.connection.username");
String password = props.getProperty("hibernate.connection.password");

// In my examples, I use Postgres, but Hibernate
// supports virtually every popular dbms out there.
Class.forName("org.postgresql.Driver");
Connection conn = DriverManager.getConnection(connUrl, username, password);

Configuration cfg = new Configuration();
cfg.setProperties( props );
SessionFactory sessions = cfg.buildSessionFactory();
Session session = sessions.openSession(conn);


这样我们就得到了Hibernate Session类了。但我们也有必要解决如何利用现有的实体映射这个问题。在《Hibernate in Action》一书中,提到怎样从实体映射XML文件中加载,如下所示:

清单3:
Configuration cfg = new Configuration(); 
cfg.addResource("hello/Message.hbm.xml");
cfg.setProperties( System.getProperties() );
SessionFactory sessions = cfg.buildSessionFactory();


这段代码清晰的说明了从hello包里加载Message实体定义的过程。对于这个例子来说还好,但对那些有多个实体的应用来说,就很单一而且容易出错。不仅映射关系是硬编码,还得手工管理每次添加一个新的实体就要更新实体加载的代码。其实有跟简单的方法去查找和加载映射关系以使其与最新的jar文件保持一致。

首先,在你的web服务器或者企业服务器里,映射文件需要放置在类路径里,这样Hibernate才能正常的运行。这样做是很有好处的,因为你所需要做的就是使用同样的jar包和查找相应的映射文件的名字。因为你可能会有多个jar文件在你的类路径里,你需要指定哪个jar包包含了映射文件。以下就是一种查找映射关系的方法

清单4:
String cp = System.getProperty("java.class.path");
String jarFile = null;
List hbmList = null;

String[] cparr = cp.split("\\:");
for(int j=0;j<cparr.length;j++){
// The following assumes our entities
// are wrapped up in a jar file
// called 'dbobjs.jar'
if(cparr[j].indexOf("dbobjs.jar") != -1)
jarFile=(cparr[j]);
}

if(jarFile != null){
JarFile jar = new JarFile(new File(jarFile));
Enumeration e = jar.entries();
if(e.hasMoreElements()){
hbmList = new ArrayList();
while(e.hasMoreElements()){
// Object comes back as JarFile$JarFileEntry
JarEntry entry = (JarEntry)e.nextElement();
if(entry.getName().indexOf(".hbm.xml") != -1){
hbmList.add(entry.getName());
}
}
}else {
System.out.println("Error: The entity jar dbobjs.jar was not found in " +
"classpath: " + cp);
}
}


上面的代码主要完成了以下几件事情:获取Java虚拟机初始化的classpath系统属性;查找含有实体映射文件的jar包;解析映射文件的名字,然后添加到一个ArrayList对象中去。当我们的ArrayList对象装满了实体映射的名字后,就可以将其传递到Hibernate Configuration 对象,如下所示:

清单5:
Configuration cfg = new Configuration(); 

Iterator iterator = hbmFileNames.iterator();
while(iterator.hasNext()){
cfg.addResource((String)iterator.next());
}


只要我们在Hibernate Session 对象里配置好正确的映射关系,我们就可以将实体拿来使用了。

使用Session

关于这一点,你可以参考关于Hibernate和持久层的文章或者指南,也可以查询各种对象和实例来了解怎么使用事务,所以我不打算详细说这些内容。相反,我会更多考虑使用实体后我们需要做什么?这会对Hibernate Session 对象有怎样的影响?是否可以使用现有的业务对象,甚至是数据访问对象?当我建立数据层的时候,我使用了Spring及其提供的一些类来管理数据库连接,事务和会话。这些对象都在XML配置文件里面定义了,并与很多规则和关系紧密集成在Spring里。首先,通过Spring的依赖注射,DAO对象会被引入到应用服务中(关于依赖注射,参见Bruce Tate的《Five Things I Love About Spring》一书)。然后,配置应用服务以捕获DAO异常(通过XML配置文件),让Spring去处理。可是因为我觉得把Spring集成到数据加载应用里会带来相当大的工作量。我对DAO对象做了轻微的修改,使得可以在web应用之外使用他们。

例如说在PersonDAO类里面有一个保存person对象的方法。如果Hibernate Session 是由容器建立的,那这个方法就不能在容器外使用,因为这需要一个配置好的Session对象。以下是一个典型的PersonDAO,它由Spring 容器提供了对Session的支持。

清单6:
import org.springframework.orm.hibernate.HibernateTemplate;
import test.pojos.Person;

public class PersonDAO extends HibernateTemplate {

public PersonDAO(){}

public Person save(Person aPerson) {
if(aPerson != null) super.save(person);
return person;
}
}


上面的类继承的是Spring HibernateTemplate 类,它提供了各种不错的使用Hibernate的基类方法。而且由于HibernateTemplate类维护了大多数的常见操作,你就只需要专注特定的持久层需求。当然也应该有相应的异常处理,但在本次范例当中,只要以上的就够了。
现在,要在容器外加上对Session的支持,我们只需要做一些小小的改动:

清单7:
import org.springframework.orm.hibernate.HibernateTemplate;
import net.sf.hibernate.Session;
import test.pojos.Person;

public class PersonDAO extends HibernateTemplate {

public PersonDAO(){}

public void setExternalSessionFactory(Session aSession){
setSessionFactory(session.getSessionFactory());
}

public Person save(Person aPerson) {
if(aPerson != null) super.save(person);
return person;
}
}


因为HibernateTemplate类继承于HibernateAccessor类,我们就可以从任何Session对象中建立SessionFactory。这是Spring小组的一个高灵活性的设计,使得重用现有代码更加容易。
也许你并没有使用Spring而是采用完全不同的方法。如果你不喜欢Spring的一来注射,你也可以通过JNDI查找Session对象:

清单8:
import net.sf.hibernate.Session;

public class PersonDAO {

// This example assumes that there is a Hibernate
// Session object at the following JNDI location
// on a Tomcat 5.5 server:
// java:/comp/env/obj/hibernateSession

private Session session;

public PersonDAO(){
try {
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
session = (Session)envCtx.lookup("obj/hibernateSession");
}catch(Exception e) {
e.printStackTrace();
}
}

public Person save(Person aPerson) {
if(aPerson != null) session.save(person);
return person;
}
}


以上的例子依赖于应用服务器来使得Hibernate Session对象可用。在容器之外使用的最简单方法就是添加一个带Session参数的构造函数,如下所示:

清单9:
import net.sf.hibernate.Session;

public class PersonDAO {

// This example assumes that there is a Hibernate
// Session object at the following JNDI location
// on a Tomcat 5.5 server:
// java:/comp/env/obj/hibernateSession

private Session session;

public PersonDAO(){
try {
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
session = (Session)envCtx. lookup("obj/hibernateSession");
}catch(Exception e) {
e.printStackTrace();
}
}

public PersonDAO(Session aSession){
session = aSession;
}

public Person save(Person aPerson) {
if(aPerson != null) session.save(person);
return person;
}
}


当然我们并没有处理太多的异常,事务问题。甚至我们在多个方法内共用一个Session对象,这会导致一些并发事务问题(取决于容器或框架如何处理对象实例)。不过我想很显然以上的例子演示了如何重用大量的现有数据层代码。只需要一点点有创造力的想法。要弄清楚你是否想在应用服务器之外使用现有的实体和DAO,接下来就不断尝试把。

结论

正如你所见,要在web容器外使用Hibernate 实体和DAO是需要技巧的,但这肯定能做到的。最大的困难在于如何查找实体映射关系和如何重设置(或者说修改)现有的数据访问对象(即DAO)。处理后者时,要小心处理事务问题,因为没有应用服务可以依赖了。不过最后,我们还是可以访问所有的实体和进行持久化的对象,这样能省下大量的重新开发代码的时间。祝您好运!!
分享到:
评论

相关推荐

    在Java SE中使用Hibernate处理数据

    在Java SE环境中使用Hibernate处理数据是一项常见的任务,尤其是在开发企业级应用时,需要对数据库进行高效、灵活的管理和操作。Hibernate作为一个流行的Object-Relational Mapping(ORM)框架,能够简化Java程序员...

    Java EE+hibernate

    #### 五、Hibernate在Java EE中的应用实践 在实际项目中,Hibernate通常作为数据访问层的一部分,与其他Java EE组件紧密结合,共同实现复杂的企业级应用。 - **与Servlets和JSP集成**:利用Servlets接收用户的HTTP...

    企业人事管理系统Java Swing+Hibernate+Oracal

    在企业人事管理系统中,Hibernate负责将业务对象(如员工、部门等)映射到数据库表,通过HQL(Hibernate Query Language)或SQL语句进行数据查询和操作,减少了大量手动编写数据库操作代码的工作量。 Oracle数据库...

    mysql的驱动包,适合使用hibernate和jpa

    MySQL驱动是Java应用程序连接到MySQL数据库的关键组件,特别是在使用Hibernate和JPA这样的对象关系映射(ORM)框架时。这两个框架极大地简化了数据库操作,但它们依赖于合适的数据库驱动来建立连接。本篇文章将深入...

    Windows Java SE Development Kit 8u321

    同时,还需要将bin目录添加到PATH环境变量中,这样可以在任何路径下直接运行Java命令。 对于开发者而言,JDK 8u321不仅提供了一个稳定的开发环境,还通过持续的更新保证了与最新技术的同步。无论是初学者还是经验...

    hibernate中文参考文档

    这部分将介绍如何在Hibernate中执行原生SQL查询。 14. 性能提升:本部分可能包括如何通过合理的配置、查询优化、缓存使用等手段提升Hibernate应用的性能。 15. 工具箱指南:Hibernate提供了许多工具类和实用方法来...

    javaSwing +hibernate+spring苹果界面

    JavaSwing、Hibernate和Spring是Java开发中的三个关键组件,它们在构建用户界面、数据持久化和企业级应用架构方面发挥着重要作用。本项目结合这三个技术,创建了一个苹果风格的用户管理系统,对于学习和理解这些技术...

    在JavaSE下使用HibernateJPA所需的jar包

    在JavaSE环境中使用Hibernate JPA(Java Persistence API)进行数据持久化操作,需要引入一系列的jar包来构建完整的开发环境。这些jar包包含了对JPA规范的实现、Hibernate ORM框架的核心功能以及相关的依赖库。以下...

    Hibernate环境

    在Hibernate中,实体类代表数据库中的表,通常需要使用`@Entity`注解标记。例如,创建一个`User`实体类: ```java import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax....

    hibernate中文开发手册

    《Hibernate中文开发手册》是Java开发者的重要参考资料,它详尽地介绍了如何在Java应用程序中使用Hibernate框架进行对象关系映射(ORM)。Hibernate作为一款流行的开源ORM解决方案,极大地简化了数据库操作,使得...

    Hibernate4中文帮助文档(中文教程)

    在Hibernate中,每个Java类代表一个数据库表,类中的字段对应表中的列。使用`@Entity`注解标记实体类,`@Table`指定对应表名。字段通过`@Id`、`@GeneratedValue`等注解定义主键,其他字段如`@Column`定义列属性。 ...

    Gerador-de-carteirinha-estudantil:Java SE中使用Hibernate和IReport的JPA库开发的系统。 在netbeans IDE 7.4和Mysql数据库上开发。 学生证和标签的生成器,可用于生成员工证章,仅需进行少量更改即可适应所需公司的布局和徽标

    学生证生成器 Java SE中使用Hibernate和IReport的JPA库开发的系统。 在netbeans IDE 7.4和Mysql数据库上开发。 学生证和标签的生成器,可用于生成员工证章,而只需稍作改动即可适应所需公司的布局和徽标。

    Hibernate(session管理)

    首先,理解Session在Hibernate中的角色至关重要。Session是Hibernate的主要工作单元,它是应用程序与数据库之间的桥梁。它负责保存、检索和更新Java对象,同时处理事务和缓存机制。Session对象具有短暂性,通常在一...

    Hibernate3.6中文API帮助文档

    1. 实体类:在Hibernate中,业务对象被称为实体类,它们通过@Entity注解标记,并使用@Id注解指定主键。 2. 映射文件或注解:使用.hbm.xml文件或@Entity、@Table、@Column等注解来定义实体类与数据库表的映射关系。 3...

    hibernate的jar包

    下面将详细介绍Hibernate框架的核心组件、功能以及如何在项目中使用Hibernate的jar包。 1. Hibernate核心组件: - Hibernate Core:这是Hibernate的核心模块,包含了对持久化对象的基本支持,如Session接口、...

    hibernate实例

    2. 实体类的定义:在Hibernate中,首先需要定义实体类,实体类即为映射到数据库表的Java类。通常实体类会包含一些基本的属性以及对应的getter和setter方法。 以文档中提供的User实体类为例,它包含了id、username、...

    hibernate4使用JPA所需要的jar包

    在Java世界中,Hibernate是一个非常流行的对象关系映射(ORM)框架,它使得开发者能够用面向对象的方式来操作数据库。而JPA(Java Persistence API)是Java标准,为应用程序提供了一种统一的方式来管理持久化对象。...

    Hibernate4实战.pdf

    因此,文档很可能是为那些希望从基础开始学习Hibernate,并希望在实际项目中有效地使用Hibernate的开发者设计的。 另外,文档中还包含了关于Java程序员薪资的讨论和学习方法的建议,这虽然与Hibernate直接相关性...

    hibernate validator 校验器

    - UnifiedEL:统一表达式语言,Hibernate Validator支持在表达式中使用校验注解。 - CDI:上下文依赖注入,Hibernate Validator可以与CDI无缝集成,便于在应用中管理校验器的生命周期。 - 安全管理器:可以在有...

    Java SE图书管理系统项目.zip

    在这个图书管理系统中,Java SE 提供了编程语言和类库,使得开发者可以构建功能丰富的应用程序。 2. **MVC设计模式**: Model-View-Controller (MVC) 是一种常见的软件设计模式,用于分离业务逻辑、数据模型和用户...

Global site tag (gtag.js) - Google Analytics