在EJB 3应用程序中(在WebSphere Application Server v7.0.0.21上),我有一个返回String的方法。在方法内部我使用StringBuffer生成动态字符串(也尝试使用StringBuilder,结果相同)。每隔一段时间发生的问题是String的内容全部被扰乱。我现在很长一段时间都在努力解决这个问题。
修改:
示例1 :
用户A和B在不同的时间调用方法generateDocument并获得正确的结果。
用户A的结果:
字符串1:1
String2的:2
STRING3:3
串,4:4
和用户B的结果:
字符串1:5
String2的:6
STRING3:7
串,4:8
示例2 :
用户A和B同时调用方法generateDocument,并且它们都获得相同的加扰结果(部分响应来自用户A,部分响应来自用户B):
字符串1:1
String2的:2
<德尔> STRING3:7 德尔>
<德尔>串,4:8 德尔>
示例代码
dao.properties
# jndi lookup string
jndi.datasource = jdbc/DS
# integers
select.integers = \
SELECT \
num1 \
FROM \
DBINTEGERS \
WHERE \
param1 = :param1 \
AND param2 = :param2 \
ORDER BY num1 \
WITH UR
# custom object
select.custom.object = \
SELECT \
number1, number2, number3, number4 \
FROM \
DB_OBJECTS \
WHERE \
param1 = :param1 \
ORDER BY number1 \
WITH UR
spring.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:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:dao.properties</value>
</list>
</property>
<property name="order" value="1" />
<property name="ignoreUnresolvablePlaceholders" value="false" />
<property name="localOverride" value="true" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.WebSphereDataSourceAdapter">
<property name="targetDataSource">
<bean class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${jndi.datasource}" />
<property name="resourceRef" value="true" />
</bean>
</property>
</bean>
<bean id="abstractDao" abstract="true">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dao" class="org.example.beans.dao.DaoSpringJdbc" parent="abstractDao">
<property name="selectIntegers" value="${select.integers}" />
<property name="selectCustomObject" value="${select.custom.object}" />
</bean>
</beans>
Dao.java
package org.example.beans.dao;
import java.sql.SQLException;
import org.example.beans.models.CustomObject;
public interface Dao {
List<Integer> selectINTEGERS(String param1, String param2) throws SQLException;
List<CustomObject> selectCustomObject(Integer param1) throws SQLException;
}
DaoBeanLocal.java
package org.example.beans.dao;
import java.util.Date;
import java.util.List;
import java.sql.SQLException;
import javax.ejb.Local;
@Local
public interface DaoBeanLocal extends Dao {
}
DaoBean.java
package org.example.beans.dao;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.EJBException;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
@Stateless
public class DaoBean implements DaoBeanLocal {
private Dao dao;
@PostConstruct
protected void init() {
try {
this.dao = (Dao) getBeanFactory().getBean("dao", Dao.class);
} catch (Exception e) {
// log.error(e.getMessage(), e);
throw new EJBException(e.getMessage(), e);
}
}
@PreDestroy
protected void destroy() {
if (this.dao != null) {
this.dao = null;
}
}
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public List<Integer> selectINTEGERS(String param1, String param2) throws SQLException {
return dao.selectINTEGERS(param1, param2);
}
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public List<CustomObject> selectCustomObject(Integer param1) throws SQLException {
return dao.selectCustomObject(param1);
}
}
DaoSpringJdbc.java
package org.example.beans.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport;
import org.example.beans.models.CustomObject;
public class DaoSpringJdbc extends NamedParameterJdbcDaoSupport implements Dao {
private String selectIntegers;
private String selectCustomObject;
@Override
public List<Integer> selectINTEGERS(String param1, String param2) throws SQLException {
final Map<String, Object> sqlParameters = new HashMap<String, Object>(2);
sqlParameters.put("param1", param1);
sqlParameters.put("param2", param2);
List<Integer> list = getNamedParameterJdbcTemplate().query(this.selectIntegers, sqlParameters, new RowMapper<Integer>() {
@Override
public Integer mapRow(ResultSet rs, int rowNum) throws SQLException {
return (rs.getObject("num1") == null ? null : rs.getInt("num1"));
}
});
return list;
}
@Override
public List<CustomObject> selectCustomObject(Integer param1) throws SQLException {
final Map<String, Object> sqlParameters = new HashMap<String, Object>(1);
sqlParameters.put("param1", param1);
List<CustomObject> list = getNamedParameterJdbcTemplate().query(this.selectCustomObject, sqlParameters, new RowMapper<CustomObject>() {
@Override
public CustomObject mapRow(ResultSet rs, int rowNum) throws SQLException {
CustomObject o = new CustomObject();
o.setNumber1(rs.getObject("number1") == null ? null : rs.getInt("number1"));
o.setNumber2(rs.getObject("number2") == null ? null : rs.getInt("number2"));
o.setNumber3(rs.getObject("number3") == null ? null : rs.getInt("number3"));
o.setNumber4(rs.getObject("number4") == null ? null : rs.getInt("number4"));
return o;
}
});
return list;
}
public void setSelectIntegers(String selectIntegers) {
this.selectIntegers = selectIntegers;
}
public void setSelectCustomObject(String selectCustomObject) {
this.selectCustomObject = selectCustomObject;
}
}
CustomObject.java
package org.example.beans.models;
public class CustomObject {
private int number1;
private int number2;
private int number3;
private int number4;
public int getNumber1() {
return this.number1;
}
public void setNumber1(int number1) {
this.number1 = number1;
}
public int getNumber1() {
return this.number1;
}
public void setNumber2(int number2) {
this.number2 = number2;
}
public int getNumber2() {
return this.number2;
}
public void setNumber3(int number3) {
this.number3 = number3;
}
public int getNumber3() {
return this.number3;
}
public void setNumber4(int number4) {
this.number4 = number4;
}
public int getNumber4() {
return this.number4;
}
}
CustomException.java
package org.example.beans.exceptions;
import javax.ejb.ApplicationException;
@ApplicationException(rollback = true)
public class CustomException extends Exception {
private static final long serialVersionUID = 1L;
public CustomException() {
super();
}
public CustomException(Throwable t) {
super(t);
}
public CustomException(String detailMessage) {
super(detailMessage);
}
public CustomException(String detailMessage, Throwable t) {
super(detailMessage, t);
}
}
Data.java
package org.example.beans.data;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.example.beans.models.CustomObject;
import org.example.beans.dao.DaoBeanLocal;
import org.example.beans.exceptions.CustomException;
public class Data {
public void getContent(StringBuffer doc, DaoBeanLocal dao, Integer param1) throws CustomException {
List<CustomObject> list = dao.selectCustomObject(param1);
for (CustomObject obj : list) {
doc.append("------------------");
doc.append("String1: ").append(obj.getNumber1()).append("\n");
doc.append("String2: ").append(obj.getNumber2()).append("\n");
doc.append("String3: ").append(obj.getNumber3()).append("\n");
doc.append("String4: ").append(obj.getNumber4()).append("\n");
}
}
}
DocumentBean.java
package org.example.beans;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.EJB;
import javax.ejb.EJBException;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import org.example.beans.exceptions.CustomException;
import org.example.beans.data.Data;
import org.example.beans.dao.DaoBeanLocal;
@Stateless
public class DocumentBean implements DocumentRemote {
@PostConstruct
protected void init() {
}
@PreDestroy
protected void destroy() {
}
// DAO local ejb
@EJB
private DaoBeanLocal dao;
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public String generateDocument(String param1, String param2) throws CustomException {
StringBuffer doc = new StringBuffer(10000);
try {
// some utility class
Data data1 = new Data();
Data data2 = new Data();
Data data3 = new Data();
Data data4 = new Data();
// some data from database
List<Integer> list = dao.selectIntegers(param1, param2);
for (Integer param1 : list) {
// a lot of usage of StringBuffer inside methods
data1.getContent(doc, dao, param1);
data2.getContent(doc, dao, param1);
data3.getContent(doc, dao, param1);
data4.getContent(doc, dao, param1);
}
} catch (CustomException e) {
log.error(e.getMessage(), e);
throw e;
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new CustomException(e.getMessage(), e);
}
String result = doc.toString();
return result;
}
}
我猜这是同步问题 - 线程。我认为EJB上下文处理同步,并且每个远程调用都是在单独的线程中进行的。
任何人都知道如何解决这个问题?