藉助sharding-jdbc實現資料分片
阿新 • • 發佈:2018-12-28
1、引入依賴:
<!-- 引入sharding-jdbc -->
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>${shardingjdbc.version}</version>
</dependency>
< dependency>
<groupId>com.dangdang</groupId>
<artifactId>sharding-jdbc-transaction</artifactId>
<version>${shardingjdbc.version}</version>
</dependency>
<dependency>
<groupId>com.dangdang</ groupId>
<artifactId>sharding-jdbc-config-yaml</artifactId>
<version>${shardingjdbc.version}</version>
</dependency>
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>sharding-jdbc-config-spring</ artifactId>
<version>${shardingjdbc.version}</version>
</dependency>
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>sharding-jdbc-self-id-generator</artifactId>
<version>${shardingjdbc.version}</version>
</dependency>
2、spring配置檔案:
<!-- 主庫資料來源 -->
<bean id="masterDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<!-- 資料庫基本資訊配置 -->
<property name="driverClassName" value="${data1.jdbc.driverClassName}" />
<property name="url" value="${data1.jdbc.url}" />
<property name="username" value="${data1.jdbc.username}" />
<property name="password" value="${data1.jdbc.password}" />
<!-- 初始化連線數量 -->
<property name="initialSize" value="1" />
<!-- 最大併發連線數 -->
<property name="maxActive" value="20" />
<!-- 最大空閒連線數 -->
<!--<property name="maxIdle" value="3" />-->
<!-- 最小空閒連線數 -->
<property name="minIdle" value="1" />
<!-- 配置獲取連線等待超時的時間 -->
<property name="maxWait" value="60000" />
<!-- 超過時間限制是否回收 -->
<property name="removeAbandoned" value="true" />
<!-- 超過時間限制多長; -->
<property name="removeAbandonedTimeout" value="180" />
<!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連線,單位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一個連線在池中最小生存的時間,單位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000" />
<!-- 用來檢測連線是否有效的sql,要求是一個查詢語句-->
<property name="validationQuery" value="SELECT 1 FROM DUAL" />
<!-- 申請連線的時候檢測 -->
<property name="testWhileIdle" value="true" />
<!-- 申請連線時執行validationQuery檢測連線是否有效,配置為true會降低效能 -->
<property name="testOnBorrow" value="false" />
<!-- 歸還連線時執行validationQuery檢測連線是否有效,配置為true會降低效能 -->
<property name="testOnReturn" value="false" />
<!-- 開啟PSCache,並且指定每個連線上PSCache的大小 -->
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize" value="50" />
</bean>
<bean id="salveDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<!-- 資料庫基本資訊配置 -->
<property name="driverClassName" value="${data2.jdbc.driverClassName}" />
<property name="url" value="${data2.jdbc.url}" />
<property name="username" value="${data2.jdbc.username}" />
<property name="password" value="${data2.jdbc.password}" />
<!-- 初始化連線數量 -->
<property name="initialSize" value="1" />
<!-- 最大併發連線數 -->
<property name="maxActive" value="20" />
<!-- 最大空閒連線數 -->
<!--<property name="maxIdle" value="3" />-->
<!-- 最小空閒連線數 -->
<property name="minIdle" value="1" />
<!-- 配置獲取連線等待超時的時間 -->
<property name="maxWait" value="60000" />
<!-- 超過時間限制是否回收 -->
<property name="removeAbandoned" value="true" />
<!-- 超過時間限制多長; -->
<property name="removeAbandonedTimeout" value="180" />
<!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連線,單位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一個連線在池中最小生存的時間,單位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000" />
<!-- 用來檢測連線是否有效的sql,要求是一個查詢語句-->
<property name="validationQuery" value="SELECT NOW() FROM DUAL" />
<!-- 申請連線的時候檢測 -->
<property name="testWhileIdle" value="true" />
<!-- 申請連線時執行validationQuery檢測連線是否有效,配置為true會降低效能 -->
<property name="testOnBorrow" value="false" />
<!-- 歸還連線時執行validationQuery檢測連線是否有效,配置為true會降低效能 -->
<property name="testOnReturn" value="false" />
<!-- 開啟PSCache,並且指定每個連線上PSCache的大小 -->
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize" value="50" />
</bean>
<!-- 分庫演算法、根據user_id % n(n為資料庫個數)分庫-->
<rdb:strategy id="databaseShardingStrategy" sharding-columns="user_id" algorithm-class="com.wangcw.sharding.SingleKeyModuloDatabaseShardingAlgorithm"/>
<!-- 分表演算法、根據 id % n (n為分表數)分庫-->
<rdb:strategy id="tableShardingStrategy" sharding-columns="id" algorithm-class="com.wangcw.sharding.SingleKeyModuloTableShardingAlgorithm"/>
<!--因為我只有一張表。所以就只需要配置一個dataSource-->
<rdb:data-source id="shardingDataSource">
<rdb:sharding-rule data-sources="masterDataSource, salveDataSource" default-data-source="masterDataSource">
<rdb:table-rules>
<!-- 邏輯表名:t_user 實際表名:t_user_0、t_user_1 -->
<rdb:table-rule logic-table="t_user" actual-tables="t_user_0,t_user_1" database-strategy="databaseShardingStrategy" table-strategy="tableShardingStrategy">
<!-- 設定id自增 -->
<rdb:auto-increment-column column-name="id"/>
</rdb:table-rule>
</rdb:table-rules>
</rdb:sharding-rule>
</rdb:data-source>
<!-- session使用資料來源 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="shardingDataSource" />
<!-- 指定mybaits於spring結合的配置檔案 -->
<property name="configLocation" value="classpath:sqlMapcfg.xml" />
<!-- 指定mapper地址 -->
<property name="mapperLocations" value="classpath*:mappers/*.xml"></property>
</bean>
<!-- 指定dao介面地址即注入seqSessionFactory -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.wangcw.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
<!-- 事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="shardingDataSource" />
</bean>
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager">
<ref local="transactionManager" />
</property>
</bean>
<!-- 開啟切面註解支援 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 開啟事務的Annotation支援 -->
<tx:annotation-driven transaction-manager="transactionManager" />
3、分庫演算法
public class SingleKeyModuloDatabaseShardingAlgorithm implements
SingleKeyDatabaseShardingAlgorithm<Integer> {
/* 分庫個數 */
private int dbCount = 2;
@Override
public String doEqualSharding(
final Collection<String> availableTargetNames,
final ShardingValue<Integer> shardingValue) {
for (String each : availableTargetNames) {
if (each.endsWith(shardingValue.getValue() % dbCount + "")) {
return each;
}
}
throw new UnsupportedOperationException();
}
@Override
public Collection<String> doInSharding(
final Collection<String> availableTargetNames,
final ShardingValue<Integer> shardingValue) {
Collection<String> result = new LinkedHashSet<>(
availableTargetNames.size());
Collection<Integer> values = shardingValue.getValues();
for (Integer value : values) {
for (String dataSourceName : availableTargetNames) {
if (dataSourceName.endsWith(value % dbCount + "")) {
result.add(dataSourceName);
}
}
}
return result;
}
@Override
public Collection<String> doBetweenSharding(
final Collection<String> availableTargetNames,
final ShardingValue<Integer> shardingValue) {
Collection<String> result = new LinkedHashSet<>(availableTargetNames.size());
Range<Integer> range = shardingValue.getValueRange();
for (Integer i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
for (String each : availableTargetNames) {
if (each.endsWith(i % dbCount + "")) {
result.add(each);
}
}
}
return result;
}
/**
* 設定database分庫的個數
*
* @param dbCount
*/
public void setDbCount(int dbCount) {
this.dbCount = dbCount;
}
}
4、分表演算法
public class SingleKeyModuloTableShardingAlgorithm implements
SingleKeyTableShardingAlgorithm<Integer> {
/* 分表個數 */
private int tableCount = 2;
@Override
public String doEqualSharding(
final Collection<String> availableTargetNames,
final ShardingValue<Integer> shardingValue) {
for (String each : availableTargetNames) {
if (each.endsWith(shardingValue.getValue() % tableCount + "")) {
return each;
}
}
throw new UnsupportedOperationException();
}
@Override
public Collection<String> doInSharding(
final Collection<String> availableTargetNames,
final ShardingValue<Integer> shardingValue) {
Collection<String> result = new LinkedHashSet<>(
availableTargetNames.size());
Collection<Integer&