在EJB 3中使用StringBuffer或StringBuilder

时间:2014-10-06 06:47:58

标签: java ejb stringbuilder stringbuffer

在EJB 3应用程序中(在WebSphere Application Server v7.0.0.21上),我有一个返回String的方法。在方法内部我使用StringBuffer生成动态字符串(也尝试使用StringBuilder,结果相同)。每隔一段时间发生的问题是String的内容全部被扰乱。我现在很长一段时间都在努力解决这个问题。

修改

  • 为dao.properties,spring.xml,Dao.java,DaoBeanLocal.java,DaoBean.java和DaoSpringJdbc.java添加了代码
  • 我正在使用Java EE 5,JRE 1.6和Spring JDBC 3.0.6

示例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上下文处理同步,并且每个远程调用都是在单独的线程中进行的。

任何人都知道如何解决这个问题?

0 个答案:

没有答案