5

我正在处理一个门户项目,我被迫使用 WebSphere Portal、Spring portlet MVC 和 Hibernate。我在配置 Spring 和 Hibernate 方面都没有太多经验,因此非常感谢各种帮助。
我在 WebSphere 7.0.0.25(安装了 Portal 6.1)上创建了一个 JNDI 名称为 jdbc/eshop 的 JDBC 数据源。然后我指定了 JAAS 身份验证别名并将其设置为容器管理的身份验证别名。测试连接尝试成功,所以我猜数据源的配置是合适的。我的下一步是在 web.xml 中进行资源引用:

<resource-ref>    
    <description>DB Connection</description>    
    <res-ref-name>eshop</res-ref-name>   
    <res-type>javax.sql.DataSource</res-type>    
    <res-auth>Container</res-auth>   
</resource-ref>

为了将 res-ref-name 绑定到 ibm-web-bnd 中的实际 JNDI 名称,我添加了这一行:

<resource-ref name="eshop" binding-name="java:comp/env/jdbc/eshop" />

现在我的休眠实体:

@Entity
@Table(name = "HIBERNATE_TEST", schema = "SCHEME_NAME")
public class HibernateTest implements java.io.Serializable {

private short id;
private String text;

public HibernateTest() {
}

public HibernateTest(String text) {
    this.text = text;
}


@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "ID")
public short getId() {
    return this.id;
}

public void setId(short id) {
    this.id = id;
}

@Column(name = "TEXT", nullable = false, length = 10)
public String getText() {
    return this.text;
}

public void setText(String text) {
    this.text = text;
}

休眠测试DAO:

