我们使用MySQL主从设置来存储REST API中使用的数据 .
我们计划直接到master db-host或slave db-host依赖REST请求参数 .
为此,我们使用MySQL ReplicationDriver . 我们使用MyBatis作为DB和API之间的一层.Spring被用作IOC框架 .
我们已经定义了两个方法,它们从DB中检索数据的逻辑相同 . 这两种方法之间的区别仅在于,一种方法在@Transactional注释中具有“readOnly = true”,它将指向“slave”,另一种方法具有“readOnly = false”,它将指向“master” .
@Override
@Transactional(value = "itemTrxManager", readOnly = true, rollbackFor = Exception.class)
public Item getShopItemFromSlave(ItemGetKey itemKey, Options... opts) throws ItemException {
..
}
@Override
@Transactional(value = "itemTrxManager", readOnly = false, rollbackFor = Exception.class)
public Item getShopItemFromMaster(ItemGetKey itemKey, Options... opts) throws ItemException {
..
}
但是我们注意到内部ReplicationDriver(MySQLConnection对象)始终指向它连接的第一个主机,并且在更改“readOnly”标志后不会更改 .
即:启动我们的API后,如果我们发送使用“slave”的请求,ReplicationDriver将使用“slave host”,即使我们改为使用“master”,它仍然指向“slave host” . 其他方面是相同的:启动我们的API后,如果我们发送请求使用“master”,ReplicationDriver将使用“master host”,然后如果更改为使用“slave”,它仍然指向“master host” .
请注意,所有日志(Apache DBCP,Spring DAO,MyBatis日志)显示它连接到正确的主机,但在调试之后我们发现问题出在MySQL驱动程序类中(MySQLConnection对象显示不正确的主机名).ie连接对象已从Apache DBCP DataSource和内部MySQLConnection对象显示不同的主机信息 .
例如,下面显示了我们日志中的一个片段 . 它说它连接到“slave”,当调试MySQL Driver内部类时,ReplicationDriver有关于“master”的信息 .
DEBUG [http-8080-2] [AbstractPlatformTransactionManager.java:365] - 使用名称[com.foo.bar.item.core.businesslogic.impl.MerchantCategoryBusinessLogicImpl.listMerchantCategory]创建新事务:PROPAGATION_REQUIRED,ISOLATION_DEFAULT; 'itemTrxManager'DEBUG [http-8080-2] [DataSourceTransactionManager.java:204] - 用于JDBC事务的获取连接[jdbc:mysql:// master-host:3301 /,UserName =item_user@10.9.203.50,MySQL Connector Java] DEBUG [http-8080-2] [DataSourceUtils.java:153] - 设置JDBC连接[jdbc:mysql:// master-host:3301 /,UserName =item_user @ 10.9.203.50,MySQL Connector Java]只读DEBUG [ http-8080-2] [Slf4jImpl.java:47] - 创建一个新的SqlSession DEBUG [http-8080-2] [Slf4jImpl.java:47] - 为SqlSession注册事务同步[org.apache.ibatis.session.defaults . DefaultSqlSession @ 329203a8] DEBUG [http-8080-2] [Slf4jImpl.java:47] - JDBC连接[jdbc:mysql:// slave-host:3306 /,UserName =item_user @ 10.9.203.50,MySQL Connector Java]将是由Spring DEBUG管理[http-8080-2] [Slf4jImpl.java:47] - ooo使用Connection [jdbc:mysql:// slave-host:3306 /,UserName =item_user @ 10.9.203.50,MySQL Connector Java] DEBUG [ http-8080-2] [Slf4jImpl.java:47] - ==>准备:选择商家来自glb_merchant_cat_tbl的_category_id,custom_category_id,merchant_id,parent_id,sibling_position,image_url,create_time,update_time,其中merchant_id =? . . . DEBUG [http-8080-2] [Slf4jImpl.java:47] - 事务同步提交SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@329203a8] DEBUG [http-8080-2] [Slf4jImpl.java:47] - 事务同步关闭SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@329203a8] DEBUG [http-8080-2] [DataSourceUtils.java:222] - 重置JDBC连接的只读标志[jdbc:mysql:/ / slave-host:3306 /,UserName=item_user@10.9.203.50,MySQL Connector Java] DEBUG [http-8080-2] [DataSourceTransactionManager.java:322] - 发布JDBC连接[jdbc:mysql:// master-host:事务DEBUG之后的3301 /,UserName=item_user@10.9.203.50,MySQL Connector Java] [http-8080-2] [DataSourceUtils.java:332] - 返回到DataSource的JDBC连接
如何解决这个问题呢?这可能是ReplicationDriver中的错误?
Update :
这是我们的 Spring 天背景:
<!-- this is needed for the annotated transactions to work -->
<tx:annotation-driven transaction-manager="trx-manager-item" proxy-target-class="true" />
<bean id="trx-manager-item" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="itemDataSource" />
<qualifier value="itemTrxManager" />
</bean>
连接网址:
jdbc:mysql:replication:// master-host:3301,master-slave:3301 / item2_1?allowMasterDownConnections = true&roundRobinLoadBalance = true&autoReconnectForPools = true
Context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/item"
auth="Container"
type="javax.sql.DataSource"
factory="com.foo.bar.dbcp.BasicDataSourceFactory"
driverClassName="com.mysql.jdbc.Driver"
defaultAutoCommit="false"
defaultTransactionIsolation="READ_COMMITTED"
removeAbandonedTimeout="600"
timeBetweenEvictionRunsMillis="60000"
minEvictableIdleTimeMillis="60000"
logAbandoned="true"
poolPreparedStatements="true"
removeAbandoned="true"
testOnBorrow="false"
testOnReturn="false"
validationQuery="select null"
testWhileIdle="true"
/>
连接URL在com.foo.bar.dbcp.BasicDataSourceFactory类中设置 .