我们使用MySQL主从设置来存储REST API中使用的数据。
我们计划指向主数据库主机或从数据库主机依赖于REST请求参数。
为实现这一目标,我们使用MySQL ReplicationDriver。我们使用MyBatis作为DB和API之间的一层.Spring被用作IOC框架。
我们已经定义了两个方法,它们从DB中检索数据的逻辑相同。 这两种方法之间的区别仅在于,一种方法具有" readOnly = true"在@Transactional注释中,它将指向" 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"之后不会改变。标志。
ie:启动我们的API之后,如果我们发送请求使用" slave" ,ReplicationDriver将使用" slave host"即使我们改为使用" master",它仍然指向" slave host"。 其他方面是相同的:在启动我们的API后,如果我们发送请求使用" master" ,ReplicationDriver将使用" master host"然后如果改为使用" slave",它仍然指向"主控主机"。
请注意,所有日志(Apache DBCP,Spring DAO,MyBatis日志)都显示它连接到正确的主机,但在调试之后我们发现问题出在MySQL驱动程序类中(MySQLConnection对象显示错误的主机名).ie Connection从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:mysql:// master-host:3301 /, 用户名为=item_user@10.9.203.50,用于JDBC的MySQL Connector Java transaction 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]调查 [http-8080-2] [Slf4jImpl.java:47] - JDBC连接 [jdbc:mysql:// slave-host:3306 /,UserName=item_user@10.9.203.50,MySQL 连接器Java]将由Spring DEBUG [http-8080-2]管理 [Slf4jImpl.java:47] - ooo使用连接 [jdbc:mysql:// slave-host:3306 /,UserName=item_user@10.9.203.50,MySQL 连接器Java] DEBUG [http-8080-2] [Slf4jImpl.java:47] - ==> 准备:选择merchant_category_id,custom_category_id, merchant_id,parent_id,sibling_position,image_url,create_time, 来自glb_merchant_cat_tbl的update_time,其中merchant_id =?
。 。
DEBUG [http-8080-2] [Slf4jImpl.java:47] - 事务同步 提交SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@329203a8]调查 [http-8080-2] [Slf4jImpl.java:47] - 事务同步 关闭SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@329203a8]调查 [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:3301 /, UserName =item_user@10.9.203.50,MySQL Connector Java]之后 transaction DEBUG [http-8080-2] [DataSourceUtils.java:332] - 返回 JDBC连接到DataSource
如何解决这个问题?这可能是ReplicationDriver中的一个错误?
更新:
这是我们的春天背景:
<!-- 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的:复制://主主机:3301,主从:3301 / ITEM2_1 allowMasterDownConnections =真安培; roundRobinLoadBalance =真安培; autoReconnectForPools =真
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类中设置。