@Repository("hibernateTestDAO")
@Transactional
public class HibernateTestDAO  implements GenericDAO<HibernateTest> {
@Autowired
private SessionFactory sessionFactory;

private Session sess;

public HibernateTestDAO ()  {

}

public SessionFactory getSessionFactory() {
    return sessionFactory;
}

public void setSessionFactory(SessionFactory sf) {
    sessionFactory = sf;
}

public boolean add(HibernateTest item) {
    boolean isAdded = false;
    try {
        sess = sessionFactory.getCurrentSession();
        sess.persist(item);
        isAdded =  true;
    } catch (Exception e) {
        e.printStackTrace();
    } 
    return isAdded;
}

public boolean edit(HibernateTest item) {
    boolean isEdited = false;
    try {
        sess = sessionFactory.getCurrentSession();
        item = (HibernateTest)sess.merge(item);
        sess.update(item);
        isEdited =  true;
    } catch (Exception e) {
        e.printStackTrace();
    } 
    return isEdited;
}

public boolean delete(HibernateTest item) {
    boolean isDeleted = false;
    try {
        sess = sessionFactory.getCurrentSession();
        item = (HibernateTest)sess.merge(item);
        sess.delete(item);
        isDeleted =  true;
    } catch (Exception e) {
        e.printStackTrace();
    } 
    return isDeleted;
}

@SuppressWarnings("unchecked")
@Override
@Transactional(readOnly = true)
public List<HibernateTest> getAll() {
    List<HibernateTest> l = new ArrayList<HibernateTest>(0);
    try {
        sess = sessionFactory.getCurrentSession();
        Query q = sess.createQuery("FROM HibernateTest");
        l = (List<HibernateTest>) q.list();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return l;
}

@Override
@Transactional(readOnly = true)
public HibernateTest getByID(long id) {
    try {
        sess = sessionFactory.getCurrentSession();
        return (HibernateTest)sess.get(HibernateTest.class, new Short((short)id));
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
}

如您所见,我不想使用程序管理的事务。我了解到,Spring 有 WebSphereUowTransactionManager 类来管理 WebSphere 数据源的事务。我试过这个配置(applicationContext.xml):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd    
    http://www.springframework.org/schema/jee
    http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <context:annotation-config /> 
    <context:component-scan base-package="test.dao,test.entities,test.portlet.controller" />

        <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="jdbc/eshop"/>
    <property name="lookupOnStartup" value="false"/>
    <property name="cache" value="true" />
    <property name="proxyInterface"  value="javax.sql.DataSource" />
    </bean>

    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory"     class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="annotatedClasses">
        <list>
            <value>test.entities.HibernateTest</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
          <prop key="hibernate.dialect">org.hibernate.dialect.DB2Dialect</prop>
          <prop key="hibernate.show_sql">true</prop>
          <!--           IBM WAS SPECIFIC             -->          
          <prop key="hibernate.connection.datasource">jdbc/eshop</prop>
          <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory</prop>
          <prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</prop>
          <prop key="hibernate.transaction.jta.platform">org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform</prop> 
          <!--           /END IBM WAS SPECIFIC        -->
        </props>
    </property>
    </bean>

    <bean id="transactionManager"
    class="org.springframework.transaction.jta.WebSphereUowTransactionManager">
        <property name="userTransactionName" value="java:comp/UserTransaction" />
    </bean>  

    <bean id="hibernateTestDAO" class="test.dao.HibernateTestDAO" /> 

    </beans> 

,但它会导致这个异常链:

错误 500:org.springframework.beans.factory.BeanCreationException:在 ServletContext 资源 [/WEB-INF/applicationContext.xml] 中定义名称为“transactionManager”的 bean 创建错误:调用 init 方法失败;嵌套异常是 org.springframework.transaction.TransactionSystemException:JTA UserTransaction 在 JNDI 位置 [java:comp/UserTransaction] 不可用;嵌套异常是 org.springframework.jndi.TypeMismatchNamingException:JNDI 位置 [java:comp/UserTransaction] 上可用的类型 [class com.ibm.ws.tx.jta.UserTransactionImpl] 的对象不可分配给 [javax.transaction.UserTransaction]

我知道这种情况下的典型解决方案是从类路径中删除 jta.jar,但我的类路径中没有这个 jar!我只是不明白 IBM 如何使用一些特定于供应商的库来创建 UserTransaction 类,但我应该让它工作,所以我需要你的帮助来配置我的应用程序。

另外我想补充一点,我在这个问题上工作了大约 3 天,尝试了不同的配置,但遗憾的是没有成功。所以我决定使用来自这个来源的工作(如作者所说)配置作为在这里提出问题的起点。我已经没有办法解决这个问题了,所以我需要帮助。

更新

我可以通过 Hibernate 对当前事务的抱怨来解决问题:没有<tx:annotation-driven transaction-manager="transactionManager" />指定元素,所以我想 UOWManager 不知道我希望何时开始事务。但事实证明,这并不是我困难的结束。portlet 控制器的代码如下:

public class TestDIController extends AbstractController implements ApplicationContextAware{

private ApplicationContext appCtx;

@Override
public ModelAndView handleRenderRequest(RenderRequest request,
        RenderResponse response) throws Exception {
    appCtx = getApplicationContext();
    System.out.println(UserTransaction.class.getClassLoader());
    @SuppressWarnings("rawtypes")
    GenericDAO cd = (GenericDAO)appCtx.getBean("hibernateTestDAO");
    ModelAndView m = new ModelAndView("test").addObject("list", cd.getAll());
    return m;
}
}

当 ModelAndView 实例尝试向自己添加新对象时,HibernateTestDAO 的代码行l = (List<HibernateTest>) q.list();抛出以下异常

org.hibernate.exception.SQLGrammarException:无法打开连接

...一些堆栈跟踪...

原因:java.sql.SQLException: [jcc][t4][10205][11234][3.58.81] 不支持空用户标识。ERRORCODE=-4461,SQLSTATE=42815DSRA0010E: SQL 状态 = 42815,错误代码 = -4 461

而且这个错误比较混乱,因为我已经指定了Container-managed authentication alias,见下图

在此处输入图像描述 其中 'auth' 是我的 JAAS-J2C 身份验证别名。当我从管理控制台测试到数据源的连接时,它总是成功的!我尽我所能寻找这个问题的答案,但在这一点上没有结果。例如,这里描述的问题与我的非常相似,但解决方案不适合我,因为该元素<lookup-name>在我的 web.xml 中未定义。可能是我应该在 WebSphere 上配置一些 J2C 选项、资源适配器,可能是 applicationContext 中缺少一些配置行,谁能帮忙?这次我真的很困惑。

4

1 回答 1

5

com.ibm.ws.tx.jta.UserTransactionImpl实现javax.transaction.UserTransaction。你的代码很好。很可能您正在使用 parent-last ClassLoader 策略并且javax.transaction.UserTransaction在您的应用程序中的一个 jar 中。

javax.transaction.UserTransaction尝试从您的应用程序中摆脱它。

于 2012-11-08T20:55:32.513 回答