我正在开发一个门户项目,我不得不使用WebSphere Portal,Spring portlet MVC和Hibernate。我在配置Spring和Hibernate方面没有太多经验,因此非常感谢各种帮助 我在WebSphere 7.0.0.25(安装了Portal 6.1)上创建了一个JDBC数据源,其中JNDI名称为jdbc / eshop。然后我指定了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>
要在ibm-web-bnd中将res-ref-name绑定到实际的JNDI名称,我添加了这一行:
<resource-ref name="eshop" binding-name="java:comp/env/jdbc/eshop" />
现在我的Hibernate实体:
@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;
}
HibernateTestDAO:
@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]上可用的类型[类com.ibm.ws.tx.jta.UserTransactionImpl]的对象不能赋予[javax.transaction.UserTransaction]
我知道这种情况下的典型解决方案是从类路径中删除jta.jar,但我在类路径中没有这个jar! 我只是不知道IBM如何使用某些特定于供应商的库来创建UserTransaction类,但我应该这样做,所以我需要你的帮助来配置我的应用程序。
另外我想补充一点,我解决了这个问题大约3天,尝试了不同的配置,但遗憾的是没有成功。所以我决定使用this source中的一个工作(作为作者说)配置作为起点来问这里的问题。我试图解决这个问题已经用尽了,所以我需要帮助。
更新
我可以解决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
此错误令人困惑,因为我已指定容器管理的身份验证别名,请参阅下面的图片
其中'auth'是我的JAAS-J2C认证别名。
当我从管理控制台测试与数据源的连接时,它总是成功的!我尽力寻找答案,但到目前为止没有结果。例如,problem described here与我的完全相同,但解决方案不适合我,因为我的web.xml中未定义元素<lookup-name>
。
可能是我应该在WebSphere上配置一些J2C选项,资源适配器,可能是applicationContext中有一些错过的配置行,谁可以提供帮助?这次我真的很困惑。
答案 0 :(得分:5)
com.ibm.ws.tx.jta.UserTransactionImpl
实施javax.transaction.UserTransaction
。你的代码很好。很可能你正在使用父级最后一个ClassLoader策略,并且在你的应用程序的一个jar中有javax.transaction.UserTransaction
。
尝试从您的应用程序中删除javax.transaction.UserTransaction
。