java - Threads 和 Hibernate session 的随机错误

标签 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                
        }

短信发送者:

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>

hibernate 库
repositoriesLocator.getMessageToSendRepository().更新代码:

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 中的更改。

随机错误是:

session 结束,

无法初始化代理 - 没有 session ,

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

非法尝试将一个集合与 hibernate 和两个打开的 session 相关联

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


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

我不明白如何在我的架构中明确地将对象与 session 分离。

最佳答案

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

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

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

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

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

关于java - Threads 和 Hibernate session 的随机错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12920349/

相关文章:

java - Oracle - 连接池与 spring 框架

java - 使用 JAVA 和 JPA 1.0 对 DB2 进行大量更新或插入

java - 使用按小时分组的 Hibernate 标准

java - 使用JPA执行数据库功能

java - 如何在java中的非数组网格中填充正方形?

java - 从静态内部类访问非静态成员方法的解决方法

java - 为什么我得到 "Error 500: java.lang.NullPointerException"java servlet

java - XMLRPC java 插入问题

spring - 找不到元素“beans :beans”的声明

java - 应用程序初始化的首选方式