-1

I have a main method like this

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

Inside my run method I connect to db and run some hibernate queries to update data in different tables. Both main method and run method are return in same Java file. When I run this file I am getting the following exception

java.lang.NullPointerException at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:119) at org.hibernate.service.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:75) at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:159) at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:131) at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:77) at org.hibernate.cfg.Configuration.buildSettingsInternal(Configuration.java:2283) at org.hibernate.cfg.Configuration.buildSettings(Configuration.java:2279) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1748) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1788) at com.myfw.runtime.Application.getSessionFactory(Application.java:15) at com.myfw.runtime.ServiceExecutionContext.setup(ServiceExecutionContext.java:114) at com.myorg.customer.CustomerUtils.getServiceExecutionContextForCustomer(CustomerUtils.java:633) at com.myorg.utils.UpdateDataForDb.updateDataMethod(UpdateDataForDb.java:747) at com.myorg.utils.UpdateDataForDb.run(UpdateDataForDb.java:736) at java.lang.Thread.run(Unknown Source) Initial SessionFactory creation failed.java.lang.NullPointerException Exception in thread "Thread-1" java.lang.ExceptionInInitializerError at com.myfw.runtime.Application.getSessionFactory(Application.java:21) at com.myfw.runtime.ServiceExecutionContext.setup(ServiceExecutionContext.java:114) at com.myorg.customer.CustomerUtils.getServiceExecutionContextForCustomer(CustomerUtils.java:633) at com.myorg.utils.UpdateDataForDb.updateDataMethod(UpdateData.java:747) at com.myorg.utils.UpdateDataForDb.run(UpdateData.java:736) at java.lang.Thread.run(Unknown Source)

This problem comes only when I run the methods using threads, If I dont use threads and call the updatedata method for multiple dbs one by one everything seems to work fine.

All methods used inside my code are given below :

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

/* * Method which takes db name as input and update tables inside the db */

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

}

/** * Creates connection to db */

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

Get sessionfactory from hibernate.cfg.xml is as follows

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;
    }
Jerry
  • 987
  • 4
  • 16
  • 46
  • So what's your `getSessionFactory` method doing? Perhaps you can show us the code. – Dawood ibn Kareem Jan 08 '18 at 07:19
  • 3
    @Zoe it would be completely pointless to mark this question as a duplicate of that one, as here, the exception is being thrown deep inside Hibernate. The normal ways of dealing with a null pointer exception don't apply here. I sincerely hope that nobody closes this question as a duplicate of that one. – Dawood ibn Kareem Jan 08 '18 at 07:20
  • I agree with @DawoodibnKareem need to debug the cause of the npe – Akshay Jan 08 '18 at 07:23
  • @DawoodibnKareem I have added getSessionFactory method in the question – Jerry Jan 08 '18 at 07:27
  • @DawoodibnKareem SessionFactory ends up catching an exception, which is thrown as an ExceptionInInitializerError causing an NPE later because the session is never created. Since the session is null, it causes an NPE – Zoe Jan 08 '18 at 07:29
  • @Zoe Why session is not getting created is my problem. Same method when I run without threads it works perfectly fine. – Jerry Jan 08 '18 at 07:31
  • The problem can be Thread safe issue : have you tried to add synchronized keyword on the getSessionFactory function? – Tuco Jan 08 '18 at 08:18
  • Does you code works without using Thread ? – Tuco Jan 08 '18 at 08:24
  • @Tuco I din't try that. But if the threads are connecting to same db it seems to work fine. And yes it works without Thread – Jerry Jan 08 '18 at 08:24
  • So, do the test with the synchronized keyword – Tuco Jan 08 '18 at 08:30
  • @Tuco synchronized keyword doesn't solve the issue. Actually its kind of weird. When I try with some 5 or 6 different dbs error comes inconsistently. Like while testing two times it worked fine but the third time I ran it threw same error. When I test this in an environment with more than 100 dbs it fails always – Jerry Jan 08 '18 at 09:53

1 Answers1

0

Synchronize your getSessionFactory() since it throws ExceptionInInitializerError, this is a common problem when dealing with multi-threading.

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;
}
zhh
  • 2,346
  • 1
  • 11
  • 22
  • I tried that, but din't solve my issue. – Jerry Jan 08 '18 at 08:48
  • Post ```run()``` method in your thread. It looks like a multi-threading issue. – zhh Jan 08 '18 at 08:59
  • updated the question with all related methods – Jerry Jan 08 '18 at 09:46
  • You should synchronize ```getServiceExecutionContextForCustomer``` as well. In this method I see ```CustomerInfoThreadLocal.setDBHost(dbHost);```. This is the problem since the ```dbHost``` may be used as a global variable. If more than one threads come here there will be a problem. – zhh Jan 08 '18 at 10:05
  • 1
    It will be very hard to make thread safe in your case since you use a lot of global variable (those static methods). If you want some operations to run parallel you should make them not interfere with each other. – zhh Jan 08 '18 at 10:11