在Java SE中使用Hibernate框架

来源:百度文库 编辑:神马文学网 时间:2024/04/26 15:58:53
在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=dbuserhibernate.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// 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 对象里配置好正确的映射关系,我们就可以将实体拿来使用了。