Sharding-JDBC自動(dòng)實(shí)現(xiàn)MySQL讀寫分離的示例代碼
前言:上一篇博客我用AOP+AbstractRoutingDataSource實(shí)現(xiàn)了MySQL讀寫分離,自己寫代碼實(shí)現(xiàn)判斷該使用哪個(gè)數(shù)據(jù)源挺麻煩的。Sharding-JDBC 是 Apache 旗下的 ShardingSphere 中的一款輕量級(jí)產(chǎn)品,引入 jar 即可完成讀寫分離的需求,可以理解為增強(qiáng)版的 JDBC,現(xiàn)在被使用的較多。使用Sharding-JDBC配置MySQL讀寫分離,優(yōu)點(diǎn)在于數(shù)據(jù)源完全有Sharding-JDBC托管,寫操作自動(dòng)執(zhí)行master庫(kù),讀操作自動(dòng)執(zhí)行slave庫(kù)。不需要程序員在程序中關(guān)注這個(gè)實(shí)現(xiàn),比你自己去配多數(shù)據(jù)源簡(jiǎn)單多了。
一、ShardingSphere和Sharding-JDBC概述
1.1、ShardingSphere簡(jiǎn)介
在介紹Sharding-JDBC之前,有必要先介紹下Sharding-JDBC的大家族ShardingSphere。在介紹ShardingSphere之后,相信大家會(huì)對(duì)ShardingSphere的整體架構(gòu)以及Sharding-JDBC扮演的角色會(huì)有更深的了解。
ShardingSphere是后來(lái)規(guī)劃的,最開始是只有 Sharding-JDBC 一款產(chǎn)品,基于客戶端形式的分庫(kù)分表。后面發(fā)展變成了現(xiàn)在的Apache ShardingSphere(Incubator) ,它是一套開源的分布式數(shù)據(jù)庫(kù)中間件解決方案組成的生態(tài)圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(規(guī)劃中)這3款相互獨(dú)立,卻又能夠混合部署配合使用的產(chǎn)品組成。它們均提供標(biāo)準(zhǔn)化的數(shù)據(jù)分片、分布式事務(wù)和數(shù)據(jù)庫(kù)治理功能,可適用于如Java同構(gòu)、異構(gòu)語(yǔ)言、容器、云原生等各種多樣化的應(yīng)用場(chǎng)景。
ShardingSphere定位為關(guān)系型數(shù)據(jù)庫(kù)中間件,旨在充分合理地在分布式的場(chǎng)景下利用關(guān)系型數(shù)據(jù)庫(kù)的計(jì)算和存儲(chǔ)能力,而并非實(shí)現(xiàn)一個(gè)全新的關(guān)系型數(shù)據(jù)庫(kù)。 它與NoSQL和NewSQL是并存而非互斥的關(guān)系。NoSQL和NewSQL作為新技術(shù)探索的前沿,放眼未來(lái),擁抱變化,是非常值得推薦的。反之,也可以用另一種思路看待問(wèn)題,放眼未來(lái),關(guān)注不變的東西,進(jìn)而抓住事物本質(zhì)。 關(guān)系型數(shù)據(jù)庫(kù)當(dāng)今依然占有巨大市場(chǎng),是各個(gè)公司核心業(yè)務(wù)的基石,未來(lái)也難于撼動(dòng),我們目前階段更加關(guān)注在原有基礎(chǔ)上的增量,而非顛覆。

1.2、Sharding-JDBC簡(jiǎn)介
定位為輕量級(jí)Java框架,在Java的JDBC層提供的額外服務(wù)。 它使用客戶端直連數(shù)據(jù)庫(kù),以jar包形式提供服務(wù),無(wú)需額外部署和依賴,可理解為增強(qiáng)版的JDBC驅(qū)動(dòng),完全兼容JDBC和各種ORM框架。
- 適用于任何基于Java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
- 基于任何第三方的數(shù)據(jù)庫(kù)連接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
- 支持任意實(shí)現(xiàn)JDBC規(guī)范的數(shù)據(jù)庫(kù)。目前支持MySQL,Oracle,SQLServer和PostgreSQL。

1.3、Sharding-JDBC作用

1.4、ShardingSphere規(guī)劃線路圖

1.5、ShardingSphere三種產(chǎn)品的區(qū)別

二、數(shù)據(jù)庫(kù)中間件
透明化讀寫分離所帶來(lái)的影響,讓使用方盡量像使用一個(gè)數(shù)據(jù)庫(kù)一樣使用主從數(shù)據(jù)庫(kù),是讀寫分離數(shù)據(jù)庫(kù)中間件的主要功能。
2.1、數(shù)據(jù)庫(kù)中間件簡(jiǎn)介
數(shù)據(jù)庫(kù)中間件可以簡(jiǎn)化對(duì)讀寫分離以及分庫(kù)分表的操作,并隱藏底層實(shí)現(xiàn)細(xì)節(jié),可以像操作單庫(kù)單表那樣操作多庫(kù)多表,主流的設(shè)計(jì)方案主要有兩種:
- 服務(wù)端代理:需要獨(dú)立部署一個(gè)代理服務(wù),該代理服務(wù)后面管理多個(gè)數(shù)據(jù)庫(kù)實(shí)例,在應(yīng)用中通過(guò)一個(gè)數(shù)據(jù)源與該代理服務(wù)器建立連接,由該代理去操作底層數(shù)據(jù)庫(kù),并返回相應(yīng)結(jié)果。優(yōu)點(diǎn)是支持多語(yǔ)言,對(duì)業(yè)務(wù)透明,缺點(diǎn)是實(shí)現(xiàn)復(fù)雜,實(shí)現(xiàn)難度大,同時(shí)代理需要確保自身高可用
- 客戶端代理:在連接池或數(shù)據(jù)庫(kù)驅(qū)動(dòng)上進(jìn)行一層封裝,內(nèi)部與不同的數(shù)據(jù)庫(kù)建立連接,并對(duì)
SQL進(jìn)行必要的操作,比如讀寫分離選擇走主庫(kù)還是從庫(kù),分庫(kù)分表select后如何聚合結(jié)果。優(yōu)點(diǎn)是實(shí)現(xiàn)簡(jiǎn)單,天然去中心化,缺點(diǎn)是支持語(yǔ)言較少,版本升級(jí)困難
一些常見的數(shù)據(jù)庫(kù)中間件如下:
Cobar:阿里開源的關(guān)系型數(shù)據(jù)庫(kù)分布式服務(wù)中間件,已停更DRDS:脫胎于Cobar,全稱分布式關(guān)系型數(shù)據(jù)庫(kù)服務(wù)MyCat:開源數(shù)據(jù)庫(kù)中間件,目前更新了MyCat2版本Atlas:Qihoo 360公司Web平臺(tái)部基礎(chǔ)架構(gòu)團(tuán)隊(duì)開發(fā)維護(hù)的一個(gè)基于MySQL協(xié)議的數(shù)據(jù)中間層項(xiàng)目,同時(shí)還有一個(gè)NoSQL的版本,叫Pikatddl:阿里巴巴自主研發(fā)的分布式數(shù)據(jù)庫(kù)服務(wù)Sharding-JDBC:ShardingShpere的一個(gè)子產(chǎn)品,一個(gè)輕量級(jí)Java框架
2.2、Sharding-JDBC和MyCat區(qū)別
1)mycat是一個(gè)中間件的第三方應(yīng)用,sharding-jdbc是一個(gè)jar包
2)使用mycat時(shí)不需要改代碼,而使用sharding-jdbc時(shí)需要修改代碼
Mycat(proxy中間件層):

Sharding-jdbc(TDDL為代表的應(yīng)用層):

