メニューを閉じる

テクノデジタルグループ

メニューを開く

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://ではなく、jdbc:mysql:replication://を使用する。

通常はurlに指定するのは jdbc:mysql://スキームですが、Master/Slave構成の場合は jdbc:mysql:replication:// スキームを使用します。
そして jdbc:mysql:replication:// スキームに続けて、Masterのホストアドレス、Slaveのホストアドレスの順にカンマ区切りで記載していきます。

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です。

Master or Slave の向き先を切り替える

宣言的トランザクションを利用している場合、readOnly オプションに true を指定すれば Slave に向きます。

@Transactional(readOnly = true)
fun findAllBySlave(): List<User> = this.userRepository.findAll()

明示的トランザクションを利用する場合は、 java.sql.Connection インタンスを取得し、setReadOnly メソッドに true を設定してください。

実際に動かして確認してみる。

事前に以下の user テーブルを作成し、MasterとSlaveで異なるデータを登録しておきます。

CREATE TABLE IF NOT EXISTS user (
  id   BIGINT       PRIMARY  KEY AUTO_INCREMENT,
  name VARCHAR(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Master側
INSERT INTO user (name) VALUES ("user1"), ("user2"),( "user3");
-- Slave側
INSERT INTO user (name) VALUES ("user4"), ("user5"),( "user6");

次にデータを取得するサービス層で、宣言的トランザクションを利用して、読み取り専用とするかを定義しておきます。

@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側に登録されたユーザ情報を取得する。

ではアクセスしてみます。

$ 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"}]

ちゃんと向き先が変わってますね。

今回のプログラムとか

application.yml

spring:
  datasource:
    driver-class-name: "com.mysql.jdbc.Driver"
    url: "jdbc:mysql:replication://localhost:3306,localhost:3307/dev"
    username: "dev"
    password: "password"

MysqlReplicationSandboxApplication.kt

@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>

docker-compose.yml

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つでも当てはまる方は是非、詳細ページへ!
  • 自分でアプリを作ってみたい
  • ITで世の中にワクワクを生み出したい
  • 使いやすさ、デザインにこだわったWebサイトを開発したい

採用情報の詳細はこちら


Qangaroo(カンガルー)

  • 徹底した見やすさと優れた操作性で、テストの「見える化」を実現。
  • テストの進捗が見える。開発がスマートに進む。
  • クラウド型テスト管理ツール『Qangaroo(カンガルー)』

【テクノデジタルのインフラサービス】

当社では、多数のサービスの開発実績を活かし、
アプリケーションのパフォーマンスを最大限に引き出すインフラ設計・構築を行います。
AWSなどへのクラウド移行、既存インフラの監視・運用保守も承りますので、ぜひご相談ください。
詳細は下記ページをご覧ください。

https://www.tcdigital.jp/infrastructure/

最近の記事