2014-06-05 37 views
2

我有一個Spring應用程序,當前使用存儲過程執行一些查詢。配置是這樣的:使用ReplicationDriver在mysql slave上調用存儲過程

數據源:

<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 ...)開頭。

有沒有人知道是否有解決這個問題的解決方法?或者,也許我錯了,假設第一個字符檢查?

回答

1

看起來好像this is a bug with the driver我看了看代碼是否有一個簡單的擴展點,但它看起來像你不得不擴展很多類來影響這種行爲:(