做者:高玉瓏算法
來源:宜信技術學院spring
技術沙龍001期|AI中臺:一種敏捷的智能業務支持方案|宜信技術沙龍 3月28日晚8點線上直播,點擊報名sql
一、什麼是Sharding-JDBC數據庫
Sharding-JDBC定位爲輕量級Java框架,在Java的JDBC層提供的額外服務。它使用客戶端直連數據庫,以jar包形式提供服務,無需額外部署和依賴,可理解爲加強版的JDBC驅動,徹底兼容JDBC和各類ORM框架。apache
二、Sharding-JDBC能作什麼網絡
分庫 & 分表負載均衡
讀寫分離框架
分佈式主鍵分佈式
分佈式事務ide
三、適用項目框架
Sharding-JDBC適用於:
任何基於Java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
基於任何第三方的數據庫鏈接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
支持任意實現JDBC規範的數據庫,目前支持MySQL,Oracle,SQLServer和PostgreSQL。
四、Maven依賴
<!-- sharding jdbc 開始--> <dependency> <groupId>io.shardingsphere</groupId> <artifactId>sharding-core</artifactId> <version>${sharding.version}</version> </dependency> <dependency> <groupId>io.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-namespace</artifactId> <version>${sharding.version}</version> </dependency> <!—若是不配置分佈式事務的話配置上邊兩個就夠了 --> <!--分佈式事務引用依賴--> <dependency> <groupId>io.shardingsphere</groupId> <artifactId>sharding-transaction-2pc-xa</artifactId> <version>${sharding.version}</version> </dependency> <dependency> <groupId>io.shardingsphere</groupId> <artifactId>sharding-transaction-spring</artifactId> <version>${sharding.version}</version> </dependency> <!-- sharding jdbc 結束--> <!--AspectJ AOP支持 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectjweaver.version}</version> </dependency>
五、讀寫分離
5.1 數據源配置
先配置數據源
也能夠配置讀寫分離
如下配置是ds0和ds1兩個數據庫的主和從一共四個數據源。
parentDs 是數據源公共的配置,抽出去以避免寫重複代碼。
<!-- ds0的主--> <bean id="ds0_master" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" parent="parentDs"> <property name="driverClassName" value=""/> <property name="url" value=""/> </bean> <!-- ds0的從--> <bean id="ds0_slave" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" parent="parentDs"> <property name="driverClassName" value=""/> <property name="url" value="${sharding.connection.url.0}"/> </bean> <!-- ds1的主--> <bean id="ds1_master" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" parent="parentDs"> <property name="driverClassName" value=""/> <property name="url" value="${sharding.connection.url.1}"/> </bean> <!-- ds1的從--> <bean id="ds1_slave" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" parent="parentDs"> <property name="driverClassName" value=""/> <property name="url" value="${sharding.connection.url.1}"/> </bean>
5.2 讀寫分離配置
只配置主從不配置分庫分表的狀況以下,若是要配置分庫分表則不須要下面這個配置。
master-data-source-name 是主數據源ID
slave-data-source-names 是從數據源ID
<master-slave:data-source id="masterSlaveDataSource" master-data-source-name="ds0_master, ds1_master" slave-data-source-names="ds0_slave, ds1_slave " > <master-slave:props> <prop key="sql.show">${sql_show}</prop> <prop key="executor.size">10</prop> <prop key="foo">bar</prop> </master-slave:props> </master-slave:data-source>
5.3 讀寫分離和分庫分表一塊兒配置
若是讀寫分離和分庫分表一塊兒使用的話把主從路由配置到 shardingdata-source下就能夠了。
sharding:master-slave-rule 的 id 就是配置出來的邏輯的數據源的名稱,若是多個從的話還能夠經過配置strategy-ref來配置負載均衡。
master-data-source 配置的是主庫數據源ID 。
slave-data-source 配置的是從庫數據源ID,多個以逗號分開。
<!-- sharding數據源--> <sharding:data-source id="shardingDataSource"> <!-- 讀寫分離的話要把全部的主從數據源都寫在這裏--> <sharding:sharding-rule data-source-names="ds0_master,ds0_slave,ds1_master,ds1_slave "> <!-- 讀寫分離的路由 一主一從配置 strategy-ref --> <sharding:master-slave-rules> <sharding:master-slave-rule id="ds0" master-data-source-name="ds0_master" slave-data-source-names="ds0_slave"/> <sharding:master-slave-rule id="ds1" master-data-source-name="ds1_master" slave-data-source-names="ds1_slave"/> </sharding:master-slave-rules> <!-- 讀寫分離配置 結束--> <sharding:table-rules> <!— 這裏是分庫分表路由的配置 --> </sharding:table-rules> <sharding:binding-table-rules> <!—- 綁定表的配置 --> </sharding:binding-table-rules> </sharding:sharding-rule> <sharding:props> <!-- 顯示SQL --> <prop key="sql.show">true</prop> </sharding:props> </sharding:data-source>
六、數據分片
6.1 分片支持
Sharding-JDBC提供了5種分片策略。因爲分片算法和業務實現緊密相關,所以Sharding-JDBC並未提供內置分片算法,而是經過分片策略將各類場景提煉出來,提供更高層級的抽象,並提供接口讓應用開發者自行實現分片算法。
StandardShardingStrategy
標準分片策略。提供對SQL語句中的=, IN和BETWEEN AND的分片操做支持。StandardShardingStrategy只支持單分片鍵,提供PreciseShardingAlgorithm和RangeShardingAlgorithm兩個分片算法。PreciseShardingAlgorithm是必選的,用於處理=和IN的分片;RangeShardingAlgorithm是可選的,用於處理BETWEEN AND分片,若是不配置RangeShardingAlgorithm,SQL中的BETWEEN AND將按照全庫路由處理。
ComplexShardingStrategy
複合分片策略。提供對SQL語句中的=, IN和BETWEEN AND的分片操做支持。ComplexShardingStrategy支持多分片鍵,因爲多分片鍵之間的關係複雜,所以Sharding-JDBC並未作過多的封裝,而是直接將分片鍵值組合以及分片操做符交於算法接口,徹底由應用開發者實現,提供最大的靈活度。
InlineShardingStrategy
Inline表達式分片策略。使用Groovy的Inline表達式,提供對SQL語句中的=和IN的分片操做支持。InlineShardingStrategy只支持單分片鍵,對於簡單的分片算法,能夠經過簡單的配置使用,從而避免繁瑣的Java代碼開發,如: tuser${user_id % 8} 表示t_user表按照user_id按8取模分紅8個表,表名稱爲t_user_0到t_user_7。
HintShardingStrategy
經過Hint而非SQL解析的方式分片的策略。
NoneShardingStrategy
不分片的策略。
6.2 分片配置
標準分片配置
<!-- 標準分片策略。--> <bean id="demoUserStandardStrategy" class="shard.strategy.DemoUserStandardStrategy"/> <sharding:standard-strategy id="shardingDemoUserStandardStrategy" precise-algorithm-ref="demoUserStandardStrategy" sharding-column="id" range-algorithm-ref=""/>
DemoUserStandardStrategy標準分片要實現 PreciseShardingAlgorithm 接口,doSharding的兩個參數一個是全部數據源的cllection.另外一個參數是執行SQL時傳過來的分片的值。
/** * 根據ID取 * 標準分片策略 * 用於處理=和IN的分片 * @author yulonggao * @date 2019/1/31 14:35 */ @Slf4j public class DemoUserStandardStrategy implements PreciseShardingAlgorithm<Long> { @Override public String doSharding(Collection<String> collection, PreciseShardingValue<Long> preciseShardingValue) { //這個裏邊有異常會被處理掉,而後致使拿不到分片。但出異常通常是業務代碼寫錯了。 //每條指定分片的操做都會調用此方法,若是是in 條件查詢的話每一個值會調用一次此方法,若是是批量插入也是每一條都要調用一次進行分片 log.info("DemoUserStandardStrategy_preciseShardingValue={}", preciseShardingValue); Long suffix = preciseShardingValue.getValue() % 4; log.info("suffix={}", suffix); final String targetDb = String.valueOf(Math.abs(suffix.intValue())); String shardingValue = collection.stream().filter(p -> p.endsWith(targetDb)).findFirst().get(); log.info("preciseShardingValue={},shardingValue={}", preciseShardingValue, shardingValue); return shardingValue; } }
強制分片
<!-- 強制路由分片策略--> <bean id="demoUserHintStrategy" class="shard.strategy.DemoUserHintStrategy"/> <!-- 強制路由例子使用--> <sharding:hint-strategy id="shardingDemoUserHintStrategy" algorithm-ref="demoUserHintStrategy"/> DemoUserHintStrategy 的Java 以下,強制分片要實現HintShardingAlgorithm接口。 /** * DemoUserHint強制路由分片策略,其實能夠共用,只是例子 * @author yulonggao * @date 2019/1/31 14:35 */ @Slf4j public class DemoUserHintStrategy implements HintShardingAlgorithm { @Override public Collection<String> doSharding(Collection<String> availableTargetNames, ShardingValue shardingValue) { //availableTargetNames 這個參數是全部的dataSource的集合,shardingValue是HintManager傳過來的分片信息 log.info("DemoUserHintStrategy_availableTargetNames={}", availableTargetNames); log.info("DemoUserHintStrategy_shardingValue={}", shardingValue); ListShardingValue listShardingValue = (ListShardingValue) shardingValue; Collection shardingValueList = listShardingValue.getValues(); //由於調用的時候分片是直接傳的 DataSource的名稱,因此直接返回就能夠了,若是傳其它值則要加業務邏輯進行分片篩選 //返回結果只能是availableTargetNames 裏邊所包含的 return shardingValueList; } }
生成分部式ID的配置,生成主鍵的類要實現KeyGenerator接口。
<!—主鍵生成 --> <bean id="keyId" class="shard.key.DefaultKeyGenerator"/>
七、分佈式事務
把下面這行代碼配置在spring裏,shardingTransaction.xml 是jar包裏邊帶的。
文件的源碼只有兩行配置:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="shardingDataSource"></property> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> <!-- 事務支持--> <import resource="classpath:META-INF/shardingTransaction.xml"/>
使用註解配置事務要同時使用ShardingTransactionType和Transactional兩個註解。
/** * 注意:@ShardingTransactionType須要同Spring的@Transactional配套使用,事務纔會生效。 * @param param * @return */ @ShardingTransactionType(TransactionType.XA) @Transactional(rollbackFor = Exception.class) @Override public int addParam(DemoParam param) { log.info("addParam-param={}", param); return demoParamDao.addParam(param); }
7.1 支持程度
徹底支持非跨庫事務,例如:僅分表或分庫可是路由的結果在單庫中。
徹底支持因邏輯異常致使的跨庫事務。例如:同一事務中跨兩個庫更新,更新完畢後,拋出空指針,則兩個庫的內容都能回滾。
支持數據庫字段約束形成的回滾。
不支持因網絡、硬件異常致使的跨庫事務。例如:同一事務中跨兩個庫更新,更新完畢後、未提交以前,第一個庫死機,則只有第二個庫數據提交。
八、其餘問題
關於order by 排序,若是排序的字段不在查詢結果中,生成的SQL也會被帶上,但結果不返回給你。
九、參考文檔
https://shardingsphere.apache.org/document/current/cn/manual/sharding-jdbc/usage/sharding/