Springboot + Mysql8實現(xiàn)讀寫分離功能
在實際的生產(chǎn)環(huán)境中,為了確保數(shù)據(jù)庫的穩(wěn)定性,我們一般會給數(shù)據(jù)庫配置雙機熱備機制,這樣在master數(shù)據(jù)庫崩潰后,slave數(shù)據(jù)庫可以立即切換成主數(shù)據(jù)庫,通過主從復(fù)制的方式將數(shù)據(jù)從主庫同步至從庫,在業(yè)務(wù)代碼中編寫代碼實現(xiàn)讀寫分離(讓主數(shù)據(jù)庫處理 事務(wù)性增、改、刪操作,而從數(shù)據(jù)庫處理查詢操作)來提升數(shù)據(jù)庫的并發(fā)負(fù)載能力。
下面我們使用最新版本的Mysql數(shù)據(jù)庫(8.0.16)結(jié)合SpringBoot實現(xiàn)這一完整步驟(一主一從)。
安裝配置mysql
從 https://dev.mysql.com/downloads/mysql/頁面下載mysql安裝包,我這里下載的是mysql8.0.16 Linux-Generic.
準(zhǔn)備兩臺虛擬機用作安裝mysql,并將下載后的文件mysql-8.0.16-linux-glibc2.12-x86_64.tar.xz
上傳至服務(wù)器/app/mysql
192.168.249.131 CENTOS7 主
192.168.249.129 CENTOS7 從
查看防火墻狀態(tài),如果啟動需要先關(guān)閉防火墻
service firewalld status ## 查看防火墻狀態(tài) service firewalld stop ## 關(guān)閉防火墻 使用如下命令將xz文件解壓成tar文件 xz -d mysql-8.0.16-linux-glibc2.12-x86_64.tar.xz
解壓安裝包
tar -xvf mysql-8.0.16-linux-gl-ibc2.12-x86_64.tar
在/app/mysql下建立data文件夾,用于存放數(shù)據(jù)
創(chuàng)建mysql用戶組和mysql用戶
groupadd mysql ## 創(chuàng)建用戶組 useradd -g mysql -d /app/mysql mysql ## 在用戶組下創(chuàng)建mysql用戶并授權(quán)相關(guān)目錄 groupdel mysql ## 刪除用戶組名(若報已存在相關(guān)用戶組) userdel mysql ## 刪除用戶(若報已存在相關(guān)用戶)
初始化安裝mysql數(shù)據(jù)庫
./mysql-8.0.16-linux-glibc2.12-x86_64/bin/mysqld --user=mysql --basedir=/app/mysql --datadir=/app/mysql/data --initialize 2019-07-01T02:05:52.681626Z 0 [Warning] [MY-011070] [Server] 'Disabling symbolic links using --skip-symbolic-links (or equivalent) is the default. Consider not using this option as it' is deprecated and will be removed in a future release. 2019-07-01T02:05:52.681694Z 0 [System] [MY-013169] [Server] /app/mysql/mysql-8.0.16-linux-glibc2.12-x86_64/bin/mysqld (mysqld 8.0.16) initializing of server in progress as process 1479 2019-07-01T02:05:52.681726Z 0 [ERROR] [MY-010338] [Server] Can't find error-message file '/app/mysql/share/errmsg.sys'. Check error-message file location and 'lc-messages-dir' configuration directive. 2019-07-01T02:05:55.713747Z 5 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: xa6(H>rK/r<E 2019-07-01T02:05:57.303240Z 0 [System] [MY-013170] [Server] /app/mysql/mysql-8.0.16-linux-glibc2.12-x86_64/bin/mysqld (mysqld 8.0.16) initializing of server has completed
注意,此時mysql會生成一個默認(rèn)的臨時密碼,如上所示,需要先保存下來然后修改
建立mysql服務(wù)并增加執(zhí)行權(quán)限
cp mysql-8.0.16-linux-glibc2.12-x86_64/support-files/mysql.server /etc/init.d/mysqld
修改mysql配置文件 vi /etc/my.cnf 增加如下配置
[mysqld] port=3306 basedir=/app/mysql/mysql-8.0.16-linux-glibc2.12-x86_64 datadir=/app/mysql/data socket=/tmp/mysql.sock symbolic-links=0 [mysqld_safe] log-error=/app/mysql/data/log/error.log pid-file=/app/mysql/data/mysql.pid user=mysql tmpdir=/tmp character_set_server=utf8 default-storage-engine=INNODB init_connect='SET NAMES utf8' !includedir /etc/my.cnf.d
如果報日志權(quán)限相關(guān)錯誤,請先建立對應(yīng)日志文件,并給mysql用戶授權(quán)
chown -R mysql:mysql /app/mysql/data/log/error.log
啟動mysql服務(wù)
service mysqld start
建立mysql客戶端軟連接
ln -s /app/mysql/mysql-8.0.16-linux-glibc2.12-x86_64/bin/mysql /usr/local/bin/mysql
登錄mysql修改密碼
mysql -uroot -p密碼 ## 登錄 ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '000000';
設(shè)置遠(yuǎn)程登錄
use mysql; update user set host='%' where user='root' limit 1; flush privileges;
配置mysql主從同步(binlog)
復(fù)制原理
- Master將數(shù)據(jù)改變記錄到二進(jìn)制日志(binary log)中,也就是配置文件log-bin指定的文件,這些記錄叫做二進(jìn)制日志事件(binary log events)
- Slave通過I/O線程讀取Master中的binary log events并寫入到它的中繼日志(relay log)
- Slave重做中繼日志中的事件,把中繼日志中的事件信息一條一條的在本地執(zhí)行一次,完成數(shù)據(jù)在本地的存儲,從而實現(xiàn)將改變反映到它自己的數(shù)據(jù)(數(shù)據(jù)重放)
復(fù)制要求
- 主從服務(wù)器操作系統(tǒng)版本和位數(shù)一致
- Master和Slave數(shù)據(jù)庫的版本要一致
- Master和Slave數(shù)據(jù)庫中的數(shù)據(jù)要一致
- Master開啟二進(jìn)制日志,Master和Slave的server_id在局域網(wǎng)內(nèi)必須唯一
配置步驟
主數(shù)據(jù)庫(192.168.249.131)
創(chuàng)建同步用戶并授權(quán)
CREATE USER 'slave'@'192.168.249.129' IDENTIFIED WITH 'mysql_native_password' BY '000000'; GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'192.168.249.129'; FLUSH PRIVILEGES;
注意這里創(chuàng)建用戶時需要選用mysql_native_password
加密方式插件,否則默認(rèn)會使用caching_sha2_password加密方式,這樣在同步的時候需要使用SSL的身份進(jìn)行驗證,為了方便簡單,我們直接采用mysql_native_password方式
修改配置/etc/my.cnf
,新增如下配置,開啟binlog,并重啟mysql服務(wù)
[mysqld] # 開啟二進(jìn)制日志功能 log-bin=mysql-bin #
設(shè)置server_id,,注意在網(wǎng)段內(nèi)要唯一 server-id=131 #(可選配置)要同步的數(shù)據(jù)庫名,要同步多個數(shù)據(jù)庫,就多加幾個replicate-db-db=數(shù)據(jù)庫名 binlog-do-db=mydb #(
可選配置)要忽略的數(shù)據(jù)庫 binlog-ignore-db=mysql
查看主服務(wù)器狀態(tài)
show master status file
注意看里面的參數(shù),特別前面兩個File和Position,在從服務(wù)器(Slave)配置主從關(guān)系會有用到的。
從數(shù)據(jù)庫(192.168.249.129)
修改/etc/my.cnf,新增如下配置,并重啟服務(wù)
[mysqld] server-id=129 log-bin=mysql-bin replicate-do-db=mydb replicate-ignore-db=mysql
在slave中設(shè)置master信息,指定同步位置
stop slave; change master to master_host='192.168.249.131',master_user='slave',master_password='000000',master_log_file='mysql-bin.000001',master_log_pos=155; start slave;
參數(shù)說明:
master_host='192.168.249.131' ## Master的IP地址
master_user='slave' ## 用于同步數(shù)據(jù)的用戶(在Master中授權(quán)的用戶)
master_password='000000' ## 同步數(shù)據(jù)用戶的密碼
master_port=3306 ## Master數(shù)據(jù)庫服務(wù)的端口
masterlogfile='mysql-bin.000001' ##指定Slave從哪個日志文件開始讀復(fù)制數(shù)據(jù)(Master上執(zhí)行命令的結(jié)果的File字段)
masterlogpos=155 ## 從哪個POSITION號開始讀(Master上執(zhí)行命令的結(jié)果的Position字段)
masterconnectretry=30 ##當(dāng)重新建立主從連接時,如果連接建立失敗,間隔多久后重試。單位為秒,默認(rèn)設(shè)置為60秒,同步延遲調(diào)優(yōu)參數(shù)。
查看從服務(wù)器狀態(tài)
show slave status\G;
至此數(shù)據(jù)庫層面主從配置完成。
SpringBoot中配置主從讀寫分離
在主從模式下請遵守如下規(guī)則:
主數(shù)據(jù)庫 只執(zhí)行 INSERT,UPDATE,DELETE 操作
從數(shù)據(jù)庫 只執(zhí)行SELECT操作
我們這里使用開源項目[dynamic-datasource-spring-boot-starter](https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter/wikis/)作為讀寫分離的工具包
使用方法
在mydb主數(shù)據(jù)庫中建立一個簡單數(shù)據(jù)表user,建好后從數(shù)據(jù)庫會自動同步
DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `account` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `position` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
引入相關(guān)依賴
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>2.5.5</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.15</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
配置數(shù)據(jù)源
spring: datasource: dynamic: primary: master #設(shè)置默認(rèn)的數(shù)據(jù)源或者數(shù)據(jù)源組,默認(rèn)值即為master strict: false #設(shè)置嚴(yán)格模式,默認(rèn)false不啟動. 啟動后再為匹配到指定數(shù)據(jù)源時候回拋出異常,不啟動會使用默認(rèn)數(shù)據(jù)源. datasource: master: type: com.zaxxer.hikari.HikariDataSource url: jdbc:mysql://192.168.249.131:3306/mydb?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false username: root password: '000000' driver-class-name: com.mysql.cj.jdbc.Driver slave_1: type: com.zaxxer.hikari.HikariDataSource url: jdbc:mysql://192.168.249.129:3306/mydb?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false username: root password: '000000' driver-class-name: com.mysql.cj.jdbc.Driver
在啟動類入口加入mybatis掃描包
@SpringBootApplication@MapperScan("com.jianzh5.dynamic.mapper") public class DynamicDatsourceBootstrap { public static void main(String[] args) { SpringApplication.run(DynamicDatsourceBootstrap.class, args); } }
建立實體類User
@Data public class User { private int id; private String account; private String name; private String position; }
建立mapper接口文件,新增兩個方法addUser(User user),getById(int id)
public interface UserDao { @Insert("INSERT INTO user(account, name, position) VALUES(#{account}, #{name}, #{position})") @Options(useGeneratedKeys = true,keyProperty = "id") int addUser(User user); @Select("SELECT * FROM user WHERE id = #{id}") User getById(int id); }
建立Service服務(wù)層相關(guān)實現(xiàn)
public interface UserService { int addUser(User user); User getById(int id); } @Service public class UserServiceImpl implements UserService { @Resource private UserDao userDao; @Override public int addUser(User user) { return userDao.addUser(user); } @DS("slave") @Override public User getById(int id) { return userDao.getById(id); } }
由于在數(shù)據(jù)源中配置了primary: master,默認(rèn)操作都會從主庫執(zhí)行,使用注解@DS切換數(shù)據(jù)源,此注解也可直接用于類文件上,同時存在方法注解優(yōu)先于類上注解。
編寫單元測試進(jìn)行測試
public class UserServiceTest extends DynamicDatsourceBootstrapTests { @Autowired private UserService userService; @Test public void testAddUser(){ User user = new User(); user.setName("李四"); user.setAccount("sili"); user.setPosition("JAVA開發(fā)工程師"); int i = userService.addUser(user); System.out.println(user); } @Test public void testGetById(){ int id = 4; User user = userService.getById(id); Assert.assertEquals("sanzhang",user.getAccount()); } }
通過觀察執(zhí)行日志,發(fā)現(xiàn)讀寫數(shù)據(jù)庫會根據(jù)@DS注解進(jìn)行切換,至此Springboot集成數(shù)據(jù)庫主從讀寫分離完成。
總結(jié)
以上所述是小編給大家介紹的Springboot + Mysql8實現(xiàn)讀寫分離功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!
相關(guān)文章
Java源碼解析之Gateway請求轉(zhuǎn)發(fā)
今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識,文章圍繞著Gateway請求轉(zhuǎn)發(fā)展開,文中有非常詳細(xì)介紹及代碼示例,需要的朋友可以參考下2021-06-06springboot中如何通過main方法調(diào)用service或dao
這篇文章主要介紹了springboot中如何通過main方法調(diào)用service或dao,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02rabbitmq的消息持久化處理開啟,再關(guān)閉后,消費者啟動報錯問題
這篇文章主要介紹了rabbitmq的消息持久化處理開啟,再關(guān)閉后,消費者啟動報錯問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11JAVA實現(xiàn)連接本地打印機并打印文件的實現(xiàn)代碼
這篇文章主要介紹了JAVA實現(xiàn)連接本地打印機并打印文件的實現(xiàn)代碼,需要的朋友可以參考下2019-10-10