mysql master/slave 复制问题:无法创建 PoolableConnectionFactory
mysql master/slave replication issue: Cannot create PoolableConnectionFactory
我花了很多时间还是想不通。我知道,如果我使用 BasicDataSource
,那么配置需要传入 openjpa.ConnectionProperties
属性。 openjpa.ConnectionProperties
是逗号 (,) 分隔的属性,映射到 DataSource
instance. Now MySQL 也需要逗号 (,) 分隔格式的主机。所以无法弄清楚,如何使用 MySQL replication
创建一个 DataSource
?*
我正在尝试使用 openjpa 设置 master/slave 数据库,但在从 EntityManagerFactory
.
创建 createEntityManager()
时失败并出现以下异常
代码如下:
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();
}
我收到以下异常:
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
数据库的主从设置似乎工作正常。我已经通过 telnet 从主机检查了从机的连接。
JDBC URL 传递给 MySQL 驱动不是你想的那样。
MySQL 驱动程序正在尝试解析 URL 并使用 ","
令牌
拆分它
if ((hostStuff != null) && (hostStuff.trim().length() > 0)) {
List<String> hosts = StringUtils.split(hostStuff, ",", ALLOWED_QUOTES, ALLOWED_QUOTES, false);
但它找不到不止一个,所以它产生错误:
int numHosts = Integer.parseInt(parsedProps.getProperty(NUM_HOSTS_PROPERTY_KEY));
if (numHosts < 2) {
throw SQLError.createSQLException("Must specify at least one slave host to connect to for master/slave replication load-balancing functionality",
SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE, null);
}
DBCP 或 OpenJPA 很可能 JDBC URL modified/broken。
Link 到 source
我认为错误的原因是使用 openjpa.ConnectionProperties
在一个字符串中设置属性,以逗号作为分隔符,而 属性 URL
的值也是以逗号分隔
根据@rkosegi 的回答,与逗号“,”相关的问题搞砸了,我认为您必须使用分隔的属性而不是 1 个字符串来解决这个问题。或者至少考虑删除 Url={1},
并使用 openjpa.ConnectionURL
进行设置
这是我认为您需要在 method()
中做的事情:
props.setProperty("openjpa.ConnectionDriverName", "org.apache.commons.dbcp.BasicDataSource");
props.setProperty("openjpa.ConnectionUserName", user);
props.setProperty("openjpa.ConnectionPassword", password);
props.setProperty("openjpa.ConnectionURL", url);
删除行:
props.setProperty("openjpa.ConnectionProperties", connProps);
不要再使用 String connProps = "DriverClassName={0},Url={1},Username={2},Password={3}";
。
P.S:请注意,您使用的是 "org.apache.commons.dbcp.BasicDataSource"
而不是 driver
参数。只要确保那是你想要的。
在花了这么多时间之后,这个解决方案似乎很愚蠢。我得到了这个工作。我需要用双引号 ("jdbc:mysql:replication://master:3306,slave:3306/db"
) 传递 jdbc url 然后工作正常。
我会尽快提供更多信息。
我花了很多时间还是想不通。我知道,如果我使用 BasicDataSource
,那么配置需要传入 openjpa.ConnectionProperties
属性。 openjpa.ConnectionProperties
是逗号 (,) 分隔的属性,映射到 DataSource
instance. Now MySQL 也需要逗号 (,) 分隔格式的主机。所以无法弄清楚,如何使用 MySQL replication
创建一个 DataSource
?*
我正在尝试使用 openjpa 设置 master/slave 数据库,但在从 EntityManagerFactory
.
createEntityManager()
时失败并出现以下异常
代码如下:
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();
}
我收到以下异常:
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
数据库的主从设置似乎工作正常。我已经通过 telnet 从主机检查了从机的连接。
JDBC URL 传递给 MySQL 驱动不是你想的那样。
MySQL 驱动程序正在尝试解析 URL 并使用 ","
令牌
if ((hostStuff != null) && (hostStuff.trim().length() > 0)) {
List<String> hosts = StringUtils.split(hostStuff, ",", ALLOWED_QUOTES, ALLOWED_QUOTES, false);
但它找不到不止一个,所以它产生错误:
int numHosts = Integer.parseInt(parsedProps.getProperty(NUM_HOSTS_PROPERTY_KEY));
if (numHosts < 2) {
throw SQLError.createSQLException("Must specify at least one slave host to connect to for master/slave replication load-balancing functionality",
SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE, null);
}
DBCP 或 OpenJPA 很可能 JDBC URL modified/broken。
Link 到 source
我认为错误的原因是使用 openjpa.ConnectionProperties
在一个字符串中设置属性,以逗号作为分隔符,而 属性 URL
的值也是以逗号分隔
根据@rkosegi 的回答,与逗号“,”相关的问题搞砸了,我认为您必须使用分隔的属性而不是 1 个字符串来解决这个问题。或者至少考虑删除 Url={1},
并使用 openjpa.ConnectionURL
这是我认为您需要在 method()
中做的事情:
props.setProperty("openjpa.ConnectionDriverName", "org.apache.commons.dbcp.BasicDataSource");
props.setProperty("openjpa.ConnectionUserName", user);
props.setProperty("openjpa.ConnectionPassword", password);
props.setProperty("openjpa.ConnectionURL", url);
删除行:
props.setProperty("openjpa.ConnectionProperties", connProps);
不要再使用 String connProps = "DriverClassName={0},Url={1},Username={2},Password={3}";
。
P.S:请注意,您使用的是 "org.apache.commons.dbcp.BasicDataSource"
而不是 driver
参数。只要确保那是你想要的。
在花了这么多时间之后,这个解决方案似乎很愚蠢。我得到了这个工作。我需要用双引号 ("jdbc:mysql:replication://master:3306,slave:3306/db"
) 传递 jdbc url 然后工作正常。
我会尽快提供更多信息。