1. 程式人生 > >藉助sharding-jdbc實現資料分片

藉助sharding-jdbc實現資料分片

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&