幻境
We are extremely fortunate not to know precisely the kind of world we live in
posts - 22,comments - 39,trackbacks - 0

 

关于这个话题,javaeye其实有一篇文章专门介绍了(http://www.javaeye.com/viewtopic.php?t=245),但是可能不是很详细,最近也有一些人我这方面的问题,所以在这里重新介绍一下。不过我还是推荐你在看本文之前首先看一下上面提到的那篇文章。


首先说明一下我们这里使用的程序,为了更容易理解,我们使用hibernate文档(英文版: http://www.hibernate.org/hib_docs/v3/reference/en/html/ 中文版:http://www.hibernate.org/hib_docs/v3/reference/zh-cn/html/)中刚开始介绍与Tomcat进行整合时候的那个程序,不过把包名改了一下。


为了更加清晰,我仍然把代码贴在下面:

 1 package example;
 2 
 3 public class Cat {
 4 
 5     private String id;
 6     private String name;
 7     private char sex;
 8     private float weight;
 9 
10     public Cat() {
11     }
12 
13     public String getId() {
14         return id;
15     }
16 
17     private void setId(String id) {
18         this.id = id;
19     }
20 
21     public String getName() {
22         return name;
23     }
24 
25     public void setName(String name) {
26         this.name = name;
27     }
28 
29     public char getSex() {
30         return sex;
31     }
32 
33     public void setSex(char sex) {
34         this.sex = sex;
35     }
36 
37     public float getWeight() {
38         return weight;
39     }
40 
41     public void setWeight(float weight) {
42         this.weight = weight;
43     }
44 
45 }
46 

还有就是Cat.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>

<hibernate-mapping>

    
<class name="example.Cat" table="CAT">

        
<!-- A 32 hex character is our surrogate key. It's automatically
            generated by Hibernate with the UUID pattern. 
-->
        
<id name="id" type="string" unsaved-value="null" >
            
<column name="CAT_ID" sql-type="char(32)" not-null="true"/>
            
<generator class="uuid.hex"/>
        
</id>

        
<!-- A cat has to have a name, but it shouldn' be too long. -->
        
<property name="name">
            
<column name="NAME" length="16" not-null="true"/>
        
</property>

        
<property name="sex"/>

        
<property name="weight"/>

    
</class>

</hibernate-mapping>



关于数据库表的建立,在这里就不再赘述了。

下面我们分成几步来介绍,为了介绍方便,我们假设你现在有一个weblogic配置在D:\bea\user_projects\domains\mydomain下。

1.      设置classpath,

A.      hibernate本身需要一些jar(到底需要哪些jar可以参照hibernate文档),你需要在classpath里面引入这些jar。另外你还会写这个方法也仍然是修改startWeblogic.cmd。举例来讲,假如你把这些jar拷贝到了D:\bea\user_projects\domains\mydomain\lib,那么可以在startWeblogic.cmd中添加这样两句话:

set HIBERNATE_LIB=D:\bea\user_projects\domains\mydomain\lib

set ClASSPATH=%HIBERNATE_LIB%\antlr-2.7.5H3.jar;%HIBERNATE_LIB%\asm-attrs.jar;%HIBERNATE_LIB%\cglib-2.1.jar;%HIBERNATE_LIB%\commons-collections-2.1.1.jar;%HIBERNATE_LIB%\commons-logging-1.0.4.jar;%HIBERNATE_LIB%\concurrent-1.3.2.jar;%HIBERNATE_LIB%\dom4j-1.6.jar;%HIBERNATE_LIB%\jaas.jar;%HIBERNATE_LIB%\jacc-1_0-fr.jar;%HIBERNATE_LIB%\jaxen-1.1-beta-4.jar;%HIBERNATE_LIB%\log4j-1.2.9.jar;%HIBERNATE_LIB%\xml-apis.jar;%HIBERNATE_LIB%\asm.jar;%HIBERNATE_LIB%\hsqldb.jar;%HIBERNATE_LIB%\hibernate3.jar;lib\classes;%HIBERNATE_LIB%\ehcache-1.1.jar;%CLASSPATH%

B.      设置你编译后的程序目录,我们这里假设假如你编译后的代码在D:\bea\user_projects\domains\mydomain\classes下,那么仍然是参照上面的方法,在startWeblogic.cmd中添加这样两句话:

set MY_CLASSES=D:\bea\user_projects\domains\mydomain\classes

set ClASSPATH=%MY_CLASSES%;%CLASSPATH%

这样classpath导入的工作就完成了。

2.      打开Weblogic Administration Console   ,然后配置好你的连接池和datasource,这里我使用datasource的JNDI Name用了mydatasource

3.      书写hibernate配置文件,大家都知道hibernate配置文件可以写成xml也可以写成properties的形式,这里我使用的是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>      
        
<!-- SQL dialect -->
        
<property name="dialect">org.hibernate.dialect.Oracle9Dialect</property>
        
<!-- Echo all executed SQL to stdout -->
        
<property name="show_sql">true</property>         
        
<property name="connection.datasource">mydatasource</property>
         
<property name="session_factory_name">hibernate.quickstart</property>
        
<property name="transaction.manager_lookup_class">org.hibernate.transaction.WeblogicTransactionManagerLookup
</property>
         
<mapping resource="example/Cat.hbm.xml" />
    
</session-factory>
</hibernate-configuration>

配置时需要注意的就是session_factory_name中使用了一个点来代替/,也就是hibernate.quickstart,实际程序lookup时候仍然使用hibernate/quickstart

    至于transaction.manager_lookup_class如果你不打算用JTA可以不配。

4.      WebLogic的启动类,WebLogic的启动类需要实现weblogic.common.T3StartupDef接口,编程时候你要引入这个接口,可以通过引入weblogic.jar实现。假如你weblogic安装在D:\bea下面,你可以在相应的weblogic81\server\lib下找到这个jar。其实只是获得SessionFactory,hibernate会自动绑定到相应的JNDI name上的。

package example;

import java.util.Hashtable;

import org.apache.log4j.Logger;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import weblogic.common.T3ServicesDef;
import weblogic.common.T3StartupDef;

public class StartHibernateConfig
    implements T3StartupDef
{

    
private Logger log = Logger.getLogger(StartHibernateConfig.class);
    
public String startup(String arg0, Hashtable arg1)
        throws Exception
    {
        Configuration config 
= new Configuration().configure();
        SessionFactory sf 
= config.buildSessionFactory();
         
        log.info(
"Initial hibernate SessionFactory successfully,sf:" + sf);

        
return "Initial hibernate SessionFactory successfully";
    }

    
public void setServices(T3ServicesDef t3servicesdef)
    {
    }

}

5.      仍然是在Weblogic Administration Console中,从左边的applet树中找到StartUp & Shutdown,然后选择Configure a new Startup Class...,按照提示一步一步配置就可以了。然后重启一下Weblogic

6.      到这里为止,所有的配置工作就完成了,你可以在程序里面使用Hibernate了。


 

下面是一些关于编程的简单介绍。


如果不使用JTA,比如在一个servlet中可以这样写

Context ctx=new InitialContext();
SessionFactory sessions
=(SessionFactory)ctx.lookup("hibernate/quickstart");
Session sess 
= factory.openSession();
Transaction tx 
= null;
try {
    tx 
= sess.beginTransaction();

    
// do some work
    

    tx.commit();
}
catch (RuntimeException e) {
    
if (tx != null) tx.rollback();
    
throw e; // or display error message
}
finally {
    sess.close();
}

使用BMT的话其实写法和上面是一样的。

如果使用CMT,那么你的程序里面就不需要自己管理事务,容器会替你完成的。

另外在获得Session的时候可以使用SessionFactory的getCurrentSession()方法。

 

下面我们通过一个完整的SLSB的例子来看一下。这里仍然使用了我们在前面提到过的Cat。

首先是需要的java程序:


Remote Interface:

package example;

import java.rmi.RemoteException;
import javax.ejb.EJBObject;
import javax.naming.NamingException;

public interface Sample extends EJBObject {
    
    
public String countCats() throws RemoteException,NamingException;
    
}

Home Interface:

package example;

import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;

public interface SampleHome extends EJBHome {
    
    
public Sample create() throws RemoteException,CreateException;
    
}

Bean Class:

package example;

import java.rmi.RemoteException;
import java.util.List;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

public class SampleBean implements SessionBean {

    
private Logger log = Logger.getLogger(SampleBean.class);

    
private SessionContext sctx;

    
public void setSessionContext(SessionContext ctx) throws EJBException,
            RemoteException {

    }

    
public void ejbCreate() throws EJBException, RemoteException {
    }

    
public void ejbRemove() throws EJBException, RemoteException {
    }

    
public void ejbActivate() throws EJBException, RemoteException {
    }

    
public void ejbPassivate() throws EJBException, RemoteException {
    }

    
public String countCats() throws RemoteException, NamingException {
        Context ctx 
= new InitialContext();
        SessionFactory sf 
= (SessionFactory) ctx.lookup("hibernate/quickstart");
        Session s 
= sf.getCurrentSession();
        
try {
            List ls 
= s.createQuery("from example.Cat").list();
            String x 
= String.valueOf(ls.size());
            log.info(
"length:" + x);
            
return x;
        } 
catch (RuntimeException e) {

        } 
finally {
            s.close();
        }
        
return null;

    }
}


这段程序一个特殊的地方就是我们使用sf.getCurrentSession ()来得到一个Session对象,另外一个就是没有在里面手动地处理事务。当然这只是一个查询而已,不过其他的程序写法都是类似的。

ejb-jar.xml

<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd"> 
<ejb-jar> 
    
<enterprise-beans> 
        
<session> 
            
<ejb-name>SampleObject</ejb-name>     
            
<home>hh.SampleHome</home> 
            
<remote>hh.Sample</remote> 
            
<ejb-class>example.SampleBean</ejb-class> 
            
<session-type>Stateless</session-type> 
            
<transaction-type>Container</transaction-type> 
    
        
</session> 
    
</enterprise-beans> 
    
<assembly-descriptor>
        
<container-transaction>
            
<method>
                
<ejb-name>SampleObject</ejb-name>
                   
<method-name>*</method-name>
            
</method>
            
<trans-attribute>Required</trans-attribute>
        
        
</container-transaction>
    
</assembly-descriptor>
</ejb-jar>

 

weblogic-ejb-jar.xml:

<!DOCTYPE weblogic-ejb-jar PUBLIC '-//BEA Systems, Inc.//DTD WebLogic 8.1.0 EJB//EN' 'http://www.bea.com/servers/wls810/dtd/weblogic-ejb-jar.dtd'> 
<weblogic-ejb-jar> 
    
<weblogic-enterprise-bean> 
        
<ejb-name>SampleObject</ejb-name>
        
<jndi-name>SampleObject</jndi-name> 
    
</weblogic-enterprise-bean> 
</weblogic-ejb-jar>


最后是我们的客户端程序:


package example;


import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;

public class TestClient {
    
/**
     * @param args
     
*/
    
public static void main(String[] args) {

        Properties p
=new Properties();
        p.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
        p.put(Context.PROVIDER_URL,
"t3://localhost:7001");      
        
try {
            Context initial
=new InitialContext(p);
            Object obj
=initial.lookup("SampleObject");          
            SampleHome sample
=(SampleHome) PortableRemoteObject.narrow(obj,SampleHome.class);           
            Sample s
=sample.create();           
            System.
out.println("We have " + s.countCats() + " cat(s).");
            
        } 
catch (Exception e)
        {
           e.printStackTrace();
        }
        
    }

}


 

运行后就可以看到表中的记录条数。

 

posted on 2005-07-11 19:17 阅读(4486) 评论(3)  编辑  收藏 所属分类: 编程相关

FeedBack:
# re: 在WebLogic中使用Hibernate
2006-03-28 18:37 | maidongdong
请问一些问题:

我的一个项目(struts+hibernate+weblogic),在struts的DemoAction中通过DAO(DemoDAOFactory,其中封装了对表Demo的相关操作)访问数据库,我也用到了上面的启动类(HibernateStartUp,并且也在weblogic控制台中实施了部署),一切工作就绪。
所有的文件也都放到了如下相应的目录:
d:\bea\user_project\domain\mydomain\application\myapp\WEB-INF\
下(包括HibernateStartUp,也放到了该目录对应的classes对应的包文件夹下面)。

但是,启动weblogic的时候,报错:无法找到HibernateStartUp类。
首先,对于web项目,应用服务器对于用到的类不是就会到WEB-INF\lib或者到
WEB-INF\classes中去找吗?为什么HibernateStartUp类他会找不到呢,
对于应用服务器是如何把WEB-INF\lib和WEB-INF\classes放到classpath中的,我实在不甚明白(查遍了startWeblogic.cmd SetEnv.cmd 等一些相关的启动文件,都找不到)

其次,如果照上面你说的做的话(即在startWeblogic.cmd中增加set Hibernate_lib set my_classes等等),应用服务器还用到WEB-INF\classes和WEB-INF\lib中相应的类吗?这样,启不是相当于把类的路径给重定向了。

望你指破其中玄机?  回复  更多评论
  
# re: 在WebLogic中使用Hibernate
2008-03-12 20:18 | jarrywen
这么好的问题竟然没有人回答,我也想要这样的一个好的解决方法。这是weblogic classloaderd的机制问题,ejb加载的classloader比web高一个级别,没法向下加载web的classloader,而web可以向上找到ejb的jar。
  回复  更多评论
  
# re: 在WebLogic中使用Hibernate
2008-03-12 20:20 | jarrywen
其次,如果照上面你说的做的话(即在startWeblogic.cmd中增加set Hibernate_lib set my_classes等等),应用服务器还吗?这样,启不是相当于把类的路径给重定向了。

《-----不指定,应用服务器不会去用到WEB-INF\classes和WEB-INF\lib中相应的类

但是web服务器可能变成加载了两次,不过好像也没有好的办法  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: