本文只说明如何使用zebra进行分库分表,不涉及原理源码
一 数据源配置文件
<bean id="shardDataSource" class="com.dianping.zebra.shard.jdbc.ShardDataSource" init-method="init"> <!-- lion配置方式,需配置shardds.xxx.shard项value为json格式 --> //所以实际对应的rule的配置的key是shardds.trade.shard <property name="ruleName" value="trade"/> <!-- 主动配置分库,lion配置下可选,xml配置必输 --> <property name="dataSourcePool">//这里能做分库的原因就是用一个map就可以配多个数据库了 <map> <entry key="ds0" value-ref="dataSource2"/><!-- 该处的key即为配置里面的dbIndexes --> // ds0可以根据开发习惯起名的,也可以叫db0... </map> </property> <!-- 内部写线程池参数,默认32-64-5000 拒绝策略-报错 --> <property name="parallelCorePoolSize" value="8"/> <property name="parallelMaxPoolSize" value="24"/> <property name="parallelWorkQueueSize" value="1000"/> <!-- 内部读线程池参数,默认32-64-5000 拒绝策略-报错 --> <property name="readWriteSplitPool" value="true"/> <property name="readParallelCorePoolSize" value="24"/> <property name="readParallelMaxPoolSize" value="24"/> <property name="readParallelWorkQueueSize" value="1000"/> <!-- 并行度设置 --> <property name="concurrencyLevel" value="8"/> <!-- 内部执行器设置任务超时时间,默认:1000ms --> <property name="parallelExecuteTimeOut" value="5000"/> </bean>
<bean id="dataSource2" class="com.dianping.zebra.group.jdbc.GroupDataSource" init-method="init"> <property name="jdbcRef" value="trade"/> //这个就是特色了 会根据value里的值,构造key去lion中查询值 <property name="initialPoolSize" value="10"/> <property name="minPoolSize" value="10"/> <property name="maxPoolSize" value="45"/> <property name="checkoutTimeout" value="3000"/> <property name="maxIdleTime" value="1800"/> <property name="idleConnectionTestPeriod" value="1800"/> <property name="acquireRetryAttempts" value="3"/> <property name="acquireRetryDelay" value="300"/> <property name="maxStatements" value="0"/> <property name="maxStatementsPerConnection" value="100"/> <property name="numHelperThreads" value="6"/> <property name="testConnectionOnCheckin" value="false"/> <property name="testConnectionOnCheckout" value="true"/> <property name="maxAdministrativeTaskTime" value="5"/> <property name="preferredTestQuery" value="SELECT 1"/> <property name="extraJdbcUrlParams" value="connectTimeout=1000" /> </bean>
这个GroupDataSource就是实现读写分离的关键,一个GroupDataSource 都会包含至少两个SingleDataSource。这里找的过程大概是这样的
根据trade拼出来key,groupds.trade.mapping 然后再拿着这个key找value
比如我们公司的lion中的配置就是这样的
keygroupds.trade.mapping value (trade-m1-read:1),(trade-m1-write)
接下来才是通过上一步得到的每个读写数据库的名字获取jdbc的url
比如在lion中保存jdbc的key为 ds.trade-m1-write.jdbc.url这其中的trade就是用jdbcRef的value拼出来的
公司的key-value是这样的
ds.trade-m1-write.jdbc.url | jdbc:mysql://wnojrdevmysql.service.dev.consul:3306/trade?characterEncoding=utf8& |
二 分库分表规则
注意到上面的ShardDataSource中的一个配置项
<property name="ruleName" value="trade"/>
那么这个ruleName是怎么找到的呢?答案就是到lion上找的
最后会拼出来一个key shardds.trade.shard
找出来的value是这样的。这里配置项很多,只选取一个订单表来说明
{ "tableShardConfigs": [ { "tableName": "tp_order", "dimensionConfigs": [ { "dbRule": "#id#.longValue() % 1", "dbIndexes": "ds0", "tbRule": "(#id#>>17) % 64", "tbSuffix": "everydb:[_0,_63]", "isMaster": true } ], "generatedPK": "id" },
- dbRule 分库规则,按照订单的id进行分库,由于是 %1,所以在dev下我们只有一个数据库
- dbIndexes 上面配数据源的地方配的数据源key,上面配的是ds0,所以这里也得是ds0.如果是多个数据库可以这么配 db[0-3]。
- tbRule 分表规则,很好理解,id右移17位后取模64,表示分64张表
- tbSuffix 表名后缀,everydb表示每个库下都有64张表0-63,该配置还可以alldb,如果是两个库,表名就是0-127了
- isMaster 这里就比较复杂了,就是说分库分表规则是根据一个字段来进行,配置为true说明是不是主字段,一般像订单表orderid就够了
如何强制走主库
在写sql的时候加上这句
/*+zebra:w*/SELECT <include refid="Base_Column_List"/> FROM tp_order_bill_item WHERE order_id = #{orderId} and is_valid = 1