Xiang Zhou
Xiang Zhou

Reputation: 11

ejb+JPA Multi-tenancy with hibernate4, could not complete schema update: java.lang.NullPointerException

Now I have an application with jpa(hibernate4) mutlitenancy, but there are some exceptions, I use ejb3+jpa+wildfly, I don't know where is wrong, only one message java lang nullponinterexception:

Could not complete schema update: java.lang.NullPointerException
    at org.hibernate.tool.hbm2ddl.SuppliedConnectionProviderConnectionHelper.prepare(SuppliedConnectionProviderConnectionHelper.java:51) [hibernate-core-4.3.5.Final.jar:4.3.5.Final]
    at org.hibernate.tool.hbm2ddl.SchemaUpdate.execute(SchemaUpdate.java:194) [hibernate-core-4.3.5.Final.jar:4.3.5.Final]
    at org.hibernate.tool.hbm2ddl.SchemaUpdate.execute(SchemaUpdate.java:178) [hibernate-core-4.3.5.Final.jar:4.3.5.Final]
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:522) [hibernate-core-4.3.5.Final.jar:4.3.5.Final]
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1857) [hibernate-core-4.3.5.Final.jar:4.3.5.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850) [hibernate-entitymanager-4.3.5.Final.jar:4.3.5.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:843) [hibernate-entitymanager-4.3.5.Final.jar:4.3.5.Final]
    at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:397) [hibernate-core-4.3.5.Final.jar:4.3.5.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:842) [hibernate-entitymanager-4.3.5.Final.jar:4.3.5.Final]
    at org.jboss.as.jpa.hibernate4.TwoPhaseBootstrapImpl.build(TwoPhaseBootstrapImpl.java:44) [jipijapa-hibernate4-3-1.0.1.Final.jar:]
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:154) [wildfly-jpa-8.1.0.Final.jar:8.1.0.Final]
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:117) [wildfly-jpa-8.1.0.Final.jar:8.1.0.Final]
    at java.security.AccessController.doPrivileged(Native Method) [rt.jar:1.8.0_25]
    at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:474) [wildfly-security-manager-1.0.0.Final.jar:1.0.0.Final]
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:182) [wildfly-jpa-8.1.0.Final.jar:8.1.0.Final]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [rt.jar:1.8.0_25]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [rt.jar:1.8.0_25]
    at java.lang.Thread.run(Thread.java:745) [rt.jar:1.8.0_25]
    at org.jboss.threads.JBossThread.run(JBossThread.java:122) [jboss-threads-2.1.1.Final.jar:2.1.1.Final]


there are my persistence.xml 、 MultiTenantConnectionProviderImpl and CurrentTenantIdentifierResolverImpl

persistence.xml

      <persistence-unit name="basic-entity"
        transaction-type="JTA">

        <!-- <provider>net.bull.javamelody.JpaPersistence</provider> -->
        <provider>org.hibernate.ejb.HibernatePersistence</provider>




        <jta-data-source>java:jboss/datasources/JcMysqlDS</jta-data-source>

        <properties>
            <property name="hibernate.connection.username" value="root" />
            <property name="hibernate.connection.password" value="123456" />
            <property name="hibernate.connection.autocommit" value="true"/>
            <property name="hibernate.transaction.flush_before_completion"        value="true"/>
            <property name="hibernate.c3p0.min_size" value="5"/>
            <property name="hibernate.c3p0.max_size" value="32"/>
            <property name="hibernate.c3p0.timeout" value="15"/>
            <property name="hibernate.c3p0.max_statements" value="10"/>
            <property name="hibernate.c3p0.idle_test_period" value="300"/>
            <property name="hibernate.c3p0.unreturnedConnectionTimeout" value="95"/>
            <property name="hibernate.c3p0.debugUnreturnedConnectionStackTraces" 
                value="true"/>

            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" 
                />
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/itoo_basic" 
                />
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
            <!-- <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/> -->
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <property name="hibernate.show_sql" value="true" />

