寫在前面
Mycat作為獨立的資料庫中間件,我們隻需要進行相關的配置,就可以非常友善的幫我們實作水準切分、垂直切分、讀寫分離等功能,但PostgreSQL的主從複制需要我們通過其它方式實作。這裡假設我們已經搭建好相關的環境,下面就開始我們的實踐吧!
準備環境
- PostgreSQL(Version : 10.1)主從環境搭建
- 對應資料庫建立(以下例子中使用的都是預設存在的postgres資料庫,可以不用額外添加)
配置server.xml
<user name="postgresmycat">
<property name="password">postgresmycat</property>
<property name="schemas">postgresmycats</property>
</user>
配置schema.xml
<schema name="postgresmycats" checkSQLschema="false" sqlMaxLimit="100">
<table name="tb_user" dataNode="mydn3,mydn4" rule="user-mod-long" />
<table name="tb_student" dataNode="mydn3,mydn4" rule="student-mod-long" />
</schema>
<dataNode name="mydn3" dataHost="myhost3" database="postgres" />
<dataNode name="mydn4" dataHost="myhost4" database="postgres" />
<!-- 這裡的dbDriver使用jdbc的方式來連接配接,用native方式似乎目前還不太相容,試過了好像不可以 -->
<dataHost name="myhost3" maxCon="100" minCon="10" balance="3" writeType="0" dbType="postgresql" dbDriver="jdbc">
<heartbeat>select user</heartbeat><!-- 注意這裡的心跳檢測指令跟mysql的有點不同 -->
<writeHost host="hostM3" url="jdbc:postgresql://localhost:5432/postgres" user="postgres" password="xxx">
<readHost host="hostS3" url="jdbc:postgresql://localhost:5433/postgres" user="postgres" password="xxx"/>
</writeHost>
</dataHost>
<dataHost name="myhost4" maxCon="100" minCon="10" balance="3" writeType="0" dbType="postgresql" dbDriver="jdbc">
<heartbeat>select user</heartbeat>
<writeHost host="hostM4" url="jdbc:postgresql://localhost:5434/postgres" user="postgres" password="xxx" >
<readHost host="hostS4" url="jdbc:postgresql://localhost:5435/postgres" user="postgres" password="xxx"/>
</writeHost>
</dataHost>
dbDriver 屬性
指定連接配接後端資料庫使用的 Driver,目前可選的值有 native 和 jdbc。使用 native 的話,因為這個值執行的
是二進制的 mysql 協定,是以可以使用 mysql 和 maridb。其他類型的資料庫則需要使用 JDBC 驅動來支援
引述《Mycat權威指南》裡面的原話:
從 1.6 版本開始支援 postgresql 的 native 原始協定。
如果使用 JDBC 的話需要将符合 JDBC4 标準的驅動 JAR 包放到 MYCAT\lib 目錄下,并檢查驅動 JAR 包中
包括如下目錄結構的檔案:META-INF\services\java.sql.Driver。在這個檔案内寫上具體的 Driver 類名,例如:
com.mysql.jdbc.Driver。
是以,具體的解決方案就是找一個postgresql的jar包,然後丢到mycat的lib目錄下,不然就會出現啟動失敗或者連接配接不到postgre資料庫的異常情況。本例中用到的jar包是:
postgresql-42.1.4.jar配置rule.xml
<tableRule name="user-mod-long">
<rule>
<columns>id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<tableRule name="student-mod-long">
<rule>
<columns>user_id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<property name="count">2</property>
</function>
修改了配置檔案後,别忘了重新開機Mycat,如果有異常出現,請通過檢視logs目錄下的日志檔案進行排查。
項目搭建(SpringBoot + JPA)
- 準備:首次建表,設定application.yml中的spring.jpa.hibernate.ddl-auto屬性為:create(JPA自動建表解決方案,使用update的話在連接配接mycat的時候會報找不到表的錯誤)。之後似乎必須更改為:none,否則使用其它屬性都會報錯(這裡Mysql與PostgreSQL不同,似乎是一個未解決的bug,這也就意味着以後新增字段都要手動連上資料庫進行添加了...)
- 添加application.yml(注意了,這裡都是用連mysql的方式去配置,Mycat會在後端做好對其它資料庫的連接配接):
spring:
jpa:
show-sql: true
hibernate:
ddl-auto: update
naming:
strategy: org.hibernate.cfg.ImprovedNamingStrategy
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5Dialect
datasource:
url: jdbc:mysql://localhost:8066/postgresmycats?characterEncoding=UTF-8&useSSL=false&autoReconnect=true&rewriteBatchedStatements=true
username: postgresmycat
password: postgresmycat
- 添加User Entity
@Entity
@Table(name = "tb_user")
@Data
public class User {
@Id
private Long id;
private String name;
private Integer gender;
}
- 添加Student Entity
@Entity
@Table(name = "tb_student")
@Data
public class Student {
@Id
private Long id;
private String name;
@Column(unique = true)
private Long userId;
}
- 添加UserDao
public interface UserDao extends JpaRepository<User, Long> {
Page<User> findByNameLike(String name, Pageable pageable);
}
- 添加StudentDao
public interface StudentDao extends JpaRepository<Student, Long> {
Page<User> findByNameLike(String name, Pageable pageable);
}
項目測試
- 測試添加
@Test
public void testAdd() {
for (long i = 0; i < 30; i++) {
User user = new User();
user.setId(i);
user.setName("李四" + i);
user.setGender(i % 2 == 0 ? 1 : 0);
userDao.save(user);
Student student = new Student();
student.setId(System.currentTimeMillis() + i);
student.setName("李四學生" + i);
student.setUserId(i);
studentDao.save(student);
}
}
測試結果:資料按id取模的方式劃分到了兩個資料庫中,同時從庫同步了主庫的資料
水準切分(id取模)
- 測試模糊查詢+分頁
@Test
public void testFind() {
Pageable pageable = new PageRequest(0, 10, Sort.Direction.ASC, "id");
List<User> userList = userDao.findByNameLike("%李四1%", pageable).getContent();
userList.forEach(System.out::println);
Pageable pageable2 = new PageRequest(0, 10, Sort.Direction.ASC, "userId");
List<Student> studentList = studentDao.findByNameLike("%李四學生2%", pageable2).getContent();
studentList.forEach(System.out::println);
}
測試結果:按照模糊比對及id升序的方式輸出結果
測試結果:讀操作都走了從庫
讀寫分離,讀都走了從庫
- 删除及修改請自行測試
Mycat系列
Mycat(入門篇) Mycat(配置篇) Mycat(實踐篇 - 基于Mysql的水準切分、主從複制、讀寫分離) Mycat(實踐篇 - 基于PostgreSQL的水準切分、主從複制、讀寫分離)
參考連結
Mycat官網 Mycat從零開始 Mycat權威指南 GitHub:Mycat-Server Wiki:Mycat-Server Issues:Mycat-Server mysql中間件研究(Atlas,Cobar,TDDL) mysql中間件研究(Atlas,Cobar,TDDL,Mycat,Heisenberg,Oceanus,Vitess,OneProxy)