2022.06.24
Haskellのdo記法について
2018.11.20
プログラミングSpringでMaster/Slave構成のMySQLに接続する(with Kotlin)
こんにちは、MTです。
今回は、Master/Slave構成のMySQLに接続する方法についてです。
(具体的には、クエリの発行先をMasterとSlaveで切り替える方法について)
■言語
・Kotlin 1.3.0
■アプリケーション
・SpringBoot 2.1.0
・mysql-connector-java 5.1.45
■MySQL 5.6
・Masterのホスト : localhost:3306
・Slave のホスト : localhost:3307
なお、MySQL自体のレプリケーション設定については触れていません。
通常はurlに指定するのは jdbc:mysql://
スキームですが、Master/Slave構成の場合は jdbc:mysql:replication://
スキームを使用します。
そして jdbc:mysql:replication://
スキームに続けて、Masterのホストアドレス、Slaveのホストアドレスの順にカンマ区切りで記載していきます。
1 2 3 4 5 6 |
spring: datasource: driver-class-name: "com.mysql.jdbc.Driver" url: "jdbc:mysql:replication://localhost:3306,localhost:3307/dev" username: "dev" password: "password" |
こんな感じ。(末尾の /dev はデータベース名。) Slaveの指定は複数でもOKです。
宣言的トランザクションを利用している場合、readOnly
オプションに true
を指定すれば Slave に向きます。
1 2 |
@Transactional(readOnly = true) fun findAllBySlave(): List<User> = this.userRepository.findAll() |
明示的トランザクションを利用する場合は、 java.sql.Connection
インタンスを取得し、setReadOnly
メソッドに true
を設定してください。
事前に以下の user テーブルを作成し、MasterとSlaveで異なるデータを登録しておきます。
1 2 3 4 |
CREATE TABLE IF NOT EXISTS user ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
1 2 |
-- Master側 INSERT INTO user (name) VALUES ("user1"), ("user2"),( "user3"); |
1 2 |
-- Slave側 INSERT INTO user (name) VALUES ("user4"), ("user5"),( "user6"); |
次にデータを取得するサービス層で、宣言的トランザクションを利用して、読み取り専用とするかを定義しておきます。
1 2 3 4 5 6 7 8 9 |
@Service class UserService(private val userRepository: UserRepository) { @Transactional(readOnly = false) fun findAllByMaster(): List<User> = this.userRepository.findAll() @Transactional(readOnly = true) fun findAllBySlave(): List<User> = this.userRepository.findAll() } |
ユーザ情報を取得するためのエンドポイントは以下のようにしました。
・/master
: Master側に登録されたユーザ情報を取得する。
・/slave
: Slave側に登録されたユーザ情報を取得する。
ではアクセスしてみます。
1 2 3 4 |
$ curl localhost:8080/master [{"id":1,"name":"user1"},{"id":2,"name":"user2"},{"id":3,"name":"user3"}] $ curl localhost:8080/slave [{"id":1,"name":"user4"},{"id":2,"name":"user5"},{"id":3,"name":"user6"}] |
ちゃんと向き先が変わってますね。
1 2 3 4 5 6 |
spring: datasource: driver-class-name: "com.mysql.jdbc.Driver" url: "jdbc:mysql:replication://localhost:3306,localhost:3307/dev" username: "dev" password: "password" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
@RestController @SpringBootApplication class MysqlReplicationSandboxApplication constructor(private val service: UserService) { @RequestMapping("master") fun getByMaster(): List<User> = this.service.findAllByMaster() @RequestMapping("slave") fun getBySlave(): List<User> = this.service.findAllBySlave() companion object { @JvmStatic fun main(args: Array<String>) { SpringApplication.run(MysqlReplicationSandboxApplication::class.java, *args) } } } @Entity data class User ( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long, val name: String ): Serializable @Service class UserService(private val userRepository: UserRepository) { @Transactional(readOnly = false) fun findAllByMaster(): List<User> = this.userRepository.findAll() @Transactional(readOnly = true) fun findAllBySlave(): List<User> = this.userRepository.findAll() } @Repository interface UserRepository : JpaRepository<User, Long> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
version: '3.1' services: db1: image: mysql:5.6 ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD : "password" MYSQL_DATABASE: "dev" MYSQL_USER: "dev" MYSQL_PASSWORD: "password" volumes: - ./mysql/init_master/:/docker-entrypoint-initdb.d db2: image: mysql:5.6 ports: - "3307:3306" environment: MYSQL_ROOT_PASSWORD : "password" MYSQL_DATABASE: "dev" MYSQL_USER: "dev" MYSQL_PASSWORD: "password" volumes: - ./mysql/init_slave/:/docker-entrypoint-initdb.d |
【テクノモバイルではエンジニア/デザイナーを積極採用中です!】
下記項目に1つでも当てはまる方は是非、詳細ページへ!Qangaroo(カンガルー)
最近の記事
タグ検索
SNS共有