可以看出sharding-jdbc作為一個(gè)組件集成在應(yīng)用內(nèi),而mycat則作為一個(gè)獨(dú)立的應(yīng)用需要單獨(dú)部署。從架構(gòu)上看sharding-jdbc更符合分布式架構(gòu)的設(shè)計(jì),直連數(shù)據(jù)庫(kù),沒有中間應(yīng)用,理論性能是最高的(實(shí)際性能需要結(jié)合具體的代碼實(shí)現(xiàn),理論性能可以理解為上限,通過(guò)不斷優(yōu)化代碼實(shí)現(xiàn),逐漸接近理論性能)。同時(shí)缺點(diǎn)也很明顯,由于作為組件存在,需要集成在應(yīng)用內(nèi),意味著作為使用方,必須要集成到代碼里,使得開發(fā)成本相對(duì)較高;另一方面,由于需要集成在應(yīng)用內(nèi),使得需要針對(duì)不同語(yǔ)言(java、C、PHP……)有不同的實(shí)現(xiàn)(事實(shí)上sharding-jdbc目前只支持Java),這樣組件本身的維護(hù)成本也會(huì)很高。最終將應(yīng)用場(chǎng)景限定在由Java開發(fā)的應(yīng)用這一種場(chǎng)景下。
Sharding-JDBC較于MyCat,我認(rèn)為最大的優(yōu)勢(shì)是:sharding-jdbc是輕量級(jí)的第三方工具,直連數(shù)據(jù)庫(kù),沒有中間應(yīng)用,我們只需要在項(xiàng)目中引用指定的jar包即可,然后根據(jù)項(xiàng)目的業(yè)務(wù)需要配置分庫(kù)分表或者讀寫分離的規(guī)則和方式。
三、Sharding-JDBC+MyBatisPlus實(shí)現(xiàn)讀寫分離
3.0、項(xiàng)目代碼結(jié)構(gòu)和建表SQL語(yǔ)句
(1) 項(xiàng)目代碼結(jié)構(gòu)

(2) 建表SQL語(yǔ)句
DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `user_id` int(11) NOT NULL AUTO_INCREMENT, `account` varchar(45) NOT NULL, `nickname` varchar(18) NOT NULL, `password` varchar(45) NOT NULL, `headimage_url` varchar(45) DEFAULT NULL, `introduce` varchar(45) DEFAULT NULL, PRIMARY KEY (`user_id`), UNIQUE KEY `account_UNIQUE` (`account`), UNIQUE KEY `nickname_UNIQUE` (`nickname`) ) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8;
3.1、引入Maven依賴
<!--Sharding-JDBC實(shí)現(xiàn)讀寫分離-->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>4.1.1</version>
</dependency>
<!-- mybatis-plus 依賴 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!-- mysql 依賴 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--支持Web開發(fā),包括Tomcat和spring-webmvc-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--LomBok使用@Data注解-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
3.2、yml文件配置
Spring Boot 2.x中,對(duì)數(shù)據(jù)源的選擇也緊跟潮流,默認(rèn)采用了目前性能最佳的HikariCP
spring:
shardingsphere:
datasource:
names: master,slave # 數(shù)據(jù)源名字
master:
type: com.zaxxer.hikari.HikariDataSource # 連接池
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://xxxxxx:3306/test?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=utf-8 #主庫(kù)地址
username: root
password: xxxxxx
hikari:
maximum-pool-size: 20 #最大連接數(shù)量
minimum-idle: 10 #最小空閑連接數(shù)
max-lifetime: 0 #最大生命周期,0不過(guò)期。不等于0且小于30秒,會(huì)被重置為默認(rèn)值30分鐘.設(shè)置應(yīng)該比mysql設(shè)置的超時(shí)時(shí)間短
idle-timeout: 30000 #空閑連接超時(shí)時(shí)長(zhǎng),默認(rèn)值600000(10分鐘)
connection-timeout: 60000 #連接超時(shí)時(shí)長(zhǎng)
data-source-properties:
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
cachePrepStmts: true
useServerPrepStmts: true
slave:
type: com.zaxxer.hikari.HikariDataSource # 連接池
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://xxxxxx:3306/test?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=utf-8 #從庫(kù)地址
username: root
password: xxxxxx
hikari:
maximum-pool-size: 20
minimum-idle: 10
max-lifetime: 0
idle-timeout: 30000
connection-timeout: 60000
data-source-properties:
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
cachePrepStmts: true
useServerPrepStmts: true
masterslave:
load-balance-algorithm-type: round_robin # 負(fù)載均衡算法,用于配置從庫(kù)負(fù)載均衡算法類型,可選值:ROUND_ROBIN(輪詢),RANDOM(隨機(jī))
name: ms # 最終的數(shù)據(jù)源名稱
master-data-source-name: master # 主庫(kù)數(shù)據(jù)源名稱
slave-data-source-names: slave # 從庫(kù)數(shù)據(jù)源名稱列表,多個(gè)逗號(hào)分隔
props:
sql:
show: true # 在執(zhí)行SQL時(shí),會(huì)打印SQL,并顯示執(zhí)行庫(kù)的名稱,默認(rèn)false
3.3、UserEntity實(shí)體類
package com.hs.sharingjdbc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
//定義表名:當(dāng)數(shù)據(jù)庫(kù)名與實(shí)體類名不一致或不符合駝峰命名時(shí),需要在此注解指定表名
@TableName(value = "user")
public class UserEntity {
//指定主鍵自增策略:value與數(shù)據(jù)庫(kù)主鍵列名一致,若實(shí)體類屬性名與表主鍵列名一致可省略value
@TableId(type = IdType.AUTO)
private Integer user_id;
private String account;
private String nickname;
private String password;
private String headimage_url;
private String introduce;
}
3.4、UserMapper接口
編寫的接口需要繼承 BaseMapper接口,該接口源碼定義了一些通用的操作數(shù)據(jù)庫(kù)方法, 單表大部分 CRUD 操作都能直接搞定,相比原生的MyBatis,效率提高了很多
package com.hs.sharingjdbc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hs.sharingjdbc.entity.UserEntity;
public interface UserMapper extends BaseMapper<UserEntity> {
// int insert(T entity);
//
// int deleteById(Serializable id);
//
// int deleteByMap(@Param("cm") Map<String, Object> columnMap);
//
// int delete(@Param("ew") Wrapper<T> queryWrapper);
//
// int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
//
// int updateById(@Param("et") T entity);
//
// int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
//
// T selectById(Serializable id);
//
// List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
//
// List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
//
// T selectOne(@Param("ew") Wrapper<T> queryWrapper);
//
// Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
//
// List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
//
// List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
//
// List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
//
// <E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
//
// <E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}
主類添加@MapperScan("com.hs.sharingjdbc.mapper"),掃描所有Mapper接口
package com.hs.sharingjdbc;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication()
@MapperScan("com.hs.sharingjdbc.mapper")
public class SharingJdbcApplication {
public static void main(String[] args) {
SpringApplication.run(SharingJdbcApplication.class, args);
}
}
3.5、UserService類
package com.hs.sharingjdbc.service;
import com.hs.sharingjdbc.entity.UserEntity;
import com.hs.sharingjdbc.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
@Autowired
UserMapper userMapper;
public List<UserEntity> findAll()
{
//selectList() 方法的參數(shù)為 mybatis-plus 內(nèi)置的條件封裝器 Wrapper,這里不填寫表示無(wú)任何條件,全量查詢
List<UserEntity> userEntities = userMapper.selectList(null);
return userEntities;
}
public int insertUser(UserEntity user)
{
int i = userMapper.insert(user);
return i;
}
}
3.6、UserController類
package com.hs.sharingjdbc.controller;
import com.hs.sharingjdbc.entity.UserEntity;
import com.hs.sharingjdbc.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class UserController
{
@Autowired
UserService userService;
@RequestMapping("/listUser")
public List<UserEntity> listUser()
{
List<UserEntity> users = userService.findAll();
return users;
}
@RequestMapping("/insertUser")
public void insertUser()
{
UserEntity userEntity = new UserEntity();
userEntity.setAccount("22222");
userEntity.setNickname("hshshs");
userEntity.setPassword("123");
userService.insertUser(userEntity);
}
}
3.7、項(xiàng)目啟動(dòng)測(cè)試
http://localhost:8080/listUser ,執(zhí)行查詢語(yǔ)句,可以看到讀操作在Slave從庫(kù)進(jìn)行:

