1

我刚刚将一个 Spring Web 应用程序从 Hibernate 3.6 升级到 4.2,并且在我所见的范围内完成了所有必要的更改。应用程序本身似乎运行良好,但一些测试通过 Spring 的应用程序上下文测试支持使用 Hibernate,现在这些测试偶尔会失败并出现以下错误:

Caused by: org.hibernate.service.UnknownServiceException: Unknown service requested [org.hibernate.service.jdbc.connections.spi.ConnectionProvider]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:126)
at org.hibernate.internal.AbstractSessionImpl.getJdbcConnectionAccess(AbstractSessionImpl.java:261)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.<init>(JdbcCoordinatorImpl.java:97)
at org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl.<init>(TransactionCoordinatorImpl.java:87)
at org.hibernate.internal.SessionImpl.<init>(SessionImpl.java:253)
at org.hibernate.internal.SessionFactoryImpl$SessionBuilderImpl.openSession(SessionFactoryImpl.java:1599)
at org.hibernate.internal.SessionFactoryImpl.openSession(SessionFactoryImpl.java:965)
at org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:412)

当以默认文件系统顺序运行时,它们似乎更可靠地运行,但我现在以随机顺序运行它们以更容易地重现它。一旦此错误发生一次,之后的所有类似测试似乎也都失败了。测试是使用注释设置的,@DirtiesContext因此 Spring 测试运行器应该为每个类重新创建一个新的ApplicationContext(以及 HSQLDB mem DB)。SessionFactory所以不应该有任何东西从一个测试类泄漏到下一个测试类。

有任何想法吗?没有 ConnectionProvider 听起来 Hibernate 要么仍在启动,要么正在关闭。

4

4 回答 4

2

您应该只在应用程序中创建一次会话工厂对象,并且不应该在整个应用程序中销毁。如果您尝试关闭曾经创建的会话工厂对象并希望使用相同的对象,那么您将获得上述异常,即。创建会话时出错:org.hibernate.service.UnknownServiceException: Unknown service requested [org.hibernate.engine.jdbc.connections.spi.ConnectionProvider] 所以在上面的场景中你应该创建hibernate util并定义如下字段:

import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {

private static Configuration configuration;
private static StandardServiceRegistry builder;
private static SessionFactory factory;

static {
try {
configuration = new Configuration().configure("/com/hibernate/hibernate.cfg.xml");
builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
factory = configuration.buildSessionFactory(builder);
} catch (HibernateException he) {
System.err.println("Error creating Session: " + he);
throw new ExceptionInInitializerError(he);
}
}

public static SessionFactory getSessionFactory() {
return factory;
}

public static void closeSessionFactory() {
if (factory != null) {
try {
StandardServiceRegistryBuilder.destroy(builder);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
于 2014-03-04T06:28:54.730 回答
1

我以前也发生过这样的事情。当我将数据库的 IP 从 127.0.0.1 更改为 192.168.1.27(我的计算机在我的网络中的 IP,它可以在 windows 中进行 ip config 或在 linux 中进行 ifconfig 时找到)时解决了。这可能不是一个永久的解决方案,但它躲过了一劫。

于 2014-01-08T12:44:07.243 回答
1

我们现在已经通过了测试。这实际上是我们的事务处理泄漏到非事务测试中的问题。我们的事务支持扩展了 Spring 的TransactionAspectSupport,并且在 Hibernate 3 中,这过去在非事务性测试中什么也不做。在 Hibernate 4 中,当它尝试使用关闭的会话工厂创建事务时,它现在以一种迂回的方式失败。

我们修改了测试的设置方式,这样它就不会尝试做任何事务性的事情,除非我们在事务性测试中,现在它们很高兴地通过了。

道德:使用单例的风险之一是它很容易在测试中泄漏东西。

于 2013-08-16T13:27:41.470 回答
0

Hibernate 中的 Session 对象不是线程安全的,你不应该在不同的线程中使用同一个 session,除非你同步访问 Session 对象。

如果您真的想使用该技巧,那么我想说的是,每次交易完成后都清除并关闭会话。或者只是使用openSession()这样您的程序将工作并执行的方式。

于 2013-10-11T09:31:33.653 回答