春天与春天Hibernate SessionFactory-从停机的服务器中恢复 [英] Spring & Hibernate SessionFactory - recovery from a down server

查看:72
本文介绍了春天与春天Hibernate SessionFactory-从停机的服务器中恢复的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,在春季之前,如果建立了成功的原始JDBC连接,我们将使用HibernateUtil版本来缓存SessionFactory实例,否则使用SQLException.这使我们能够从由于身份验证或服务器连接问题而处于错误"状态的SessionFactory的初始设置中恢复.

So pre spring, we used version of HibernateUtil that cached the SessionFactory instance if a successful raw JDBC connection was made, and threw SQLException otherwise. This allowed us to recover from initial setup of the SessionFactory being "bad" due to authentication or server connection issues.

我们迁移到Spring并使用LocalSessionFactoryBean,C3P0数据源以及注入了SessionFactory的各种dao类以某种或多或少的经典方式进行连接.

We moved to Spring and wired things in a more or less classic way with the LocalSessionFactoryBean, the C3P0 datasource, and various dao classes which have the SessionFactory injected.

现在,如果在运行Web应用程序时SQL服务器似乎未启动,则该Web应用程序将永远无法恢复.由于注入了空的sessionfactory,对dao方法的所有访问都被炸断了. (一旦sessionfactory设置正确,连接池就可以很好地处理sql server的启动/关闭状态,因此可以恢复)

Now, if the SQL server appears to not be up when the web app runs, the web app never recovers. All access to the dao methods blow up because a null sessionfactory gets injected. (once the sessionfactory is made properly, the connection pool mostly handles the up/down status of the sql server fine, so recovery is possible)

现在,默认情况下,将dao方法连接为单例,我们可以将其更改为原型.我认为这不会解决问题-我相信LocalSessionFactoryBean现在卡住了"并缓存了空引用(尽管我还没有对此进行测试,但是我会很遗憾地承认). 这必须是一个涉及到人们的问题.

Now, the dao methods are wired by default to be singletons, and we could change them to prototype. I don't think that will fix the matter though - I believe the LocalSessionFactoryBean is now "stuck" and caches the null reference (I haven't tested this yet, though, I'll shamefully admit). This has to be an issue that concerns people.

尝试如下所示的代理-失败

Tried proxy as suggested below -- this failed

首先,我不得不忽略该建议(坦率地说,从反编译来看这是错误的)来调用LocalSessionFactory.buildSessionFactory-它是不可见的.

First of all I had to ignore the suggestion (which frankly seemed wrong from a decompile) to call LocalSessionFactory.buildSessionFactory - it isn't visible.

相反,我尝试了如下修改版本:

Instead I tried a modified version as follows:

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

override newSessionFactory. At end return proxy of SessionFactory pointing to an invocation handler listed below

这也失败了.

org.hibernate.HibernateException:未找到用于配置的本地数据源-必须在LocalSessionFactoryBean上设置'dataSource'属性

org.hibernate.HibernateException: No local DataSource found for configuration - 'dataSource' property must be set on LocalSessionFactoryBean

现在,如果将newSessionfactory()更改为简单 return config.buildSessionFactory()(代替代理),它可以工作,但当然不再表现出所需的代理行为.

Now, if newSessionfactory() is changed to simply return config.buildSessionFactory() (instead of a proxy) it works, but of course no longer exhibits the desired proxy behavior.

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);    
        }

    }

在newSessionFactory中创建代理看起来像这样

The proxy creation in newSessionFactory looks like this

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

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

and one can return this proxy (which fails) or config.buildSessionFactory() which works but doesn't solve the initial issue.

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

An alternate approach has been suggested by bozho, using getObject(). Note the fatal flaw in d), because buildSessionFactory is not visible.

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

a) if this.sessionfactory is nonnull, no need for a proxy, just return b) if it is , build a proxy which... c) should contain a private reference of sessionfactory, and each time it is called check if it is null. If so, you build a new factory and if successful assign to the private reference and return it from now on. d) Now, state how you would build that factory from getObject(). Your answer should involve calling buildSessionFactory....but you CAN'T. One could create the factory by oneself, but you would end up risking breaking spring that way (look at buildSessionFactory code)

推荐答案

您不必为此担心.启动该应用程序是您在生产和开发中都很少做的事情-嗯,您仍然需要数据库服务器.

You shouldn't worry about this. Starting the app is something you will rarely do in production, and in development - well, you need the DB server anyway.

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

You should worry if the application doesn't recover if the db server stops while the app is running.

您可以做的是扩展LocalSessionFactoryBean并覆盖getObject()方法,并使其成为返回代理(通过java.lang.reflect.Proxy javassist ),在如果sessionFactory为null.这样,将注入SessionFactory.代理应保留对裸SessionFactory的引用,该引用最初为null.每当要求代理连接时,如果sessionFacotry仍然为null,则调用(LocalSessionFactoryBean的)buildSessionFactory()并委派给它.否则抛出异常. (然后,当然要映射新的工厂bean而不是当前的bean)

What you can do is extend LocalSessionFactoryBean and override the getObject() method, and make it return a proxy (via java.lang.reflect.Proxy or CGLIB / javassist), in case the sessionFactory is null. That way a SessionFactory will be injected. The proxy should hold a reference to a bare SessionFactory, which would initially be null. Whenever the proxy is asked to connect, if the sessionFacotry is still null, you call the buildSessionFactory() (of the LocalSessionFactoryBean) and delegate to it. Otherwise throw an exception. (Then of course map your new factory bean instead of the current)

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

Thus your app will be available even if the db isn't available on startup. But I myself wouldn't bother with this.

这篇关于春天与春天Hibernate SessionFactory-从停机的服务器中恢复的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