- 投稿日:2020-01-19T23:59:37+09:00
LaradockでLaravelの環境構築するもMysqlが立ち上がらない!
開発環境
- macOS Mojave 10.14.4
- Laravel6.(php7.3以上)
- Mysql8.
環境構築:参考記事
初心者でもLaradockでLaravelの環境構築をエラーなしで行おう!(Mac ver)
初心者なりに環境構築で詰まったところを共有します。
記事を参考に進めていく途中
docker-compose up -d nginx mysql phpmyadmin
mysqlが立ち上がらない
Docker再起動しても立ち上がらない!
困った!エラー内容
Recreating laradock_mysql_1 ... error ERROR: for mysql Cannot start service mysql: driver failed programming external connectivity on endpoint laradock_mysql_1(aa02fd7a36f486c3c62720a98798b7625cd855e49b5c4ef25b26a425e1299e0c): Error starting userland proxy: listen tcp 0.0.0.0:3306: bind: address already in use3306が既に使われているってことか?
ググる...
Laradock公式にこんな記述が
docker-compose.ymlの中のports欄を消せばよいとのお告げ
docker-compose.yml### MySQL ################################################ mysql: build: context: ./mysql args: - MYSQL_VERSION=${MYSQL_VERSION} environment: - MYSQL_DATABASE=${MYSQL_DATABASE} - MYSQL_USER=${MYSQL_USER} - MYSQL_PASSWORD=${MYSQL_PASSWORD} - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - TZ=${WORKSPACE_TIMEZONE} volumes: - ${DATA_PATH_HOST}/mysql:/var/lib/mysql - ${MYSQL_ENTRYPOINT_INITDB}:/docker-entrypoint-initdb.d ports: - "${MYSQL_PORT}:3306" networks: - backendports: - "${MYSQL_PORT}:3306"
これを削除してみる...再度
docker-compose up -d nginx mysql phpmyadmin
できた!ありがとうLaradock公式!!
- 投稿日:2020-01-19T23:59:37+09:00
悲劇!LaradockでLaravelの環境構築するもMysqlが立ち上がらない!
開発環境
- macOS Mojave 10.14.4
- Laravel6.(php7.3以上)
- Mysql8.
環境構築:参考記事
初心者でもLaradockでLaravelの環境構築をエラーなしで行おう!(Mac ver)
初心者なりに環境構築で詰まったところを共有します。
記事を参考に進めていく途中
docker-compose up -d nginx mysql phpmyadmin
mysqlが立ち上がらない
Docker再起動しても立ち上がらない!
困った!エラー内容
Recreating laradock_mysql_1 ... error ERROR: for mysql Cannot start service mysql: driver failed programming external connectivity on endpoint laradock_mysql_1(aa02fd7a36f486c3c62720a98798b7625cd855e49b5c4ef25b26a425e1299e0c): Error starting userland proxy: listen tcp 0.0.0.0:3306: bind: address already in use3306が既に使われているってことか?
ググる...
Laradock公式にこんな記述が
docker-compose.ymlの中のports欄を消せばよいとのお告げ
docker-compose.yml### MySQL ################################################ mysql: build: context: ./mysql args: - MYSQL_VERSION=${MYSQL_VERSION} environment: - MYSQL_DATABASE=${MYSQL_DATABASE} - MYSQL_USER=${MYSQL_USER} - MYSQL_PASSWORD=${MYSQL_PASSWORD} - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - TZ=${WORKSPACE_TIMEZONE} volumes: - ${DATA_PATH_HOST}/mysql:/var/lib/mysql - ${MYSQL_ENTRYPOINT_INITDB}:/docker-entrypoint-initdb.d ports: - "${MYSQL_PORT}:3306" networks: - backendports: - "${MYSQL_PORT}:3306"
これを削除してみる...再度
docker-compose up -d nginx mysql phpmyadmin
できた!ありがとうLaradock公式!!
- 投稿日:2020-01-19T23:38:34+09:00
MySQL Shell 8.0.19 で InnoDB ReplicaSet をちょっとだけ試してみる
先日 MySQL 8.0.19 がリリースされ、あわせて MySQL Shell 8.0.19 もリリースされました。
MySQL Shell には「AdminAPI」という管理 API が実装されていますが、8.0.19 でこの AdminAPI が機能強化されて、InnoDB ReplicaSet の構築ができるようになりました。
今回、この InnoDB ReplicaSet を構築する作業を試してみたいと思います。
※おそらく近日中にもっと詳しい(マニアックな?)エントリがこちらに掲載されることでしょう。
MySQL InnoDB ReplicaSet とは?
簡単にいうと「GTID と非同期レプリケーションを利用した、Master(Writer) - Slave(Reader) 型のクラスタ」です。Master(Writer) は 1 台のみですが、Slave(Reader) は複数台の構成にすることができます。
- The all new MySQL InnoDB ReplicaSet(MySQL Server Blog)
これまで、MySQL(InnoDB)には InnoDB Cluster が存在しましたが、
- グループレプリケーションではなく非同期レプリケーションを使う
- InnoDB ReplicaSet のフェイルオーバは手動のみ可能(スクリプト等で自動化することは可能)
- マルチ Master(Writer) の構成は不可
などの点が InnoDB Cluster と異なります。
要は、グループレプリケーションではない、MySQL としては「従来型」のレプリケーションを使うクラスタが簡単に構築できるようになった、ということです。
- 21.6 InnoDB ReplicaSet(MySQL 8.0 Reference Manual)
簡単に試してみる
細かい調査はプロの方々にお任せして、ここでは簡単に試してみます。
- 構成は Master(Writer) 1 台=サーバ名
rs-1
、Slave(Reader) 1 台=サーバ名rs-2
- InnoDB ReplicaSet を構築して、Master(Writer) で行った変更が Slave(Reader) に伝搬することを確認する
- 今回は MySQL Router の設定は行わない
準備
以下のような環境を用意します。
- OS:Linux × 2 台(サーバ名
rs-1
とrs-2
)rs-1
・rs-2
双方に mysql-community-server の 8.0.19 をインストールし、mysql_secure_installation
で初期設定しておくrs-1
に MySQL Shell 8.0.19 をインストールしておくrs-1
・rs-2
双方にroot@rs-1
ユーザを作成し、WITH GRANT OPTION
付きで全権限を許可しておく- 双方の IP アドレスを /etc/hosts ファイルで名前解決できるようにしておく
Master(Writer) インスタンスを設定する
まず MySQL Shell を起動します。
# mysqlsh -u root -p Please provide the password for 'root@localhost': ************ ※パスワードを入力 Save password for 'root@localhost'? [Y]es/[N]o/Ne[v]er (default No): ※[Enter]を入力お好みでパスワードを保存(
Y
)/一切保存しない(v
)を選択しても良いでしょう。MySQL Shell 8.0.19 Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type '\help' or '\?' for help; '\quit' to exit. Creating a session to 'root@localhost' Fetching schema names for autocompletion... Press ^C to stop. Your MySQL connection id is 16 (X protocol) Server version: 8.0.19 MySQL Community Server - GPL No default schema selected; type \use <schema> to set one.あらためて Master(writer) インスタンスにネットワーク接続します。
MySQL localhost:33060+ ssl JS > \connect root@rs-1:3306 ※rs-1(Master)に接続 Creating a session to 'root@rs-1:3306' Please provide the password for 'root@rs-1:3306': ************ ※パスワードを入力 Save password for 'root@rs-1:3306'? [Y]es/[N]o/Ne[v]er (default No): ※[Enter]を入力 Fetching schema names for autocompletion... Press ^C to stop. Closing old connection... Your MySQL connection id is 18 Server version: 8.0.19 MySQL Community Server - GPL No default schema selected; type \use <schema> to set one.Master(Writer) インスタンスを設定します。
MySQL rs-1:3306 ssl JS > dba.configureReplicaSetInstance('root@rs-1:3306', {clusterAdmin: "'rsadmin'@'rs-1%'"}); ※Masterインスタンスを設定 Please provide the password for 'root@rs-1:3306': ************ ※パスワードを入力 Save password for 'root@rs-1:3306'? [Y]es/[N]o/Ne[v]er (default No): ※[Enter]を入力 Configuring local MySQL instance listening at port 3306 for use in an InnoDB ReplicaSet... This instance reports its own address as rs-1:3306 Clients and other cluster members will communicate with it through this address by default. If this is not correct, the report_host MySQL system variable should be changed. Password for new account: ************ ※ReplicaSet管理アカウント(新規追加)用パスワードを入力 Confirm password: ************ ※同上 NOTE: Some configuration options need to be fixed: +--------------------------+---------------+----------------+--------------------------------------------------+ | Variable | Current Value | Required Value | Note | +--------------------------+---------------+----------------+--------------------------------------------------+ | enforce_gtid_consistency | OFF | ON | Update read-only variable and restart the server | | gtid_mode | OFF | ON | Update read-only variable and restart the server | | server_id | 1 | <unique ID> | Update read-only variable and restart the server | +--------------------------+---------------+----------------+--------------------------------------------------+設定は動的適用されませんので、再起動が必要です。
Some variables need to be changed, but cannot be done dynamically on the server. Do you want to perform the required configuration changes? [y/n]: y ※「y」を入力 Do you want to restart the instance after configuring it? [y/n]: y ※「y」を入力 Cluster admin user 'rsadmin'@'rs-1%' created. Configuring instance... The instance 'rs-1:3306' was configured to be used in an InnoDB ReplicaSet. Restarting MySQL... NOTE: MySQL server at rs-1:3306 was restarted.ReplicaSet を作成する
Master(Writer) インスタンス設定後は、ReplicaSet を作成します。
ここからは先ほどの MySQL Shell 操作の続きとなります(以降同じ)。
念のため Master(Writer) インスタンスに再接続します(おそらく不要だと思いますが)。
MySQL rs-1:3306 ssl JS > \connect root@rs-1:3306 ※rs-1(Master)に再接続 Creating a session to 'root@rs-1:3306' Please provide the password for 'root@rs-1:3306': ************ ※パスワードを入力 Save password for 'root@rs-1:3306'? [Y]es/[N]o/Ne[v]er (default No): ※[Enter]を入力 Fetching schema names for autocompletion... Press ^C to stop. Closing old connection... Your MySQL connection id is 9 Server version: 8.0.19 MySQL Community Server - GPL No default schema selected; type \use <schema> to set one.
example
という名前の ReplicaSet を作成します。MySQL rs-1:3306 ssl JS > var rs = dba.createReplicaSet("example") ※ReplicaSetを作成 A new replicaset with instance 'rs-1:3306' will be created. * Checking MySQL instance at rs-1:3306 This instance reports its own address as rs-1:3306 rs-1:3306: Instance configuration is suitable. * Updating metadata... ReplicaSet object successfully created for rs-1:3306. Use rs.addInstance() to add more asynchronously replicated instances to this replicaset and rs.status() to check its status.作成できたようなので、画面の指示通り ReplicaSet のステータスを確認してみます。
MySQL rs-1:3306 ssl JS > rs.status() ※ReplicaSetのステータスを確認 { "replicaSet": { "name": "example", "primary": "rs-1:3306", "status": "AVAILABLE", "statusText": "All instances available.", "topology": { "rs-1:3306": { "address": "rs-1:3306", "instanceRole": "PRIMARY", "mode": "R/W", "status": "ONLINE" } }, "type": "ASYNC" } }Master(Writer) インスタンス
rs-1
の情報が表示されました。Slave(Reader) インスタンスを設定する
引き続き、Slave(Reader) インスタンスを設定します。
今度は Slave(Reader) インスタンスにネットワーク接続します。
MySQL rs-1:3306 ssl JS > \connect root@rs-2:3306 ※rs-2(Slave)に接続 Creating a session to 'root@rs-2:3306' Please provide the password for 'root@rs-2:3306': ************ ※パスワードを入力 Save password for 'root@rs-2:3306'? [Y]es/[N]o/Ne[v]er (default No): ※[Enter]を入力 Fetching schema names for autocompletion... Press ^C to stop. Closing old connection... Your MySQL connection id is 15 Server version: 8.0.19 MySQL Community Server - GPL No default schema selected; type \use <schema> to set one.Slave(Reader) インスタンスを設定します。
MySQL rs-2:3306 ssl JS > dba.configureReplicaSetInstance('root@rs-2:3306', {clusterAdmin: "'rsadmin'@'rs-2%'"}); ※Slaveインスタンスを設定 Please provide the password for 'root@rs-2:3306': ************ ※パスワードを入力 Save password for 'root@rs-2:3306'? [Y]es/[N]o/Ne[v]er (default No): ※[Enter]を入力 Configuring MySQL instance at rs-2:3306 for use in an InnoDB ReplicaSet... This instance reports its own address as rs-2:3306 Clients and other cluster members will communicate with it through this address by default. If this is not correct, the report_host MySQL system variable should be changed. Password for new account: ************ ※ReplicaSet管理アカウント用パスワードを入力 Confirm password: ************ ※同上 NOTE: Some configuration options need to be fixed: +--------------------------+---------------+----------------+--------------------------------------------------+ | Variable | Current Value | Required Value | Note | +--------------------------+---------------+----------------+--------------------------------------------------+ | enforce_gtid_consistency | OFF | ON | Update read-only variable and restart the server | | gtid_mode | OFF | ON | Update read-only variable and restart the server | | server_id | 1 | <unique ID> | Update read-only variable and restart the server | +--------------------------+---------------+----------------+--------------------------------------------------+Master(Writer) と同様に再起動が必要です。
Some variables need to be changed, but cannot be done dynamically on the server. Do you want to perform the required configuration changes? [y/n]: y ※「y」を入力 Do you want to restart the instance after configuring it? [y/n]: y ※「y」を入力 Cluster admin user 'rsadmin'@'rs-2%' created. Configuring instance... The instance 'rs-2:3306' was configured to be used in an InnoDB ReplicaSet. Restarting MySQL... NOTE: MySQL server at rs-2:3306 was restarted.Slave(Reader) インスタンスを ReplicaSet に追加する
Slave(Reader) インスタンスを ReplicaSet に追加します。
今度は Master(Writer) インスタンスにネットワーク接続します。
MySQL rs-2:3306 ssl JS > \connect root@rs-1:3306 ※rs-1(Master)に接続 Creating a session to 'root@rs-1:3306' Please provide the password for 'root@rs-1:3306': ************ ※パスワードを入力 Save password for 'root@rs-1:3306'? [Y]es/[N]o/Ne[v]er (default No): ※[Enter]を入力 Fetching schema names for autocompletion... Press ^C to stop. Closing old connection... Your MySQL connection id is 14 Server version: 8.0.19 MySQL Community Server - GPL No default schema selected; type \use <schema> to set one.Slave(Reader) インスタンス
rs-2
を追加します。※2020/01/19 現在、公式リファレンスマニュアルの実行例が間違っている可能性があります(
addInstance()
ではパラメータとしてサーバ(インスタンス)名:ポート番号
を指定)。MySQL rs-1:3306 ssl JS > rs.addInstance('rs-2:3306') ※ReplicaSetにrs-2(Slave)を追加 Adding instance to the replicaset... * Performing validation checks This instance reports its own address as rs-2:3306 rs-2:3306: Instance configuration is suitable. * Checking async replication topology... * Checking transaction state of the instance... NOTE: The target instance 'rs-2:3306' has not been pre-provisioned (GTID set is empty). The Shell is unable to decide whether replication can completely recover its state. The safest and most convenient way to provision a new instance is through automatic clone provisioning, which will completely overwrite the state of 'rs-2:3306' with a physical snapshot from an existing replicaset member. To use this method by default, set the 'recoveryMethod' option to 'clone'. WARNING: It should be safe to rely on replication to incrementally recover the state of the new instance if you are sure all updates ever executed in the replicaset were done with GTIDs enabled, there are no purged transactions and the new instance contains the same GTID set as the replicaset or a subset of it. To use this method by default, set the 'recoveryMethod' option to 'incremental'.Master(Writer) からのクローンを行います。
Please select a recovery method [C]lone/[I]ncremental recovery/[A]bort (default Clone): C ※「C」を入力 * Updating topology Waiting for clone process of the new member to complete. Press ^C to abort the operation. * Waiting for clone to finish... NOTE: rs-2:3306 is being cloned from rs-1:3306 ** Stage DROP DATA: Completed ** Clone Transfer FILE COPY #################################################### 100% Completed PAGE COPY #################################################### 100% Completed REDO COPY #################################################### 100% Completed NOTE: rs-2:3306 is shutting down... * Waiting for server restart... ready * rs-2:3306 has restarted, waiting for clone to finish... ** Stage RESTART: Completed * Clone process has finished: 59.63 MB transferred in about 1 second (~1.00 B/s) ** Configuring rs-2:3306 to replicate from rs-1:3306 ** Waiting for new instance to synchronize with PRIMARY... The instance 'rs-2:3306' was added to the replicaset and is replicating from rs-1:3306.完了したようなので ReplicaSet のステータスを確認します。
MySQL rs-1:3306 ssl JS > rs.status() ※ReplicaSetのステータスを確認 { "replicaSet": { "name": "example", "primary": "rs-1:3306", "status": "AVAILABLE", "statusText": "All instances available.", "topology": { "rs-1:3306": { "address": "rs-1:3306", "instanceRole": "PRIMARY", "mode": "R/W", "status": "ONLINE" }, "rs-2:3306": { "address": "rs-2:3306", "instanceRole": "SECONDARY", "mode": "R/O", "replication": { "applierStatus": "APPLIED_ALL", "applierThreadState": "Slave has read all relay log; waiting for more updates", "receiverStatus": "ON", "receiverThreadState": "Waiting for master to send event", "replicationLag": null }, "status": "ONLINE" } }, "type": "ASYNC" } }今度は Slave(Reader) インスタンス
rs-2
の情報も表示されました。MySQL Shell を終了します。
MySQL rs-1:3306 ssl JS > \q ※MySQL Shellからログアウトする Bye!Master(Writer) インスタンスにデータを入れてみる
ここからは、Master(Writer) → Slave(Reader) 間のレプリケーションの確認です。
まずは Master(Writer) でデータベース・テーブルを作成し、テストデータを挿入します。
# mysql -u root -p Enter password: ※パスワードを入力 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 25 Server version: 8.0.19 MySQL Community Server - GPL Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> CREATE DATABASE example; ※データベースを作成 Query OK, 1 row affected (0.00 sec) mysql> USE example; ※データベースを選択 Database changed mysql> CREATE TABLE sample1 (id INT PRIMARY KEY AUTO_INCREMENT, str VARCHAR(100)); ※テーブルを作成 Query OK, 0 rows affected (0.02 sec) mysql> INSERT INTO sample1 SET str = 'line 1'; ※データを挿入 Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO sample1 SET str = 'line 2'; ※同上 Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO sample1 SET str = 'line 3'; ※同上 Query OK, 1 row affected (0.00 sec)データベース
example
にテーブルsample1
を作成し、3 行のデータを挿入しました。Slave(Reader) インスタンスで確認してみる
Slave(Reader) 側で挿入データの到達を確認します。
# mysql -u root -p Enter password: ※パスワードを入力 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 13 Server version: 8.0.19 MySQL Community Server - GPL Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> SHOW DATABASES; ※データベースを確認 +-------------------------------+ | Database | +-------------------------------+ | example | | information_schema | | mysql | | mysql_innodb_cluster_metadata | | performance_schema | | sys | +-------------------------------+ 6 rows in set (0.00 sec) mysql> USE example; ※データベースを選択 Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> SHOW TABLES; ※テーブルを確認 +-------------------+ | Tables_in_example | +-------------------+ | sample1 | +-------------------+ 1 row in set (0.01 sec) mysql> SELECT * FROM sample1; ※データを確認 +----+--------+ | id | str | +----+--------+ | 1 | line 1 | | 2 | line 2 | | 3 | line 3 | +----+--------+ 3 rows in set (0.00 sec)確認できました。
おわりに
以前は大掛かりな作業が必要だった非同期レプリケーションクラスタ構築ですが、比較的簡単な操作で ReplicaSet として構築できることがわかりました。
また、今回は省略しましたが、AdminAPI では MySQL Router の初期設定も簡素化することが可能です。
- Qiitaに投稿したMySQL 8.0関連記事
- MySQL 8.0 の薄い本(無料で配布中!)
- 投稿日:2020-01-19T22:38:01+09:00
count(*) するときに気をつけたい NULL
create table contents (id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY) comment='コンテンツ'; insert into contents values (), (), (), (), (), (); create table view_logs (id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, content_id BIGINT NOT NULL) comment='コンテンツに対する閲覧ログ'; insert into view_logs (content_id) values (1), (2), (3); select * from contents; select * from view_logs;今回は簡便さを優先して、外部キー制約は付けていません。
コンテンツ 閲覧ログ 6レコード 3レコード。コンテンツIDが4,5,6は閲覧ログがありません。 各コンテンツの閲覧回数は何回でしょうか?
次のようになるはずです。
コンテンツID 閲覧回数 1 1 2 1 3 1 4 0 5 0 6 0 次にSQLを書いてみます。
失敗例
内部結合を使ってカウント
INNER JOINで閲覧ログとコンテンツを結合してしまってはいけません。閲覧ログの中にすべてのコンテンツIDが現れないためです。
閲覧ログにあるコンテンツIDしか閲覧数をカウントすることができません。
SELECT ct.id AS content_id, count(*) AS view_count FROM contents AS ct JOIN view_logs AS vl ON ct.id = vl.content_id GROUP BY content_id外部結合を使ってカウント
閲覧ログとコンテンツIDを内部結合すると、閲覧ログに存在しないコンテンツIDがカウントできませんでした。
それなら、コンテンツIDを基準に外部結合をすれば、すべてのコンテンツIDが網羅できます。
しかし、安直にcount(*)
を使うと罠にハマります。SELECT ct.id as content_id ,count(*) as view_count FROM contents AS ct LEFT OUTER JOIN view_logs AS vl ON ct.id = vl.content_id group by ct.id閲覧ログがないはずのコンテンツID(4,5,6)が閲覧回数が1になっています。
これは、
count(*)
によって行単位でカウントされてしまっていることが原因です。COUNT(*) は行数をカウントするため、ペットの数をカウントするクエリーは次のようになります。
出典:https://dev.mysql.com/doc/refman/5.6/ja/counting-rows.html
COUNT 関数には NULL を件数に含めるために特別な アスタリスク(*)を使用する構文が用意されており NULL を含めて行数を取得することができる。
出典:https://www.shift-the-oracle.com/sql/aggregate-functions/count.html
count する前のレコードを観察する
countする前のレコードを見ると、レコードの数は6で、content_idが4,5,6にはlog_idがNULLになっています。
SELECT ct.id AS content_id, vl.id AS log_id FROM contents AS ct LEFT OUTER JOIN view_logs AS vl ON ct.id = vl.content_id
count(*)
はレコードが存在すればカウントするため、すべてのコンテンツIDについて 1 とカウントします。成功例
カウントしたいカラムを指定して外部結合を使う
view_logs の content_id カラムか id カラムを
count()
に与えれば、求めていた結果が得られます。
count()
には式が入るようになっていて、NULL
を与えた場合 0 とカウント するため、*
ではなくNULL
になりうるカラム名を与えれば、正しくカウントできます。SELECT ct.id as content_id, count(vl.content_id) as view_count FROM contents AS ct LEFT OUTER JOIN view_logs AS vl ON ct.id = vl.content_id group by ct.id実験後の後始末
不要になったテーブルはサクッと消して終了です。
drop table view_logs; drop table contents;
- 投稿日:2020-01-19T20:03:48+09:00
Rails Tutorialの知識から【ポートフォリオ】を作って勉強する話 #17.5 MySQL導入編
こんな人におすすめ
- プログラミング初心者でポートフォリオの作り方が分からない
- Rails Tutorialをやってみたが理解することが難しい
前回:#17 VPC環境構築編
次回:準備中今回の流れ
- SQLite3からMySQLに変更する
この記事は、動画を観た時間を記録するアプリのポートフォリオです。
今回はRailsアプリのDBをSQLite3からAWSによるRDSのMySQLに変更します。
RDSはすでにAWSで作成しているものとします(詳しくは#17をご覧ください)。SQLite3からRDSのMySQLに変更する
RailsアプリのDBをSQLite3からRDSのMySQLに変更します。
- Gemfileを編集する
- エンドポイントを確認する
- database.ymlを編集する
- RDS(MySQL)に接続する
- DBを更新する
Gemfileを編集する
Gemfileから使っているDBを削除し、MySQLを入れます。
Gemfile+ gem 'mysql2' group :development, :test do - gem 'sqlite3' end group :production do - gem 'pg' endshell$ bundle installエンドポイントを確認する
RDSのエンドポイントはDBを設定する際に必要なので、確認します。
AWSにログイン → AWSマネジメントコンソール『RDS』
画面左のダッシュボード『データベース』 → 『自分のアプリ名』 → 下部タブ『接続とセキュリティ』のエンドポイントをコピーdatabase.ymlを編集する
DBの設定を編集します。
config/database.ymldefault: &default adapter: mysql2 encoding: utf8 reconnect: false database: lantern(自分のアプリ名) pool: 5 username: ①任意の名前 password: ②任意のパスワード socket: /var/lib/mysql/mysql.sock host: コピーしたエンドポイント development: <<: *default database: lantern_devlopment(自分のアプリ名) test: <<: *default database: lantern_test(自分のアプリ名) production: <<: *default database: lantern_production(自分のアプリ名)RDS(MySQL)に接続する
RDS(MySQL)に接続します。
shell$ mysql -h コピーしたエンドポイント -P 3306 -u ①任意の名前 -p Enter password:②任意のパスワード繋がらない場合は、一度MySQLを再起動します。
shell$ sudo /etc/init.d/mysqld restartその後はユーザーを作成し、ルート権限を与えます。
mysqlmysql> create user '①任意の名前'@'コピーしたエンドポイント' identified by '②任意のパスワード'; mysql> grant all on `%`.* to '①任意の名前'@'コピーしたエンドポイント' identified by '②任意のパスワード';参考になりました↓
MySqlのソケットエラーを解決する
RailsのDBを(初めから| |後から)MySQLに変更する
RDSのMySQLでGRANT文が通らないDBを更新する
後はいつも通り、DBを更新します。
shell$ rails db:reset $ rails db:migrate $ rails db:seed以上でMySQLの移行が完了しました。
- 投稿日:2020-01-19T15:07:39+09:00
Laravel: 複数のDBに接続
mysqlとSQLite3の同時使用例
php.iniの場所
$ php -r "echo phpinfo();" | grep "php.ini"php.ini//使用するDBをコメントアウト extension=pdo_mysql extension=sqlite3httpdの再起動
データベースの作成設定
.envDB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE_1={データベース名} DB_USERNAME=root DB_PASSWORD=null DB_CONNECTION=sqlite DB_DATABASE_2={パス/データベースファイル名}config/database.php'default' => env('DB_CONNECTION_1', 'mysql'), //略 'sqlite' => [ 'driver' => 'sqlite', 'database' => env('DB_DATABASE_2', database_path({フォルダパス})), 'prefix' => '', ], 'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', 'localhost'), 'database' => env('DB_DATABASE_1', 'forge'), 'username' => env('DB_USERNAME_1', 'forge'), 'password' => env('DB_PASSWORD_1', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'strict' => false, 'engine' => null, ],migration//デフォルトDBにはconnectonメソッドは必要なし Schema::connection('sqlite')->create({テーブル名}, function (Blueprint $table) { }データベースを指定してマイグレーション
$ php artisan migration --database=sqliteModelでの接続設定
Modelclass Datas extends Model { protected $connection = 'sqlite'; }
- 投稿日:2020-01-19T14:57:51+09:00
AWSでDB(MySQL)を作成した後、A5:SQL Mk-2で接続して管理する方法
AWSでは、AWSを初めて使うという方向けに様々なチュートリアルを公式サイトで展開しており、そのチュートリアルに沿って進めていけば基本的なAWSサービスの操作や使用方法について理解することができます。
https://aws.amazon.com/jp/getting-started/tutorials/DB作成もチュートリアルが展開されており、簡単にDB作成・クライアントソフトからの接続ができるのですが、如何せんチュートリアルで紹介されているクライアントソフト「MySQL Workbench」が使いずらいのなんの。
(「MySQL Workbench」を使ったことがないからかもしれませんが。)しかも私のデスクトップPCではインストールしたのにも関わらず、なぜかプロセスが立ち上がらない事象に陥ってしまったのでこれはもうアカンと。
(おそらく「Visual C++ Redistributable for Visual Studio 2013」ランタイムがインストールされていないからと思われる。)なので、よくエンジニアの間で使用されているDB操作フリーソフト「A5:SQL Mk-2」でAWSに作成したDB(MySQL)にアクセスをする方法をご紹介したいと思います。
参考サイト
今回参考にしたサイトはこちらです。
https://a1-style.net/amazon-web-service/rds-mysql-a5-sql-mk2/(AWS)DB(MySQL)を作成
まずは、AWSでDB(MySQL)を作成していきます。
下記AWS公式サイトのDB作成チュートリアルのステップ1まで進めましょう。
ステップ2からは進めなくて大丈夫です。
https://aws.amazon.com/jp/getting-started/tutorials/create-mysql-db/(AWS)セキュリティグループを変更して管理PCからのアクセスを許可する
下記のデータベース管理画面に移動します。
移動後DB識別子のリンクをクリックします。
DBの概要や詳細情報が表示される画面になると思うので、画面中央のセキュリティグループのルールの欄を確認します。
恐らくセキュリティグループのルールとしてデフォルトで設定されている設定が2つ表示されていると思うので、上のセキュリティグループのリンクをクリックします。
セキュリティグループの設定画面に移動したら、画面下のインバウンドタブをクリックし編集ボタンをクリックします。
(下記画像はすでに設定をしている項目が表示されているため気にしなくて良いです。)編集ボタンをクリックすると下記画面のポップアップが表示されるので、下記画像の項目通り「タイプ」「プロトコル」「ポート範囲」入力をしましょう。
ポート範囲はデフォルトでは「3306」です。変更をしている場合はこちらも変更する必要があります。また、ソースの欄はDB接続をしたいPCのIPアドレスを入力するのですが、プルダウンでマイIPを選択すると自動的にIPアドレスが入力されるため特に調べる必要はありません。
すべて入力したら右下の保存ボタンをクリックして完了です。
これでAWSに作成したDBに外部(管理PC)からアクセスすることができるようになりました。
A5:SQL Mk-2で作成したDB(MySQL)と接続をする
A5:SQL Mk-2のダウンロードについて
A5:SQL Mk-2は下記URLからダウンロードすることができます。
https://a5m2.mmatsubara.com/DB接続方法
ダウンロードしたA5:SQL Mk-2を開き、上部メニューからデータベース>データベースの追加・削除を選択します。
下記赤枠の部分「MySQL/MariaDB(直接接続)」を選択します。
下記画面が表示されるので、データベースの情報を入力していきます。
入力後、OKをクリックします。
ホスト名:エンドポイント名(※)
ユーザーID:masterUsername
(AWSのチュートリアルを進めているとmasterUsernameで作られているかと思います。別のユーザーIDで作成している場合はそのユーザーIDを入力する)
パスワード:DB作成時のパスワード
※ホスト名に入力するエンドポイント名は下記画像の左側に表示されているエンドポイント名を入力します。
接続が問題なく完了すると、A5:SQL Mk-2の左側の枠に接続したDBの情報が表示されます。
ちなみに今回は、データベース名を「aws_test」で作成しているため、aws_testというデータベースが作成されていることがわかります。(データベースのみのため、テーブルなどの情報はもちろん追加されていません。)
これで、A5:SQL Mk-2でAWSのDB(MySQL)に接続することができました。
最後に
AWSでデータベースを作成するとこんなにも簡単なんだと思うと同時に、かなりさらにシステム開発としてできる幅が広がった気がします。
今回は、セキュリティグループのインバウンド設定で固定PCのIPアドレスを設定しましたが、このような設定は開発環境などだけにとどめておき、本番環境でのDB設定では行わないようにしましょう。当たり前ですが。
- 投稿日:2020-01-19T09:27:50+09:00
(初心者)MySQLのUDFを簡単に作ってみた
参考
- C++でMySQLのUDFを作る - qiita
- MySQL :: MySQL 8.0 Reference Manual :: 29.4.2 Adding a User-Defined Function
作成した関数
#include <mysql.h> #include <string> extern "C" { my_bool factorial_init(UDF_INIT *initid, UDF_ARGS *args, char *message); char *factorial(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error); } my_bool factorial_init(UDF_INIT *initid, UDF_ARGS *args, char *message) { if (args->arg_count != 1) { strcpy(message,"FACTORIAL() requires one arguments"); return 1; } if (args->arg_type[0] != INT_RESULT) { strcpy(message,"FACTORIAL() require an integer"); return 1; } return 0; } char *factorial(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error) { long long val = *(long long*) args->args[0]; int sum = 1; for (int i = 1; i <= val; ++i) { sum *= i; } strcpy(result, std::to_string(sum).c_str()); *length = strlen(result); return result; }
factorial_init
とfactorial
を作成しています。
factorial_init
が関数実行時に最初に実行されて、引数のチェックなどを行い、
factorial
が実際に処理をする部分です。コンパイル
$ mysql_config --cflags #mysql.hがあるパスを確認 -I/usr/local/opt/mysql@5.7/include/mysql $ mysql_config --plugindir #プラグインのパスを確認 /usr/local/opt/mysql@5.7/lib/plugin $ g++ factorial.cpp -shared \ -o /usr/local/opt/mysql@5.7/lib/plugin/factorial.so \ -I /usr/local/opt/mysql@5.7/include/mysql/ #コンパイルmysql> create function factorial returns string soname 'factorial.so'; Query OK, 0 rows affected (0.01 sec) mysql> select factorial(6); +--------------+ | factorial(6) | +--------------+ | 720 | +--------------+ 1 row in set (0.00 sec)UDFを動かせました。見ていただいてありがとうございました。m(_ _)m