发生问题的情况与上次的差不多,可以参考一下�
在我的EJB的应用中,都是使用CMT,并且Transaction Attribute设为Required� Method可以成功执行到最后一句,我的程序执行完毕后应该由WAS负责Commit Transaction的,但是我的程序执行完之后WAS或者VAJ4的WTE会不Commit,并且整个Table都被锁住了(我用了Find for update,即写锁,可能与这有关,但是这是建议的,用来避免Deadlock。),WAS没有继续执行下去,就是不Commit,整个Bean就挂在那里�
我的bean其实非常简单,一种是stateless session bean,一种是cmp bean。前者通过调用JDBC(通过一些自己写的DAO类)访问数据库,也调用后者的方法由WAS访问(CMP)数据库。所有这些方法独立调用时经过测试都是没有问题的。但是如果有一个stateless session bean中的方法,同时调用使用JDBC的和使用CMP的方法来共同完成一项功能,就可能出现问题。一种是先前提到的TransactionRollback的问题(已经解决,方法是enable jdbc driver JTA support,虽然我认为不需要这样的,因为都是同一个datasource,根据ibm 的redbook,多个datasource才需要,原因是要用XA,所以应该也算是一个小bug,不过我enable之后的确解决了);另一种是今天碰到的,EJB死了(因此我的客户端也死了),Table被锁住了,并且没有任何Exception抛出,经过深入的跟踪,发现WAS没有执行完成所有的他应该执行的功能,执行到beforeCompletion就停止了(这个方法本身就还没有执行完返回)。还有我对EJB的Transaction和Session都设置了60秒的timeout,但是过�5分钟都没反映,可见死的还真彻底�
我觉得会不会是EJB对两种Transaction的处理是不同的,一种是JDBC Transaction,另一种是JTA(CMP用的应该是JTA)。因为多个同样是JDBC的方法在一个Transaction里面是不会出现问题的,同样多个CMP(JTA)的也没有问题。(但是JDBC也可以用JTA的吧,否则BMP用什么?这是其中一个我想不明白的地方。)
J2EE的文档里面提到有些方法在CMT不能使用�,如getUserTransaction, Connection的commit, rollback, setAutoCommit等,我都已经避免了。但是文档中并没有说明不能把CMP和通过JDBC访问的Stateless bean混用。所以,这究竟是WAS的BUG,EJB的限制,还是我的方法错了?希望是后者,否则我就惨了,几十个Bean要重写。所以希望大家帮帮手,看看有没有解决的方法�
不知道用BMP能否解决这个问题,但是BMP也不能满足我们项目的要求,EntityBean始终是太弱了(我们的某些方法甚至连要访问那一张表都是实际应用时才能确定的,不适合用EntityBean,只能用JDBC,但是也有不少适合用的,难道通过JDBC访问DB的Stateless session bean和CMP就没有一种更好的共存方法?)�
多谢大家先!
测试环境�
Win2000 Server+WebSphere3.5.5+DB2 7.1+VAJ4EEE
这里是部分的Trace log。附件有详细的Trace log和standard out,没有出错所以没有standard err�
[02.04.04 19:25:02:156 CST] f5f31043 ContainerTx > postInvoke
[02.04.04 19:25:02:156 CST] f5f31043 ContainerTx < postInvoke
[02.04.04 19:25:02:156 CST] f5f31043 EJSContainer < postInvoke
[02.04.04 19:25:02:156 CST] f5f31043 WrapperManage > postInvoke
[02.04.04 19:25:02:156 CST] f5f31043 WrapperManage < postInvoke
[02.04.04 19:25:02:250 CST] f5f31043 CMStatelessBe > getRollbackOnly
[02.04.04 19:25:02:250 CST] f5f31043 EJSContainer > getCurrentTx
[02.04.04 19:25:02:250 CST] f5f31043 EJSContainer > getCurrentTx
[02.04.04 19:25:02:250 CST] f5f31043 EJSContainer > getCurrentTx
[02.04.04 19:25:02:250 CST] f5f31043 EJSContainer > getCurrentTx
[02.04.04 19:25:02:250 CST] f5f31043 CMStatelessBe < getRollbackOnly
[02.04.04 19:25:02:500 CST] f5f31043 EJSContainer > postInvoke
[02.04.04 19:25:02:500 CST] f5f31043 Activator > postInvoke
com.ibm.ejs.container.ContainerTx@5d49104b
BeanId(com/pdc/gwis/session/CoreManager, )
[02.04.04 19:25:02:500 CST] f5f31043 UncachedActiv > atPostInvoke
com.ibm.ejs.container.ContainerTx@5d49104b
BeanId(com/pdc/gwis/session/CoreManager, )
[02.04.04 19:25:02:500 CST] f5f31043 UncachedActiv < atPostInvoke
[02.04.04 19:25:02:500 CST] f5f31043 Activator < postInvoke
[02.04.04 19:25:02:500 CST] f5f31043 ContainerTx > postInvoke
[02.04.04 19:25:02:500 CST] f5f31043 ContainerTx < postInvoke
[02.04.04 19:25:02:546 CST] f5f31043 ContainerTx > beforeCompletion
[02.04.04 19:25:28:578 CST] 314d104c StatefulBeanR D StatefulBeanReaper thread waking up
[02.04.04 19:25:28:578 CST] 314d104c StatefulBeanR D StatefulBeanReaper thread going to sleep
[02.04.04 19:26:28:578 CST] 314d104c StatefulBeanR D StatefulBeanReaper thread waking up
[02.04.04 19:26:28:578 CST] 314d104c StatefulBeanR D StatefulBeanReaper thread going to sleep
[02.04.04 19:27:28:578 CST] 314d104c StatefulBeanR D StatefulBeanReaper thread waking up
[02.04.04 19:27:28:578 CST] 314d104c StatefulBeanR D StatefulBeanReaper thread going to sleep
[02.04.04 19:28:28:578 CST] 314d104c StatefulBeanR D StatefulBeanReaper thread waking up
[02.04.04 19:28:28:578 CST] 314d104c StatefulBeanR D StatefulBeanReaper thread going to sleep
(到这里已经彻底死了,可以看到在ContainerTx > beforeCompletion这里没有执行成功并返回,不知是不是等待某些资源的释放,但是我的应用应该不会死锁的,只有一个update,也只有一个测试的client。但是无论如�,was应该抛出错误的。)
附上次的问题�
我在项目的EJB使用中碰到一个问题,请大家帮忙看看有没有办法解决�
在下面的两个EJB的应用中,都是使用CMT,并且Transaction Attribute设为Required� 成功执行到最后一句,但是执行完之后WAS或者VAJ4的WTE会自动roll back,并抛出一个TransactionRolledbackException。这两个bean其实非常简单,一个是stateless session bean,一个是cmp bean。前者有4个方法,其中两个通过JDBC访问数据库的方法(test1, test2),另有一个利用后�(CMP)访问数据库的方法(test3),最后一个是调用这三个方法的方法(test)。对test1,test2,test3分别调用都是完全没有问题的。而且如果从test中注释掉对第三个方法的调用,则不会出现问题。唯一会出现问题的是三个方法同时调用(在一个方法里面)的时候�
我觉得会不会是EJB对两种Transaction的处理是不同的,一种是test1和test2的JDBC Transaction,另一种是test3的JTA(CMP用的应该是JTA)。因为多个同样是JDBC的方法在一个Transaction里面是不会出现问题的,同样多个JTA的也没有问题。(但是JDBC也可以用JTA的吧,否则BMP用什么?这是其中一个我想不明白的地方。)
J2EE的文档里面提到有些方法在CMT不能使用�,如getUserTransaction, Connection的commit, rollback, setAutoCommit等,我都已经避免了。但是文档中并没有说明不能把CMP和通过JDBC访问的Stateless bean混用。所以,这究竟是WAS的BUG,EJB的限制,还是我的方法错了?希望是后者,否则我就惨了,几十个Bean要重写。所以希望大家帮帮手,看看有没有解决的方法�
不知道用BMP能否解决这个问题,但是BMP也不能满足我们项目的要求,EntityBean始终是太弱了(我们的某些方法甚至连要访问那一张表都是实际应用时才能确定的,不适合用EntityBean,只能用JDBC,但是也有不少适合用的,难道通过JDBC访问DB的Stateless session bean和CMP就没有一种更好的共存方法?)�
如果你们碰到过类似的问题,或者知道解决办法,大家交流一下,建议也可以。如果有Websphere的专家推荐给我就更好了。多谢大家先�
测试环境�
Win2000 Server+WebSphere3.5.5+DB2 7.1+VAJ4EEE
下面是我的测试代码,与我的项目的某些应用相似,但是简单很多很多,供大家参考�
//the first ejb, a stateless session bean. Use CMT, and transaction attribute is set to required
package com.test.ejb;
import java.rmi.RemoteException;
import java.security.Identity;
import java.util.Properties;
import javax.ejb.*;
import java.sql.*;
import javax.naming.*;
import javax.rmi.*;
import com.pdc.common.Debug;
import com.pdc.common.Utility;
import com.pdc.common.database.*;
import com.test.ejb.*;
/**
* This is a Session Bean Class
*/
public class testJdbc1EJB implements SessionBean {
private javax.ejb.SessionContext mySessionCtx = null;
private final static long serialVersionUID = 3206093459760846163L;
private ConnectionManager cm = ConnectionManager.getInstance();
/**
* ejbActivate method comment
* @exception java.rmi.RemoteException The exception description.
*/
public void ejbActivate() throws java.rmi.RemoteException {}
/**
* ejbCreate method comment
* @exception javax.ejb.CreateException The exception description.
* @exception java.rmi.RemoteException The exception description.
*/
public void ejbCreate() throws javax.ejb.CreateException, java.rmi.RemoteException {}
/**
* ejbPassivate method comment
* @exception java.rmi.RemoteException The exception description.
*/
public void ejbPassivate() throws java.rmi.RemoteException {}
/**
* ejbRemove method comment
* @exception java.rmi.RemoteException The exception description.
*/
public void ejbRemove() throws java.rmi.RemoteException {}
/**
* Set up a database connection.
* Creation date: (3/26/2002 6:46:33 PM)
* @return java.sql.Connection the database connection.
* @exception java.sql.SQLException Cannot set up a data base connection.
*/
private Connection getConnection() throws java.sql.SQLException {
Connection con = cm.getConnection();
//con.setAutoCommit(false);
//con.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
return con;
}
/**
* getSessionContext method comment
* @return javax.ejb.SessionContext
*/
public javax.ejb.SessionContext getSessionContext() {
return mySessionCtx;
}
/**
* setSessionContext method comment
* @param ctx javax.ejb.SessionContext
* @exception java.rmi.RemoteException The exception description.
*/
public void setSessionContext(javax.ejb.SessionContext ctx) throws java.rmi.RemoteException {
mySessionCtx = ctx;
}
/**
* Insert the method's description here.
* Creation date: (4/2/2002 4:47:28 PM)
*/
public void testJdbc() {
Debug.log("Result of test 1:" + testJdbc01());
Debug.log("Result of test 2:" + testJdbc02());
//if the following line is commented, no exception will be thrown
Debug.log("Result of test 3:" + testJdbc03());
}
/**
* Insert the method's description here.
* Creation date: (4/2/2002 4:47:07 PM)
* @return int
*/
public int testJdbc01() {
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
int result = -1;
try {
con = getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery("select count(*) as count from t_work_items");
if (rs.next())
result = rs.getInt(1);
Debug.log("Result:" + result);
} catch (SQLException e) {
e.printStackTrace();
} finally {
Utility.cleanup(con, stmt, rs);
}
return result;
}
/**
* Insert the method's description here.
* Creation date: (4/2/2002 4:47:16 PM)
* @return int
*/
public int testJdbc02() {
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
int result = -1;
try {
con = getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery("select count(*) as count from t_work_queues");
if (rs.next())
result = rs.getInt(1);
Debug.log("Result:" + result);
} catch (SQLException e) {
e.printStackTrace();
} finally {
Utility.cleanup(con, stmt, rs);
}
return result;
}
/**
* Insert the method's description here.
* Creation date: (4/2/2002 5:03:28 PM)
* @return int
*/
public int testJdbc03() {
int result = -1;
try {
Test2Home home = null;
Context ctx = new javax.naming.InitialContext();
Object obj = ctx.lookup("com/test/ejb/Test2");
home = (Test2Home) javax.rmi.PortableRemoteObject.narrow(obj, Test2Home.class);
Test2 remote = home.create(1);
remote.setName("hello");
result = 0;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
//start of 2nd ejb, this is a cmp bean, use CMT, and transaction attribute is set to required
package com.test.ejb;
import java.rmi.RemoteException;
import java.security.Identity;
import java.util.Properties;
import javax.ejb.*;
/**
* This is an Entity Bean class with CMP fields
*/
public class Test2EJB implements EntityBean {
private javax.ejb.EntityContext entityContext = null;
public int id;
public String name;
private final static long serialVersionUID = 3206093459760846163L;
/**
* This method was generated for supporting the associations.
* @return java.util.Vector
*/
/* WARNING: THIS METHOD WILL BE REGENERATED. */
protected java.util.Vector _getLinks() {
java.util.Vector links = new java.util.Vector();
return links;
}
/**
* This method was generated for supporting the associations.
*/
/* WARNING: THIS METHOD WILL BE REGENERATED. */
protected void _initLinks() {}
/**
* This method was generated for supporting the associations.
* @exception java.rmi.RemoteException The exception description.
* @exception javax.ejb.RemoveException The exception description.
*/
/* WARNING: THIS METHOD WILL BE REGENERATED. */
protected void _removeLinks() throws java.rmi.RemoteException, javax.ejb.RemoveException {
java.util.Enumeration links = _getLinks().elements();
while (links.hasMoreElements()) {
try {
((com.ibm.ivj.ejb.associations.interfaces.Link) (links.nextElement())).remove();
}
catch (javax.ejb.FinderException e) {} //Consume Finder error since I am going away
}
}
/**
* ejbActivate method comment
* @exception java.rmi.RemoteException The exception description.
*/
public void ejbActivate() throws java.rmi.RemoteException {
_initLinks();
}
/**
* ejbCreate method for a CMP entity bean
* @param argId int
* @exception javax.ejb.CreateException The exception description.
* @exception java.rmi.RemoteException The exception description.
*/
public void ejbCreate(int argId) throws javax.ejb.CreateException, java.rmi.RemoteException {
_initLinks();
// All CMP fields should be initialized here.
id = argId;
}
/**
* ejbLoad method comment
* @exception java.rmi.RemoteException The exception description.
*/
public void ejbLoad() throws java.rmi.RemoteException {
_initLinks();
}
/**
* ejbPassivate method comment
* @exception java.rmi.RemoteException The exception description.
*/
public void ejbPassivate() throws java.rmi.RemoteException {}
/**
* ejbPostCreate method for a CMP entity bean
* @param argId int
* @exception java.rmi.RemoteException The exception description.
*/
public void ejbPostCreate(int argId) throws java.rmi.RemoteException {}
/**
* ejbRemove method comment
* @exception java.rmi.RemoteException The exception description.
* @exception javax.ejb.RemoveException The exception description.
*/
public void ejbRemove() throws java.rmi.RemoteException, javax.ejb.RemoveException {
_removeLinks();
}
/**
* ejbStore method comment
* @exception java.rmi.RemoteException The exception description.
*/
public void ejbStore() throws java.rmi.RemoteException {}
/**
* getEntityContext method comment
* @return javax.ejb.EntityContext
*/
public javax.ejb.EntityContext getEntityContext() {
return entityContext;
}
/**
* Getter method for name
* @return java.lang.String
*/
public java.lang.String getName() {
return name;
}
/**
* setEntityContext method comment
* @param ctx javax.ejb.EntityContext
* @exception java.rmi.RemoteException The exception description.
*/
public void setEntityContext(javax.ejb.EntityContext ctx) throws java.rmi.RemoteException {
entityContext = ctx;
}
/**
* Setter method for name
* @param newValue java.lang.String
*/
public void setName(java.lang.String newValue) {
this.name = newValue;
}
/**
* unsetEntityContext method comment
* @exception java.rmi.RemoteException The exception description.
*/
public void unsetEntityContext() throws java.rmi.RemoteException {
entityContext = null;
}
}
浏览网上本帖子最新内�
public void test() {
test1();//use jdbc to read a row in table t_1
test2();//use cmp methods to update the same row in table t_1
}
I think was lock the table when Iuse jdbc to read data from table, and do not release it, so when it try to update the row, it's locked, was keep waiting for the lock's release. I try to use "for read only" in the sql used to access db, but still fail. And stateless bean cannot declare a method as read-only. And then I want to put this jdbc code in a stateless session bean method, and set transaction attribute to required_new so to create a new transaction and suspend the old one, when the new one finished the old one will resume(this is stated in ejb spec), fail again. I am so tired, so I rewrite the bean to use jdbc only. DAMN WAS, DAMN IBM. How ever, if one of you can give me a help, your help is appeciated! I still want to solve this problem, using jdbc only is not a good design, cannot use the benefit of using CMP.
import javax.ejb.*;
import javax.naming.*;
import java.sql.*;
import javax.sql.*;
import javax.transaction.*;
public class Test_1Bean implements SessionBean {
SessionContext sessionContext;
public void ejbCreate() throws CreateException {
}
public void ejbRemove() {
}
public void ejbActivate() {
}
public void ejbPassivate() {
}
public void setSessionContext(SessionContext sessionContext) {
this.sessionContext = sessionContext;
}
public void testMethod(){
try{
TestHome thome = (TestHome)new InitialContext().lookup("java:comp/env/mytest");
sessionContext.setRollbackOnly();
Test t1 = thome.create(new Integer(2));
t1.setTestname("aaaa");
test1();
Test t2 = thome.create(new Integer(3));
t2.setTestname("aaaa");
}catch(Exception ex){
System.out.println(ex);
throw new EJBException(ex.getMessage());
}
}
public void test1() {
DataSource source = null;
Connection conn = null;
//UserTransaction tran = sessionContext.getUserTransaction();
try{
source = (DataSource)new InitialContext().lookup("java:comp/env/myjdbc");
conn = source.getConnection();
Statement st = conn.createStatement();
//tran.begin();
st.addBatch("insert into test values(4, 'ggg')");
st.addBatch("insert into test values(5, 'bbb')");
st.addBatch("insert into test values(5, 'ccc')");
//tran.setRollbackOnly();
st.executeBatch();
//tran.commit();
}catch(Exception ex){
//try{tran.rollback(); System.out.println(">>>>>");}catch(Exception ex1){ex1.printStackTrace();}
System.out.println(ex);
}finally{
try{ conn.close(); }catch(Exception ex){ ex.printStackTrace(); }
}
}
}
调用 testMethod() 能够成功� rollback(), 而不会出现你所说的那些错误� 说明你所说的不同� transaction 的不能共存没有依据(transaction type: container; transaction attribute: required�
1. You mentioned operations in testMethod() could rollback. But I thought the original problem LostParadise faced was the operations could not commit, and were rolled back instead. In other words, he didn't want to rollback the TX. Could you COMMIT your operations in your test?
2. You commented out the JTA calls in your code above. Did you test the code with these calls uncommented? We want to prove that there is no conflict between BMT and CMT, so we need to have the JTA stuff turned on.
Once again thank you for sharing your test results.
//test1();
Test t2 = thome.create(new Integer(2));
t2.setTestname("bbbb");
tran.commit();
}catch(Exception ex){
try{tran.rollback();}catch(Exception ex1){ex1.printStackTrace();}
System.out.println(ex);
}
}
作如下改动:
Test t2 = thome.create(new Integer(2)); => Test t2 = thome.create(new Integer(3)); 可以完整提交
I believe, and I hope this is a problem of WAS3.5.x. Because I do not found this limitation in J2EE/EJB specification.
And ericlma, you are familiar with EJB, right? I want to discuss with you on another problem, how to control EJB version. EJB is design for enterprise, many different application/project can use the same EJB. But they maybe use them with a little different, for example some small features. And when I upgrade my beans for one project, all projects will be impacted, that is too bad! And in WAS3.5.x, there is a great limitation, the WHOLE WAS use a single JVM, not one JVM per EJB container, or per EJB group(WAS 3.5.x do not have this concept). This limitation make me very difficult to design a good model. Do any of you have such experience? (555, after my study, I found WAS is not so compatible with SUN's standard and other app servers) Do weblogic have the same problem(I think wl6.x won't have this problem, how about 5.x?). This problem may encounter when developing a big application.
I did a quick test by selecting from the same table which the CMP inserts to, and there was no problem at all. By default WebLogic uses database concurrency strategy, i.e, relying on Oracle to handle it. Oracle never puts an exclusive lock on a table when reading, so it won't block the writer.
Is it too late to switch to WebLogic/Oracle? :) Can you upgrade to WAS 4.0?
I will think abot your second question a little more before respond. BTW, why do you have to keep mutiple versions of EJB's. Can you give a good example?
each project will have it's development progress. and when development goes on, they will have new requirements, these new feature maybe not required by other projects, but i must support them, and must not impact existing projects which do not use the new features. so i must make different project use different version of ejb.
my core will be hosted in a as400, or a s390(mainframe) as the projects grow up. client projects will use the same server to save up resource. so i must support multiple project, multiple version of ejb in the same server(or ejb container).
but WAS 3.5.x make it even worse. WAS run all programs(ejb, servlet) in a single jvm. this is true until was4.0.(I cannot perswuade my bosses to upgrade to 4.0), 4.0 can set each module to run in it's own jvm.
and WAS do not support ejb hot deploy, each time a project need to upgrade the core, every project is impacted, because i must first shut down the server and redeploy the beans. even worse, if the remote interface is changed, each project need to upgrade the clientejb.jar, or else they cannot accesss the new ejb.
EJB is design for enterprise application, and my project is truely a typical enterprise application. so I think we should find a better solution. If not, EJB should not declared ENTERPRISE.
so i must make a version control
该贴子是管理员从� EJB �转移过来的!