<property name="hibernate.default_schema" value="public"/>
            <property name="hibernate.multi_tenant_connection_provider"
            value="com.my.multi.MultiTenantConnectionProviderImpl"/>


            <property name="hibernate.tenant_identifier_resolver"
            value="com.my.multi.CurrentTenantIdentifierResolverImpl" 
                />
            <property name="hibernate.multiTenancy" value="SCHEMA" />
        </properties>
    </persistence-unit>

CurrentTenantIdentifierResolverImpl

       public class CurrentTenantIdentifierResolverImpl implements   CurrentTenantIdentifierResolver  {

       @Override
      public String resolveCurrentTenantIdentifier() {
         return "public";
      }

      @Override
      public boolean validateExistingCurrentSessions() {
        return false;
     }
}

class MultiTenantConnectionProviderImpl 

     public class MultiTenantConnectionProviderImpl implements
        MultiTenantConnectionProvider, Stoppable, ServiceRegistryAwareService     {
    /**
     * 
     */
      private static final long serialVersionUID = -5121435319787325293L;
      private  C3P0ConnectionProvider connectionProvider =null;

      @Override
      public boolean isUnwrappableAs(Class arg0) {
        // TODO Auto-generated method stub
        return false;
      }

      @Override
      public <T> T unwrap(Class<T> arg0) {
        // TODO Auto-generated method stub
        return null;
      }

      @Override
      public void stop() {
        // TODO Auto-generated method stub

      }

      @Override
      public Connection getAnyConnection() throws SQLException {
        return connectionProvider.getConnection();
       }

      @Override
      public Connection getConnection(String tenantIdentifier)
            throws SQLException {
         final Connection connection = getAnyConnection();
         try {
            connection.createStatement().execute("USE itoo_basic "  );
        } catch (SQLException e) {
            throw new HibernateException(
                    "Could not alter JDBC connection to specified schema ["
                            + tenantIdentifier + "]", e);
        }
        return connection;
    }

      @Override
       public void releaseAnyConnection(Connection connection) throws   SQLException {
        // TODO Auto-generated method stub
        connectionProvider.closeConnection(connection);
        //lazyDatasource.getConnection().close();
     }

      @Override
      public void releaseConnection(String tenantIdentifier, Connection   connection)
            throws SQLException {
        try {
            connection.createStatement().execute("USE master");
        } catch (SQLException e) {
            // on error, throw an exception to make sure the connection is   not
            // returned to the pool.
            // your requirements may differ`enter code here`
            throw new HibernateException(
                    "Could not alter JDBC connection to specified schema ["
                            + tenantIdentifier + "]", e);
        }
        connectionProvider.closeConnection(connection);
        //lazyDatasource.getConnection().close();

       }

      @Override
      public boolean supportsAggressiveRelease() {
        // TODO Auto-generated method stub
        return false;
      }

      @Override
      public void injectServices(ServiceRegistryImplementor serviceRegistry)        {
        // TODO Auto-generated method stub

          Map lSettings =     serviceRegistry.getService(ConfigurationService.class).getSettings();

        connectionProvider = new C3P0ConnectionProvider();
         connectionProvider.injectServices(serviceRegistry);
          connectionProvider.configure(lSettings);
       }

       }

I use schema. Can anybody help me?

Upvotes: 1

Views: 637

Answers (1)

GHajba
GHajba

Reputation: 3691

If you look at the code in org.hibernate.engine.jdbc.internal.JdbcServicesImpl.buildJdbcConnectionAccess(Map) you can see that it fills the "default" connection provider with the value null. So the schema update with Hibernate fails and throws this nasty NullPointerException.

This is because it would only update the default schema when starting the application -- and if you switch to another one it might not be updated.

So the solution is to disable the line <property name="hibernate.hbm2ddl.auto" value="update" /> and update the schemas on your own.

Upvotes: 1

Related Questions