我刚刚将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
(以及SessionFactory
和HSQLDB mem DB)。所以不应该从一个测试类泄漏到下一个测试类。
有什么想法吗?没有ConnectionProvider听起来像Hibernate要么仍在启动,要么正在关闭。
答案 0 :(得分:2)
您应该只在应用程序中创建一次Session Factory对象,并且不应在整个应用程序中销毁。如果您尝试关闭曾经创建的会话工厂对象并希望使用相同的对象,那么您将获得上述异常 即。 创建会话时出错:org.hibernate.service.UnknownServiceException:请求未知服务[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();
}
}
}
}
答案 1 :(得分:1)
我们现在已经通过测试了。这实际上是我们的事务处理泄漏到非事务性测试中的问题。我们的事务支持扩展了Spring的TransactionAspectSupport
,而对于Hibernate 3,它通常无用地在非事务性测试中工作。在Hibernate 4中,当它尝试使用关闭的会话工厂创建事务时,它现在以迂回方式失败。
我们修改了测试的设置方式,这样除非我们进行交易测试,否则它根本不会尝试做任何事务性的事情,现在他们很快就过去了。
道德:使用单身人士的一个危险就是它很容易在测试中泄漏东西。答案 2 :(得分:1)
之前发生过这样的事情。当我将数据库的IP从127.0.0.1更改为192.168.1.27(在我的网络中我的计算机的IP,它可以在windows中执行ip config或在linux中执行ifconfig)时解决了。它可能不是一个永久的解决方案,但它会躲过一劫。
答案 3 :(得分:0)
Hibernate中的Session对象不是线程安全的,除非您同步对Session对象的访问,否则不应在不同的线程中使用相同的会话。
如果你真的想要使用那个技巧,那么我想告诉你,每次交易完成后清除和关闭会话。或者只使用openSession()
,这样您的程序就能运行并执行。