【问题标题】:Spring & Hibernate SessionFactory - recovery from a down serverSpring & Hibernate SessionFactory - 从停机服务器恢复
【发布时间】:2011-02-15 15:30:14
【问题描述】:

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

我们迁移到 Spring 并以或多或少的经典方式连接了 LocalSessionFactoryBean、C3P0 数据源和注入 SessionFactory 的各种 dao 类。

现在,如果在 Web 应用程序运行时 SQL 服务器似乎未启动,则 Web 应用程序永远不会恢复。对 dao 方法的所有访问都会因为一个空 sessionfactory 被注入而崩溃。 (一旦 sessionfactory 设置好,连接池主要处理 sql server 的 up/down 状态,所以恢复是可能的)

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

按照下面的建议尝试了代理 -- 失败了

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

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

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

这也失败了。

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

现在,如果 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);    
        }

    }

newSessionFactory 中的代理创建是这样的

    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 的私有引用,并且每次调用它时检查它是否为空。如果是这样,您将构建一个新工厂,如果成功分配给私有引用并从现在开始返回它。 d) 现在,说明您将如何从 getObject() 构建该工厂。您的答案应该涉及调用 buildSessionFactory ....但您不能。一个人可以自己创建工厂,但你最终会冒着破坏弹簧的风险(查看 buildSessionFactory 代码)

【问题讨论】:

  • 你在启动时得到堆栈跟踪吗?
  • 我做到了,如果你愿意,我可以发布它,但如果注入的会话工厂在 dao 中为空,那只不过是你所期望的......
  • 我找到了奇怪的数据源错误的原因。Spring 在调用 newSessionFactory 之后非常故意将 buildSessionFactory 中的引用(它是线程本地的)清空。如果不重写课程,想不出办法解决这个问题
  • 显示您的getObject() 方法。
  • getObject() 没有条目,因为您无法使用您的方法。简单证明:如果 this.sessionFactory 为空,如何在不重写 buildSessionFactory 的情况下从这里返回 sessionFactory?

标签: java hibernate spring orm


【解决方案1】:

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

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

您可以做的是扩展LocalSessionFactoryBean 并覆盖getObject() 方法,并使其返回一个代理(通过java.lang.reflect.ProxyCGLIB / javassist),以防万一sessionFactory 为空。这样SessionFactory 就会被注入。代理应持有对裸SessionFactory 的引用,该引用最初为空。每当要求代理连接时,如果sessionFacotry 仍然为空,则调用buildSessionFactory()LocalSessionFactoryBean)并委托给它。否则抛出异常。 (然后当然映射你的新工厂 bean 而不是当前的)

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

【讨论】:

  • 嗯。我会调查这种方法。我很欣赏这个建议,尽管我认为你的意见在这里是错误的。目标受众是面向最终用户的,因此恢复很重要。我同意这是一个内部应用程序还是专业托管的应用程序,这不是问题
  • 您的代理建议看起来很有希望,但我无法让它发挥作用
  • 从代理开始并不容易。你可能想问另一个关于它的问题。
  • 我确信代理正在工作,是 LocalSessionFactory bean 正在与之抗争。你建议什么具体问题?
  • @MJB 不习惯给某人投反对票,他花了一些时间调查您的问题,并给出了您不理解的解决方案。
猜你喜欢
  • 2011-12-28
  • 1970-01-01
  • 1970-01-01
  • 2014-07-17
  • 2011-05-06
  • 2012-06-10
  • 2015-12-31
  • 2013-02-19
  • 1970-01-01
相关资源
最近更新 更多