我正在使用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和
中的两个打开会话相关联未能懒惰地初始化角色集合:没有会话或会话已关闭
我不明白如何在我的架构中明确地从会话中分离对象。
答案 0 :(得分:1)
使用线程和Hibernate会话,你做的很糟糕。首先,CommunicationServiceImpl.sendAllMessages()
是交易性的。这意味着MessageToSend
实体在迭代messagesToSend
集合时连接到Hibernate会话。没关系。
然而,对于每个实体,您启动新线程 * 来处理该实体。在该线程中,您在MessageToSend
上执行了大量计算,包括一些子查询和更新。这就是危险的种族状况所在的地方:
如果线程在我们仍处于主while (iteratorMesToSe.hasNext())
循环内时启动(我们仍然在sendAllMessages()
方法内)MessageToSend
仍然附加到在父线程中启动的原始会话。但是,如果父线程完成迭代(我们退出sendAllMessages()
)但子MessageSender
仍在运行,则会出现如上所述的瞬态错误。 “session closed
”基本上意味着父线程在子线程完成处理之前关闭了会话。
简单来说,你永远不应该让绑定到Hibernate会话的对象从当前线程中逃脱。而是明确地将它们从会话中分离出来(例如,通过清除会话或进一步移动事务,以便在迭代时将对象附加到会话中)并为每个已处理的行启动新事务。
* - 您似乎正在为要发送的每条短信创建新线程。这不是很可扩展,一旦发送的消息总数达到数千,您的系统就会崩溃。而是使用线程池(ExecutorService
)。