java - 使用 ReplicationDriver 在 mysql slave 上调用存储过程

标签 java mysql jdbc mysql-connector master-slave

我有一个 Spring 应用程序,它当前使用存储过程执行一些查询。配置是这样的:

数据源:

<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.ReplicationDriver"/>
    <property name="url" value="jdbc:mysql:replication://master,slave1,slave2/db?allowMultiQueries=true"/>
    <property name="username" value="${db.dbusername}"/>
    <property name="password" value="${db.dbpassword}"/>
    <property name="defaultReadOnly" value="true"/>
</bean>
<bean id="jdbcDeviceDAO" class="dao.jdbc.JdbcDeviceDAO">
    <property name="dataSource" ref="dataSource"/>
</bean>

DAO:

public class JdbcDeviceDAO implements DeviceDAO {
    // ...

    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
        this.procGetCombinedDeviceRouting = new SimpleJdbcCall(jdbcTemplate)
                .withProcedureName("get_combined_device_routing");
        // ...
    }

    public CombinedDeviceRouting getCombinedDeviceRouting(String deviceName, String deviceNameType) {
        SqlParameterSource in = createParameters(deviceName, deviceNameType);

        Map<String, Object> results = this.procGetCombinedDeviceRouting.execute(in);

        return extractResults(results);
    }

现在,当我调用 getCombinedDeviceRouting(...) 时,它会失败并出现以下异常:

org.springframework.dao.TransientDataAccessResourceException: CallableStatementCallback; SQL [{call get_combined_device_routing()}]; Connection is read-only. Queries leading to data modification are not allowed; nested exception is java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed

我知道连接是只读的,我需要它是那样的,以便查询在从属主机之间实现负载平衡。但是存储过程实际上是只读的,它只是很多 SELECT 语句,实际上我尝试将 READS SQL DATA 添加到它的定义中但是它没有用。

最后我到了阅读 mysql 的连接器代码的地步,我发现了这个:

protected boolean checkReadOnlySafeStatement() throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
        return this.firstCharOfStmt == 'S' || !this.connection.isReadOnly();
    }
}

这听起来很天真,但是连接器是否仅通过将第一个字符与“S”匹配来检查我的语句是否只读? 如果是这种情况,似乎无法在从属主机上调用存储过程,因为该语句以“C”开头(CALL ...)。

有谁知道这个问题是否有解决方法?或许我假设这第一个字符检查是错误的?

最佳答案

看起来好像this is a bug with the driver我查看了代码,看看是否有一个简单的扩展点,但看起来您必须扩展很多类才能影响此行为:(

关于java - 使用 ReplicationDriver 在 mysql slave 上调用存储过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24069407/

相关文章:

java - 如何将java程序交付给客户?

java - Qulice - 如何在整个项目中禁用需要 package-info.java 的规则?

java - 在 GAE 项目上调试时,Eclipse Oxygen 服务器启动速度非常慢。服务器进程挂起并处于停止挂起状态

php - 关键问题: Which key strategy should I use in my database?

java - 这是通过 jdbc 连接和断开 mysql 的安全方法吗?

java - 如何使用 xpath Java Selenium 获取所有包含指定文本的 td 标签?

MySQL对三个相互连接的表进行连接查询

Java Enum 类型与 Hibernate

eclipse - 如何在Eclipse Web项目中安装JDBC驱动程序而不面临java.lang.ClassNotFoundException

java - 使用 JDBC 在 mysql 表中插入和更新