Spring & Hibernate SessionFactory - 从宕机的服务器中恢复

2024-04-24

因此,在春季之前,我们使用了 HibernateUtil 版本,如果成功建立原始 JDBC 连接,它会缓存 SessionFactory 实例,否则抛出 SQLException。这使我们能够从由于身份验证或服务器连接问题而导致的 SessionFactory 初始设置“错误”中恢复过来。

我们转向 Spring,并以一种或多或少经典的方式使用 LocalSessionFactoryBean、C3P0 数据源和注入了 SessionFactory 的各种 dao 类来连接事物。

现在,如果 Web 应用程序运行时 SQL Server 似乎未启动,则 Web 应用程序永远不会恢复。所有对 dao 方法的访问都会崩溃,因为注入了空的 sessionfactory。 (一旦sessionfactory正确制作,连接池主要处理sql server的up/down状态,因此可以恢复)

现在,dao 方法默认连接为单例,我们可以将它们更改为原型。我认为这不会解决问题 - 我相信 LocalSessionFactoryBean 现在“卡住”并缓存空引用(不过,我还没有测试过这一点,我会羞愧地承认)。 这一定是人们关心的问题。

尝试了下面建议的代理——失败了

首先,我必须忽略调用的建议(坦率地说,反编译似乎是错误的)LocalSessionFactory.buildSessionFactory- 它不可见。

相反,我尝试了修改后的版本,如下所示:

覆盖 newSessionFactory。最后返回代理SessionFactory指向下面列出的调用处理程序

这也失败了。

org.hibernate.HibernateException:找不到配置的本地数据源 - 必须在 LocalSessionFactoryBean 上设置“dataSource”属性

Now, if newSessionfactory()改为简单地return config.buildSessionFactory()(而不是代理)它可以工作,但当然不再表现出所需的代理行为。

public static class HibernateInvocationHandler implements InvocationHandler {
    final private Configuration config;
    private SessionFactory realSessionFactory;
    public HibernateInvocationHandler(Configuration config) {
        this.config=config;
        }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        if (false) proxy.hashCode();
        System.out.println("Proxy for SessionFactory called");
            synchronized(this) {
                if (this.realSessionFactory == null){
                    SessionFactory sf =null;
                    try {
                        System.out.println("Gonna BUILD one or die trying");

                        sf=this.config.buildSessionFactory();
                    } catch (RuntimeException e) {
                        System.out.println(ErrorHandle.exceptionToString(e));
                        log.error("SessionFactoryProxy",e);
                        closeSessionFactory(sf);
                        System.out.println("FAILED to build");
                        sf=null;
                    }
                    if (sf==null) throw new RetainConfigDataAccessException("SessionFactory not available");
                    this.realSessionFactory=sf;                     
                }
                return method.invoke(this.realSessionFactory, args);    
        }

    }

新 SessionFactory 中的代理创建如下所示

    SessionFactory sfProxy= (SessionFactory) Proxy.newProxyInstance(
            SessionFactory.class.getClassLoader(),
            new Class[] { SessionFactory.class },
            new HibernateInvocationHandler(config));

并且可以返回此代理(失败)或 config.buildSessionFactory() ,它可以工作但不能解决最初的问题。

bozho 建议使用 getObject() 的替代方法。注意d)中的致命缺陷,因为buildSessionFactory不可见。

a) 如果 this.sessionfactory 为非空,则不需要代理,只需返回 b) 如果是,构建一个代理... c) 应包含sessionfactory的私有引用,并且每次调用时检查它是否为null。如果是这样,您将构建一个新工厂,如果成功,则分配给私有引用并从现在开始返回它。 d) 现在,说明如何从 getObject() 构建该工厂。您的答案应该涉及调用 buildSessionFactory...但您不能。人们可以自己创建工厂,但最终会冒着破坏 spring 的风险(查看 buildSessionFactory 代码)


你不应该担心这个。在生产和开发中很少会启动应用程序 - 无论如何,您都需要数据库服务器。

如果数据库服务器在应用程序运行时停止,应用程序是否无法恢复,您应该担心。

你能做的就是延长LocalSessionFactoryBean并覆盖getObject()方法,并使其返回代理 (via java.lang.reflect.Proxy or CGLIB http://cglib.sourceforge.net/ / javassist http://www.jboss.org/javassist),以防 sessionFactory 为空。这样一个SessionFactory将被注入。代理应该保存对裸露的引用SessionFactory,最初为空。每当代理被要求连接时,如果sessionFacotry仍然为空,你调用buildSessionFactory()(的LocalSessionFactoryBean)并委托给它。否则抛出异常。 (当然,然后映射你的新工厂 bean 而不是当前的)

因此,即使数据库在启动时不可用,您的应用程序也将可用。但我自己不会为此烦恼。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring & Hibernate SessionFactory - 从宕机的服务器中恢复 的相关文章

随机推荐