【问题标题】:Exception while creating connection to multiple dbs through threads [duplicate]通过线程创建与多个数据库的连接时出现异常[重复]
【发布时间】:2018-01-08 07:16:44
【问题描述】:

我有一个这样的主要方法

public static void main(String[] args) {
        String dbHosts = args[0];
        String[] dbHostsArr = dbHosts .split(",");
            for(String dbHost: dbHostsArr ){
                try {
                    Thread t = new Thread(new UpdateDataForDb(dbHost));
                    t.start();
                } catch (Exception e) {
                    e.printStackTrace();
                } 
            }
        }

在我的 run 方法中,我连接到 db 并运行一些休眠查询来更新不同表中的数据。 main 方法和 run 方法都在同一个 Java 文件中返回。当我运行此文件时,出现以下异常

java.lang.NullPointerException 在 org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:119) 在 org.hibernate.service.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:75) 在 org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:159) 在 org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:131) 在 org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:77) 在 org.hibernate.cfg.Configuration.buildSettingsInternal(Configuration.java:2283) 在 org.hibernate.cfg.Configuration.buildSettings(Configuration.java:2279) 在 org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1748) 在 org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1788) 在 com.myfw.runtime.Application.getSessionFactory(Application.java:15) 在 com.myfw.runtime.ServiceExecutionContext.setup(ServiceExecutionContext.java:114) 在 com.myorg.customer.CustomerUtils.getServiceExecutionContextForCustomer(CustomerUtils.java:633) 在 com.myorg.utils.UpdateDataForDb.updateDataMethod(UpdateDataForDb.java:747) 在 com.myorg.utils.UpdateDataForDb.run(UpdateDataForDb.java:736) 在 java.lang.Thread.run(Unknown Source) 初始 SessionFactory 创建 failed.java.lang.NullPointerException 线程“Thread-1”中的异常 java.lang.ExceptionInInitializerError 在 com.myfw.runtime.Application.getSessionFactory(Application.java:21) 在 com.myfw.runtime.ServiceExecutionContext.setup(ServiceExecutionContext.java:114) 在 com.myorg.customer.CustomerUtils.getServiceExecutionContextForCustomer(CustomerUtils.java:633) 在 com.myorg.utils.UpdateDataForDb.updateDataMethod(UpdateData.java:747) 在 com.myorg.utils.UpdateDataForDb.run(UpdateData.java:736) 在 java.lang.Thread.run(未知来源)

只有当我使用线程运行方法时才会出现此问题,如果我不使用线程并为多个 dbs 调用 updatedata 方法,一切似乎都可以正常工作。

我的代码中使用的所有方法如下:

public void run() {
        updateDataMethod(dbHost);
        return;
    }

/* * 将数据库名称作为输入并更新数据库内表的方法 */

private void updateDataMethod(String dbHost) {
        ServiceExecutionContext ctx = null;
            try {
                ctx = CustomerUtils.getServiceExecutionContextForCustomer(dbHost);
                System.out.println("ctx for "+dbHost);
                if(ctx != null){
                    // different methods to insert data into tables
                  ctx.tearDownNormal();
                }
            }
            catch(Exception e){
                e.printStackTrace();
                if(ctx != null)
                  ctx.tearDownException();
           }

}

/** * 创建到数据库的连接 */

public static ServiceExecutionContext getServiceExecutionContextForCustomer(String dbHost) {
        CustomerInfoThreadLocal.setDBHost(dbHost);
        ServiceExecutionContext ctx = null;
        try {
            ctx = new ServiceExecutionContext(null);
            ctx.setTransactionMode(ServiceExecutionContext.READWRITE);
            ctx.setup();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
         return ctx;
    }

public void setup() throws Exception
    {
        try
        {
            System.out.println("Hibernate session setup started");
            if (session == null)
                session = Application.getInstance().getSessionFactory().openSession();
            tx = session.beginTransaction();
            if (this.transactionMode == ServiceExecutionContext.READWRITE)
                session.setFlushMode(FlushMode.AUTO);
            else
                if (this.transactionMode == ServiceExecutionContext.READWRITECOMMITAFTER)
                    session.setFlushMode(FlushMode.COMMIT);
                else
                    session.setFlushMode(FlushMode.MANUAL);
            System.out.println("Hibernate session setup done");
        } catch (Exception e)
        {
            throw e;
        }
    }

从hibernate.cfg.xml获取sessionfactory如下

public SessionFactory getSessionFactory() throws Exception
    {
        if (sessionFactory == null)
        {
            try {
                // Create the SessionFactory from hibernate.cfg.xml
                sessionFactory =  new Configuration().configure().buildSessionFactory();
            }
            catch (Throwable ex) {
                ex.printStackTrace();
                throw new ExceptionInInitializerError(ex);
            }           
        }
        return sessionFactory;
    }

【问题讨论】:

  • 那么您的getSessionFactory 方法在做什么?也许您可以向我们展示代码。
  • @Zoe 将这个问题标记为那个问题的副本是完全没有意义的,因为在这里,异常被抛出在 Hibernate 的深处。处理空指针异常的常规方法在这里不适用。我真诚地希望没有人将这个问题作为那个问题的副本来结束。
  • 我同意@DawoodibnKareem需要调试npe的原因
  • @DawoodibnKareem 我在问题中添加了 getSessionFactory 方法
  • @DawoodibnKareem SessionFactory 最终捕获了一个异常,该异常作为 ExceptionInInitializerError 被抛出,随后导致 NPE,因为从未创建会话。由于会话为空,因此会导致 NPE

标签: java multithreading hibernate


【解决方案1】:

同步你的getSessionFactory(),因为它抛出ExceptionInInitializerError,这是处理多线程时的常见问题。

public synchronized SessionFactory getSessionFactory() throws Exception
{
    if (sessionFactory == null)
    {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            sessionFactory =  new Configuration().configure().buildSessionFactory();
        }
        catch (Throwable ex) {
            ex.printStackTrace();
            throw new ExceptionInInitializerError(ex);
        }           
    }
    return sessionFactory;
}

【讨论】:

  • 我试过了,但没有解决我的问题。
  • 在您的线程中发布run() 方法。它看起来像一个多线程问题。
  • 用所有相关方法更新了问题
  • 你也应该同步getServiceExecutionContextForCustomer。在这种方法中,我看到了CustomerInfoThreadLocal.setDBHost(dbHost);。这是问题,因为dbHost 可以用作全局变量。如果有多个线程来这里就会有问题。
  • 由于您使用了很多全局变量(那些静态方法),因此很难在您的情况下确保线程安全。如果您希望某些操作并行运行,则应使它们不会相互干扰。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-28
  • 2012-11-18
  • 2020-04-11
  • 2017-06-07
  • 1970-01-01
相关资源
最近更新 更多