线程和Hibernate会话的随机错误

时间:2012-10-16 17:35:16

标签: java spring hibernate

我正在使用hibernate3和spring。

Java代码:

类CommunicationServiceImpl,方法sendAllMessages:

Collection<MessageToSend> messagesToSend = this.repositoriesLocator.getMessageToSendRepository().getMessagesToSend();


        Iterator<MessageToSend> iteratorMesToSe = messagesToSend.iterator();
        while (iteratorMesToSe.hasNext()) {
            MessageToSend mts = iteratorMesToSe.next();

            MessageSender sender = new SmsSender(mts, this.repositoriesLocator);
            sender.start(); //run thread                
        }

SmsSender:

public class SmsSender extends MessageSender {

public SmsSender(MessageToSend messageToSend, RepositoriesLocator repositoriesLocator) {
    super(messageToSend, repositoriesLocator);      
}

public void sendMessages() {            
    try {
        MessageToSendSms messageToSendSms = (MessageToSendSms) this.messageToSend;                                                      
        Iterator<CustomerByMessage> itCbmsgs = messageToSendSms.getCustomerByMessage().iterator();          
        while (itCbmsgs.hasNext()) {                
            CustomerByMessage cbm = (CustomerByMessage) itCbmsgs.next();        

            //sms sending                           
            String sResult = this.sendSMS(cb.getBody(), cbm.getCellPhone());
            cbm.setStatus(CustomerByMessageStatus.SENT_OK);
            cbm.setSendingDate(Calendar.getInstance().getTime());                               
        }

        messageToSendSms.setStatus(messageToSendStats.PROCESSED)
        this.log.info("saving messageToSend..."); 
        //this line dont work!
        this.repositoriesLocator.getMessageToSendRepository().update(messageToSendSms);         
        this.log.info("messageToSend saved!");                      
    } catch (Exception e) {         
        this.log.error("Error sms sender " + e.getMessage());
    }       
}

这是我appContext.xml的一部分:

<bean id="serviceCommunication"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager">
        <ref local="transactionManager" />
    </property>
    <property name="target">
        <ref local="communicationServiceImpl" />
    </property>             
    <property name="transactionAttributes">
        <props>
            <prop key="*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
</bean>

<bean id="communicationServiceImpl"
    class="com.ninatec.fnet3.services.communication.impl.CommunicationServiceImpl"
    parent="serviceParent">
</bean>

HibernateRepository
repositoriesLocator.getMessageToSendRepository()。update CODE:

public void update(MessageToSend messageToSend) {
    try {
        this.getSession().update(messageToSend);
    } catch (HibernateException e) {
        this.log.error(e.getMessage(), e);
        throw e;
    }
}

实体MessageToSend,从未更新。

当我调用CommunicationServiceImpl.sendAllMessages()时,我在一个集合中有所有messagesToSend。 对于每个MessageToSend,我创建一个Thread来发送消息。 Thread smsSender运行良好,但不是数据库中的持久性。 MessageToSend对象中的更改尚未在我的数据库中更新。

Randoms错误是:

会话结束,

无法初始化代理 - 没有会话,

无法初始化代理 - 拥有的会话已关闭,

非法尝试将集合与hibernate和

中的两个打开会话相关联

未能懒惰地初始化角色集合:没有会话或会话已关闭


    • 关于线程。我想为x短信使用一个线程。每个smsSender,发送一组短信。

我不明白如何在我的架构中明确地从会话中分离对象。

1 个答案:

答案 0 :(得分:1)

使用线程和Hibernate会话,你做的很糟糕。首先,CommunicationServiceImpl.sendAllMessages()是交易性的。这意味着MessageToSend实体在迭代messagesToSend集合时连接到Hibernate会话。没关系。

然而,对于每个实体,您启动新线程 * 来处理该实体。在该线程中,您在MessageToSend上执行了大量计算,包括一些子查询和更新。这就是危险的种族状况所在的地方:

如果线程在我们仍处于主while (iteratorMesToSe.hasNext())循环内时启动(我们仍然在sendAllMessages()方法内)MessageToSend仍然附加到在父线程中启动的原始会话。但是,如果父线程完成迭代(我们退出sendAllMessages())但子MessageSender仍在运行,则会出现如上所述的瞬态错误。 “session closed”基本上意味着父线程在子线程完成处理之前关闭了会话。

简单来说,你永远不应该让绑定到Hibernate会话的对象从当前线程中逃脱。而是明确地将它们从会话中分离出来(例如,通过清除会话或进一步移动事务,以便在迭代时将对象附加到会话中)并为每个已处理的行启动新事务。

* - 您似乎正在为要发送的每条短信创建新线程。这不是很可扩展,一旦发送的消息总数达到数千,您的系统就会崩溃。而是使用线程池(ExecutorService)。