3

我使用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                
        }

短信发件人:

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 代码:

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,我都会创建一个线程来发送消息。线程 smsSender 工作得很好,但不是数据库中的持久性。对象 MessageToSend 的更改尚未在我的数据库中更新。

随机误差是:

会议结束,

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

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

非法尝试将集合与 hibernate 和

未能延迟初始化角色集合:没有会话或会话已关闭


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

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

4

1 回答 1

1

您正在使用线程和 Hibernate 会话做非常糟糕的事情。首先CommunicationServiceImpl.sendAllMessages()是事务性的。这意味着MessageToSend实体在您迭代messagesToSend集合时连接到 Hibernate 会话。没关系。

但是,对于每个实体,您都会启动处理该实体的新线程* 。在该线程中,您对 执行大量计算MessageToSend,包括一些子查询和更新。这是危险的竞争条件表现出来的地方:

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

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

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

于 2012-10-16T18:04:40.830 回答