简体   繁体   English

使用ReplicationDriver在mysql从属服务器上调用存储过程

[英]Call stored procedure on mysql slave using ReplicationDriver

I have a Spring application that currently executes some queries utilizing stored procedures. 我有一个Spring应用程序,当前使用存储过程执行一些查询。 The configuration is something like this: 配置是这样的:

Datasource: 数据源:

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

Now when I call getCombinedDeviceRouting(...) it fails with the following exception: 现在,当我调用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

I know the connection is read-only and I need it to be that way so the queries are load-balanced between slave hosts. 我知道连接是只读的,因此我需要这样做,以便在从属主机之间实现查询负载平衡。 But the stored procedure is actually read only, it's just a lot of SELECT statements, in fact I tried adding READS SQL DATA to its definition but it didn't work. 但是存储过程实际上是只读的,它只是很多SELECT语句,实际上我尝试将READS SQL DATA添加到其定义中,但是没有用。

Finally I came to the point of reading the mysql's connector code and I found this: 最后,我来到阅读mysql连接器代码的地步,发现了这一点:

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

It sounds naive, but is the connector checking whether my statement is read-only by just matching the first character with 'S'? 这听起来很幼稚,但是连接器是否仅通过将第一个字符与'S'匹配来检查我的语句是否为只读? If this is the case, it seems like there's no way of calling a stored procedure on a slave host, because the statement starts with 'C' (CALL ...). 在这种情况下,似乎无法在从属主机上调用存储过程,因为该语句以'C'(CALL ...)开头。

Does anyone know if there's a workaround for this problem? 有人知道这个问题是否有解决方法吗? Or maybe I'm wrong assuming this first character check? 还是我认为这是第一个字符检查错了?

看来这是驱动程序的错误,我看了一下代码,看是否有一个简单的扩展点,但是看来您必须扩展很多类才能影响此行为:(

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM