Search code examples
javamysqljdbcopenjpamaster-slave

mysql master/slave replication issue: Cannot create PoolableConnectionFactory


I have spent a lot of time but could not figure it out. I know that, If I use the BasicDataSource then the configuration needs to passed in the openjpa.ConnectionProperties property. The openjpa.ConnectionProperties is comma (,) separated properties which get mapped to the DataSource instance. Now MySQL also expects the hosts in comma (,) separated format. So not able to figure out, How do I create an DataSource with MySQL replication?*

I am trying to setup master/slave db with openjpa and it fails with the below exception while creating the createEntityManager() from the EntityManagerFactory.

Here is the code:

String driver ="com.mysql.jdbc.ReplicationDriver";
String url = "jdbc:mysql:replication://master:3306,slave:3306/db";
String user = "abc";
String password = "123";
String connProps = "DriverClassName={0},Url={1},Username={2},Password={3}";

public void method() {
    connProps = MessageFormat.format(connProps, driver, url, user, password);
    Properties props = new Properties();
    props.setProperty("openjpa.ConnectionProperties", connProps);
    props.setProperty("openjpa.ConnectionDriverName", "org.apache.commons.dbcp.BasicDataSource");
    EntityManagerFactory factory = Persistence.createEntityManagerFactory("mysql", props);
    EntityManager manager = factory.createEntityManager();
}

I getting the following exception:

Exception in thread "main" <openjpa-2.4.1-r422266:1730418 fatal general error> org.apache.openjpa.persistence.PersistenceException: Cannot create PoolableConnectionFactory (Must specify at least one slave host to connect to for master/slave replication load-balancing functionality)
    at org.apache.openjpa.jdbc.sql.DBDictionaryFactory.newDBDictionary(DBDictionaryFactory.java:106)
    at org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl.getDBDictionaryInstance(JDBCConfigurationImpl.java:603)
    at org.apache.openjpa.jdbc.meta.MappingRepository.endConfiguration(MappingRepository.java:1520)
    at org.apache.openjpa.lib.conf.Configurations.configureInstance(Configurations.java:533)
    at org.apache.openjpa.lib.conf.Configurations.configureInstance(Configurations.java:458)
    at org.apache.openjpa.lib.conf.PluginValue.instantiate(PluginValue.java:121)
    at org.apache.openjpa.conf.MetaDataRepositoryValue.instantiate(MetaDataRepositoryValue.java:68)
    at org.apache.openjpa.lib.conf.ObjectValue.instantiate(ObjectValue.java:83)
    at org.apache.openjpa.conf.OpenJPAConfigurationImpl.newMetaDataRepositoryInstance(OpenJPAConfigurationImpl.java:967)
    at org.apache.openjpa.conf.OpenJPAConfigurationImpl.getMetaDataRepositoryInstance(OpenJPAConfigurationImpl.java:958)
    at org.apache.openjpa.kernel.AbstractBrokerFactory.makeReadOnly(AbstractBrokerFactory.java:642)
    at org.apache.openjpa.kernel.AbstractBrokerFactory.newBroker(AbstractBrokerFactory.java:202)
    at org.apache.openjpa.kernel.DelegatingBrokerFactory.newBroker(DelegatingBrokerFactory.java:154)
    at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:226)
    at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:153)
    at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:59)
    at ExampleJPA.method(ExampleJPA.java:22)
    at ExampleJPA.main(ExampleJPA.java:27)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (Must specify at least one slave host to connect to for master/slave replication load-balancing functionality)
    at org.apache.commons.dbcp.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:1549)
    at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1388)
    at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
    at org.apache.openjpa.lib.jdbc.DelegatingDataSource.getConnection(DelegatingDataSource.java:110)
    at org.apache.openjpa.lib.jdbc.DecoratingDataSource.getConnection(DecoratingDataSource.java:86)
    at org.apache.openjpa.jdbc.sql.DBDictionaryFactory.newDBDictionary(DBDictionaryFactory.java:90)
    ... 22 more
Caused by: java.sql.SQLException: Must specify at least one slave host to connect to for master/slave replication load-balancing functionality
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:896)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:885)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860)
    at com.mysql.jdbc.NonRegisteringDriver.connectReplicationConnection(NonRegisteringDriver.java:414)
    at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:313)
    at org.apache.commons.dbcp.DriverConnectionFactory.createConnection(DriverConnectionFactory.java:38)
    at org.apache.commons.dbcp.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:582)
    at org.apache.commons.dbcp.BasicDataSource.validateConnectionFactory(BasicDataSource.java:1556)
    at org.apache.commons.dbcp.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:1545)
    ... 27 more

The master slave setup of the database is seems to working fine. I have checked the connectivity of the slave from master through telnet.


Solution

  • This solution seems silly after spending so much time on it. I got this working. I need to pass the jdbc url with double quotes ("jdbc:mysql:replication://master:3306,slave:3306/db") and then works fine.

    I will provide the more information soon.