http://localhost:8090/insertUser,執(zhí)行插入語(yǔ)句,可以看到寫操作在Master主庫(kù)進(jìn)行:

這樣讀寫分離就算是可以了。
四、HikariCP連接池使用遇到的兩個(gè)Bug
4.1、SpringBoot2關(guān)于HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImp
上面在使用springboot2.x 時(shí)遇到了一個(gè)很奇怪的問(wèn)題,在程序運(yùn)行起來(lái)之后,長(zhǎng)時(shí)間的不進(jìn)行數(shù)據(jù)庫(kù)操作就會(huì)出現(xiàn)這樣的錯(cuò)誤,后面跟著這樣的敘述, Connection is not available, request timed out after XXXms. Possibly consider using a shorter maxLifetime value.
為什么會(huì)存在不可用的連接呢?maxLifetime可以控制連接的生命周期,我們來(lái)以前看看maxLifetime參數(shù)。

我引一下chrome上面的中文翻譯:
此屬性控制數(shù)據(jù)庫(kù)連接池中連接的最大生存期。使用中的連接永遠(yuǎn)不會(huì)停止,只有關(guān)閉連接后,連接才會(huì)被移除。在逐個(gè)連接的基礎(chǔ)上,應(yīng)用較小的負(fù)衰減以避免池中的質(zhì)量消滅。 我們強(qiáng)烈建議設(shè)置此值,它應(yīng)該比任何數(shù)據(jù)庫(kù)或基礎(chǔ)結(jié)構(gòu)施加的連接時(shí)間限制短幾秒鐘。 值0表示沒有最大壽命(無(wú)限壽命),當(dāng)然要遵守該idleTimeout設(shè)置。 默認(rèn)值:1800000(30分鐘)
分析是HikariCP連接池對(duì)連接管理的問(wèn)題,因此想方設(shè)法進(jìn)行SpringBoot2.0 HikariCP連接池配置
hikari:
maximum-pool-size: 20 #最大連接數(shù)量
minimum-idle: 10 #最小空閑連接數(shù)
max-lifetime: 0 #最大生命周期,0不過(guò)期。不等于0且小于30秒,會(huì)被重置為默認(rèn)值30分鐘.設(shè)置應(yīng)該比mysql設(shè)置的超時(shí)時(shí)間短
idle-timeout: 30000 #空閑連接超時(shí)時(shí)長(zhǎng),默認(rèn)值600000(10分鐘)
connection-timeout: 60000 #連接超時(shí)時(shí)長(zhǎng)
data-source-properties:
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
cachePrepStmts: true
useServerPrepStmts: true
spring.datasource.hikari.minimum-idle: 最小空閑連接,默認(rèn)值10,小于0或大于maximum-pool-size,都會(huì)重置為maximum-pool-sizespring.datasource.hikari.maximum-pool-size: 最大連接數(shù),小于等于0會(huì)被重置為默認(rèn)值10;大于零小于1會(huì)被重置為minimum-idle的值spring.datasource.hikari.idle-timeout: 空閑連接超時(shí)時(shí)間,默認(rèn)值600000(10分鐘),大于等于max-lifetime且max-lifetime>0,會(huì)被重置為0;不等于0且小于10秒,會(huì)被重置為10秒。spring.datasource.hikari.max-lifetime: 連接最大存活時(shí)間,不等于0且小于30秒,會(huì)被重置為默認(rèn)值30分鐘.設(shè)置應(yīng)該比mysql設(shè)置的超時(shí)時(shí)間短spring.datasource.hikari.connection-timeout: 連接超時(shí)時(shí)間:毫秒,小于250毫秒,否則被重置為默認(rèn)值30秒
4.2、com.zaxxer.hikari.pool.HikariPool : datasource -Thread starvation or clock leap detected (housekeeper delta=4m32s295ms949µs223ns).
分析:WARN警告級(jí)別,看起來(lái)不是什么錯(cuò)誤,但是連接數(shù)據(jù)庫(kù)就是連不上
英譯漢:數(shù)據(jù)源-檢測(cè)到線程饑餓或時(shí)鐘跳動(dòng)
人話:要么是檢測(cè)到等待連接的時(shí)間過(guò)長(zhǎng),造成進(jìn)饑餓;要么是檢測(cè)到時(shí)鐘跳動(dòng),反正最后是關(guān)閉了數(shù)據(jù)庫(kù)連接。
其實(shí),這里根本就沒有報(bào)錯(cuò),只是一個(gè)警告。是上游代碼出了問(wèn)題,長(zhǎng)時(shí)間不調(diào)用Service層進(jìn)行存儲(chǔ),然后Hikari數(shù)據(jù)源就關(guān)掉了自己;當(dāng)有新的調(diào)用時(shí),會(huì)啟用新的數(shù)據(jù)源。
修改默認(rèn)的連接池配置如下:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${ip}:3306/${數(shù)據(jù)庫(kù)}?useSSL=false&characterEncoding=UTF-8
username: ${username}
password: ${password}
hikari:
auto-commit: true
#空閑連接超時(shí)時(shí)長(zhǎng)
idle-timeout: 60000
#連接超時(shí)時(shí)長(zhǎng)
connection-timeout: 60000
#最大生命周期,0不過(guò)期
max-lifetime: 0
#最小空閑連接數(shù)
minimum-idle: 10
#最大連接數(shù)量
maximum-pool-size: 20
五、讀寫分離架構(gòu),經(jīng)常出現(xiàn)的讀延遲的問(wèn)題如何解決?
剛插入一條數(shù)據(jù),然后馬上就要去讀取,這個(gè)時(shí)候有可能會(huì)讀取不到?歸根到底是因?yàn)橹鞴?jié)點(diǎn)寫入完之后數(shù)據(jù)是要復(fù)制給從節(jié)點(diǎn)的,讀不到的原因是復(fù)制的時(shí)間比較長(zhǎng),也就是說(shuō)數(shù)據(jù)還沒復(fù)制到從節(jié)點(diǎn),你就已經(jīng)去從節(jié)點(diǎn)讀取了,肯定讀不到。mysql5.7 的主從復(fù)制是多線程了,意味著速度會(huì)變快,但是不一定能保證百分百馬上讀取到,這個(gè)問(wèn)題我們可以有兩種方式解決:
(1)業(yè)務(wù)層面妥協(xié),是否操作完之后馬上要進(jìn)行讀取
(2)對(duì)于操作完馬上要讀出來(lái)的,且業(yè)務(wù)上不能妥協(xié)的,我們可以對(duì)于這類的讀取直接走主庫(kù)
當(dāng)然Sharding-JDBC也是考慮到這個(gè)問(wèn)題的存在,所以給我們提供了一個(gè)功能,可以讓用戶在使 用的時(shí)候指定要不要走主庫(kù)進(jìn)行讀取。在讀取前使用下面的方式進(jìn)行設(shè)置就可以了:
public List<UserInfo> findAllUser()
{
// 強(qiáng)制路由主庫(kù)
HintManager.getInstance().setMasterRouteOnly();
return this.list();
}
參考鏈接:
Spring Boot demo系列(十二):ShardingSphere + MyBatisPlus讀寫分離 + 主從復(fù)制
mycat和sharding-jdbc哪個(gè)比較好?各有什么優(yōu)缺點(diǎn)?
Spring Boot 2.x基礎(chǔ)教程:默認(rèn)數(shù)據(jù)源Hikari的配置詳解
解決springboot2.x遇到的一段時(shí)間內(nèi)不使用,redis連接和HikariPool連接池超時(shí)的問(wèn)題
Thread starvation or clock leap detected (housekeeper delta=4m32s295ms949µs223ns).
到此這篇關(guān)于Sharding-JDBC自動(dòng)實(shí)現(xiàn)MySQL讀寫分離的文章就介紹到這了,更多相關(guān)Sharding-JDBC MySQL讀寫分離內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot開發(fā)編譯后讀取不到@spring.profiles.active@的問(wèn)題及解決步驟
這篇文章主要介紹了Spring Boot開發(fā)編譯后讀取不到@spring.profiles.active@的問(wèn)題及解決步驟,需要的朋友可以參考下2024-12-12
Springboot中的異步任務(wù)執(zhí)行及監(jiān)控詳解
這篇文章主要介紹了Springboot中的異步任務(wù)執(zhí)行及監(jiān)控詳解,除了自己實(shí)現(xiàn)線程外,springboot本身就提供了通過(guò)注解的方式,進(jìn)行異步任務(wù)的執(zhí)行,下面主要記錄一下,在Springboot項(xiàng)目中實(shí)現(xiàn)異步任務(wù),以及對(duì)異步任務(wù)進(jìn)行封裝監(jiān)控,需要的朋友可以參考下2023-10-10
feignclient?https?接口調(diào)用報(bào)證書錯(cuò)誤的解決方案
這篇文章主要介紹了feignclient?https?接口調(diào)用報(bào)證書錯(cuò)誤的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
帶有@Transactional和@Async的循環(huán)依賴問(wèn)題的解決
這篇文章主要介紹了帶有@Transactional和@Async的循環(huán)依賴問(wèn)題的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
Java synchronized關(guān)鍵字和Lock接口實(shí)現(xiàn)原理
這篇文章主要介紹了Java synchronized關(guān)鍵字和Lock接口實(shí)現(xiàn)原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
java搭建ftp/sftp進(jìn)行數(shù)據(jù)傳遞的全過(guò)程
ftp是一種文件傳輸協(xié)議,讓客戶端和服務(wù)端能夠互相傳遞文件,圖片等數(shù)據(jù),sftp也是一種文件傳輸協(xié)議,但是相比較而言要比f(wàn)tp安全性更好些,但是也有缺點(diǎn)就是傳輸效率低2021-07-07

