1. 程式人生 > 程式設計 >基於ShardingJDBC進行資料庫讀寫分離

基於ShardingJDBC進行資料庫讀寫分離

1、引入依賴

專案pom.xml檔案中,引入sharding-jdbc的依賴:

<dependency>
  	<groupId>org.apache.shardingsphere</groupId>
  	<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
  	<version>4.0.0-RC1</version>
</dependency>
複製程式碼

2、增加讀寫分離的配置

專案bootstrap.yml增加讀寫分離的配置,以下是dev環境的配置:

spring:
  shardingsphere:
    datasource:
      names: master, slave
      master:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/testdb
        username: ''
        password: ''
      slave:
        type:
com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/testdb1 username: '' password: '' masterslave: name: ms master-data-source-name: master slave-data-source-names: slave 複製程式碼

3、演示效果

3.1、新建測試表

dev環境實際關閉了主從同步,通過手動修改從庫的資料來演示效果

CREATE TABLE `t1` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,`name` varchar(50) NOT NULL DEFAULT 'testname',`age` int(10) unsigned NOT NULL DEFAULT '30',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 主庫插入的資料
INSERT INTO `testdb`.`t1`(`id`,`name`,`age`) VALUES (1,'wangao',10);

-- 從庫插入的資料
INSERT INTO `testdb1`.`t1`(`id`,20);
複製程式碼

3.2、編寫資料庫訪問介面

@Entity
@Table(name = "t1")
@Data
public class User {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    @Column(name = "name")
    private String name;
    
    @Column(name = "age")
    private Integer age;
    
}
複製程式碼
public interface UserDao extends JpaRepository<User,Integer> {
    
}
複製程式碼

3.3、儲存資料

@Test
public void base() {
  	User user = new User();
  	user.setName("wangao");
  	user.setAge(10);
  	user = userDao.save(user);
  	System.out.println(user);
}
複製程式碼

save方法可以正常返回帶自增id的物件:

主庫中有新插入的資料:

從庫中沒有資料(主從同步關閉):

3.4、讀取資料

讀取id為1的資料,注意此時是從從庫中獲取,年齡為20

@Test
public void readSlave() {
 		User user = userDao.findById(1).get();
  	System.out.println(user);
}
複製程式碼

3.5、強制從主庫讀取

部分情況需要強制從主庫進行讀取。依舊讀取id為1的資料,注意此時是從主庫中獲取,年齡為10:

@Test
public void readMaster() {
  	HintManager manager = HintManager.getInstance();
  	manager.setMasterRouteOnly();
  	User user = userDao.findById(1).get();
  	System.out.println(user);
  	//一定記得最後close
  	manager.close();
}
複製程式碼

3.6、特別注意

官方檔案關於讀寫分離有這樣一段話:

這裡需要注意的是,預設配置spring.jpa.open-in-view=true,此時一個Restful請求對資料庫的連線是同一個,如果存在寫入操作,則後續讀操作均從主庫讀取

@RestController
public class UserController {
    
    private final UserDao userDao;
    
    public UserController(UserDao userDao) {
        this.userDao = userDao;
    }
    
    @GetMapping("api/user/{id}")
    public User get(@PathVariable int id) {
      	//進行寫入操作
        User user = new User();
        user.setName("奧利奧");
        user.setAge(30);
        user = userDao.save(user);
        System.out.println(user);
        //進行讀取操作
        return userDao.findById(id).orElse(null);
    }
}
複製程式碼

如果將配置改成spring.jpa.open-in-view=false,此時每個操作資料庫的連線都會從連線池中獲取,這樣讀取的操作會從從庫讀取:

4、參考

更多細節可以參考sharding-jdbc的官方網站獲取資訊:

shardingsphere.apache.org/document/cu…