20200211のMySQLに関する記事は10件です。

[MySQL]インデックス�と索引の違いについて

この投稿の経緯

インデックスはDBの初学者に、「索引」という2文字で説明されることが多い。
私も、その説明で何となく理解したつもりになっていたが、よくよく考えてみると「索引」ではインデックスを正確に理解することはできない気がしてきた(無知の知)。
「索引」と「インデックス」の2つを比較しながら頭の整理をしたメモ書き的な内容です。
認識が違っていましたら、コメントお待ちしております。
ここでは本の索引は「索引」、DBのインデックスは「インデックス」と呼びます。

索引

索引とは

引用元
https://www.weblio.jp/content/%E3%81%95%E3%81%8F%E3%81%84%E3%82%93

ある書物に載っている項目・人名・用語などを書き出して五十音順などに並べ、その所在ページなどを示した表。インデックス。

  • 本でいうページにあたるものが主キー
  • 索引の項目は1項目単位で表現

「大陸の生態系」みたいな本の索引のイメージです

image.png

インデックス

インデックスとは

  • インデックスの種類
    • インデックスのない状態: ページの順番がバラバラな本でしょうか?
    • クラスタインデックス: 本自身(「キー:ページ、値:本文」、一意のキーが連番で昇順に並んでいる)です
    • セカンダリインデックス: 索引です ※ALTERで作成するインデックスはこちらのことです
      • 単一列インデックス
        • 本の索引に近い(1項目単位の項目と該当する主キー(ページ)だけを持っている)のはこっち
      • カバリングインデックス 本の索引とは異なる(複数項目を組み合わせた単位の項目と該当する主キー(ページ)及び取得するべき全ての値を持っている)
        • 複合インデックス(予め組み合わせを作っておく)
        • インデックスマージ(複数の単一列インデックスがクエリ実行の際に合体、オーバーヘッドあり)

continentテーブルです

image.png

カバリングインデックスの定義だとこうなります
alter table continent add index (name, animal, fruit);

まとめ

索引は項目一つに対して一つまたは、複数のページを参照させるもの。
インデックスは、項目一つまたは、複数の項目の組み合わせに対して一つの主キーを参照させるもの。

インデックスについて調べるとクラスタインデックスとセカンダリインデックスを明示することなく単にインデックスと記載している記事、参考書が多くそこを理解するのに結構苦労しました。
インデックスが効いている言われるときのインデックスはセカンダリインデックスです。
セカンダリの中でもカバリングインデックスは取得項目を全てセカンダリインデックスのリーフブロックに保持しているので、わざわざクラスタインデックスを見に行かなくてよいので検索件数が減り検索が早いです。
索引で例えるなら、索引を見れば本文の内容までわかってしまうといったことでしょうか?
ちなみにフルインデックススキャンとはクラスタインデックスを全て見てるので検索が遅いです。

この様に頭をインデックスと索引の違いを整理すると、「索引」という例えは結構無理があるのかなと思いました。
とはいえ、「索引」の例えは良いアプローチだと思いますので、人に説明するときは、誤解の内容に「索引」という例えを使っていこうと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[MySQL]インデックス�と本の索引の違いについて

この投稿の経緯

インデックスはDBの初学者に、本の「索引」という2文字で説明されることが多い。
私も、その説明で何となく理解したつもりになっていたが、よくよく考えてみると「索引」ではインデックスを正確に理解することはできない気がしてきた(無知の知)。
「索引」と「インデックス」の2つを比較しながら頭の整理をしたメモ書き的な内容です。
認識が違っていましたら、コメントお待ちしております。
ここでは本の索引は「索引」、DBのインデックスは「インデックス」と呼びます。

索引

索引とは

引用元
https://www.weblio.jp/content/%E3%81%95%E3%81%8F%E3%81%84%E3%82%93

ある書物に載っている項目・人名・用語などを書き出して五十音順などに並べ、その所在ページなどを示した表。インデックス。

  • 本でいうページにあたるものが主キー
  • 索引の項目は1項目単位で表現

「大陸の生態系」みたいな本の索引のイメージです

image.png

インデックス

インデックスとは

  • インデックスの種類
    • インデックスのない状態: ページの順番がバラバラな本でしょうか?
    • クラスタインデックス: 本自身(「キー:ページ、値:本文」、一意のキーが連番で昇順に並んでいる)です
    • セカンダリインデックス: 索引です ※ALTERで作成するインデックスはこちらのことです
      • 単一列インデックス
        • 本の索引に近い(1項目単位の項目と該当する主キー(ページ)だけを持っている)のはこっち
      • カバリングインデックス 本の索引とは異なる(複数項目を組み合わせた単位の項目と該当する主キー(ページ)及び取得するべき全ての値を持っている)
        • 複合インデックス(予め組み合わせを作っておく)
        • インデックスマージ(複数の単一列インデックスがクエリ実行の際に合体、オーバーヘッドあり)

continentテーブルです

image.png

カバリングインデックスの定義だとこうなります
alter table continent add index (name, animal, fruit);

まとめ

索引は項目一つに対して一つまたは、複数のページを参照させるもの。
インデックスは、項目一つまたは、複数の項目の組み合わせに対して一つの主キーを参照させるもの。

インデックスについて調べるとクラスタインデックスとセカンダリインデックスを明示することなく単にインデックスと記載している記事、参考書が多くそこを理解するのに結構苦労しました。
インデックスが効いている言われるときのインデックスはセカンダリインデックスです。
セカンダリの中でもカバリングインデックスは取得項目を全てセカンダリインデックスのリーフブロックに保持しているので、わざわざクラスタインデックスを見に行かなくてよいので検索件数が減り検索が早いです。
索引で例えるなら、索引を見れば本文の内容までわかってしまうといったことでしょうか?
ちなみにフルインデックススキャンとはクラスタインデックスセカンダリインデックスのリーフブロックを全て見てるので検索が遅いです。

この様に頭をインデックスと索引の違いを整理すると、「索引」という例えは結構無理があるのかなと思いました。
とはいえ、「索引」の例えは良いアプローチだと思いますので、人に説明するときは、誤解の内容に「索引」という例えを使っていこうと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Sequel Proがクラッシュ(?)した件

Sequel Proがこの画面から進まなくなりました。

image.png

一応、自分なりに公式ドキュメントや、キータを読み漁りましたが解決することができませんでした。

どうしたか

macを初期化し、新しくSequel Proを入れ直しました。(あまり良い方法ではないと思いますが。)

その後、生まれ変わったmacbookにslackやらGithubやらを入れ、問題のSequel Proも入れました。

すると普通にソケット接続がされて、データベースを選択できるようになりました。

なぜこうなったのか

考えられる原因としてはエラーを解決しようとする中で、何度もmysqlのインストール・アンインストールを繰り返したことだと思います。
またはSequel Proのタブを閉じ、再び起動すると毎回のごとく「アプリが予期せぬ終了の仕方をしました」のような文が表示されていたことも原因の一つかなと思います。

まとめ

エラーを解決するときにターミナルに打ち込んだコマンドが、思わぬエラーを引き起こすことがあるかもしれないので、エラー解決は慎重に行う必要があるなと感じました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MacBookの環境 mysql5.6からmysql8.0に更新

やったこと

どこかで、rails6 色々変わりすぎてヤバイ!笑
っていう話を耳にして、そういえば開発環境に関してはスクールから言われるままに特定のバージョンを入れただけだな〜と思い確認すると案の定、古い安定バージョンを入れていた。自分は金がかからない限りは無駄に冒険してしまうところがあるので、Rails、Ruby、Mysqlをバージョンアップさせようと思いついてしまった。

ちなみにちなみに、自分は少数派のキチンとバックアップタイプですが、timemachineで外付けHDDにバックアップがある為、いつでも戻れる!という安心感の中でやりました。

新旧バージョン

app
Ruby 2.5.1 2.6.5
Rails 5.2.3 6.0.2.1
Mysql 5.6 8.0

※Rubyに関しては、最新2.7.0にしてしまうと、対応しているgemが少なくなってしまう為開発に甚大なダメージが・・・ということで、その前のバージョンで我慢しておく事にした。

RubyとRails

Homebrewをアップデートして、

  1. 最新バージョンをダウンロードしてきて、
  2. 最新バージョンをインストールして、
  3. 最新バージョンをデフォルト指定した。

Railsは旧バージョンをアンインストールしたかもしれない。Rubyはインストールしたバージョンを残しておけるみたい(brew??)。

実行したコマンドは忘れた。けど大して苦労はしてないハズ。

Rubyだけ、最新2.7.0にした時に既存アプリをrails startした時にエラーがいっぱい出てきて、それらのエラーはgemが未対応な事によるエラーだよ、っていう記事を見つけて考え直して2.6.5を入れたぐらい。

時刻設定

色々やって手順が前後する(Mysqlの設定にも関わる)が、まずRailsからMysql使ってた時に自動保存される時刻情報が無茶ずれてる(UTC時刻になってる)事が気に入らなかった。これに関してはRailsアプリを使っている時にRailsのプログラム内で日本時間に直すようなことをやっていたが、結局のところMysql自体にはUTC時間のまま保存されていたので、それを分かりやすく日本時間にしたかった。

デスクトップから右上に見える時刻表示(正常に日本時間表示)を気にしながら、コマンドラインでDateコマンドを打ってみると、なぜかUTC時刻になっていた。ひょっとしたらMacBookPro2017のデフォルトではJSTになっていたのかもしれないが、色々触りまくったので定かではない・・・

ということで、まずはシステム時間の修正から

システム時間(OS)

色々と調べた結果、システム時間の設定は /etc/localtime のバイナリファイルらしい。
更に、日本時間他各国のtimezone設定は /usr/share/zoneinfo/ にバイナリファイルがあり、日本時間の設定は /usr/share/zoneinfo/Japan のバイナリファイルらしい。

色々調べてたら、 /usr/share/zoneinfo/Asia/Tokyo っていう情報がいっぱい出てきたので必死にAsiaフォルダの中を探してたヨ。

$ sudo ln -s /usr/share/zoneinfo/Japan /etc/localtime
でdateコマンドがJSTで表示されるようになる。
※一般的にこういう操作する時は、 /etc/localtimeのバイナリファイルをバックアップとっておくらしい。自分はtimemachineでシステムバックアップとってるので気にしなかった。 

んで、あ〜安心と油断してたらデスクトップ右上の時間がこれまたメチャずれてた。なんでやねん、と思いながら "日付と時刻"環境設定を開く から時刻修正。

日付と時刻は、「日付と時刻を自動的に設定」にチェックを入れて、appleアジア(time.asia.apple.com)を選択。
時間帯は、「現在の位置情報に基づいて、時間帯を自動的に設定」のチェックを外してエリア選択で「日本」を設定した。

これで直ればいいが、すぐに時刻が設定されなかったので、なんとなくMACを再起動。
なんとか、デスクトップ右上の時刻も正常になった。

Mysql

時刻設定した後に、mysqlの時刻設定を見てみたらキチンと日本時間が適用されていた。

mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | JST    |
| time_zone        | SYSTEM |
+------------------+--------+
2 rows in set (0.02 sec)

Mysqlはバージョン共存する方法もあるらしいが、自分は旧の方はアンインストールした。

順に
旧をバックアップ、
旧をアンインストール、
(一応)再起動、
新をインストール、
my.cnf設定、
バックアップをリストア

バックアップ(エクスポート)

※後述するが、Mysql8.0に移行させる為にこの時のバックアップファイル(.sql)を編集するので、mysqldumpコマンドのオプションでなんとかできるならば、その方が楽。

$ mysqldump --single-transaction -u root -p -x --all-databases > 出力ファイル名

でいけるハズだけど、一時期うまく実行できなかった。
どういうコマンドで見たのか覚えていないが、データベースのプロパティをみる方法があり、--all-databases がFALSEになっていた。原因はよくわからないが、どこかの時点から --all-databasesができるようになっていた。よく分からん。

とりあえず、コマンド実行後に何も表示されないので、ちゃんと中身にクエリが入っているかは見ておいた方がいい

旧をアンインストール

単純な話、 brew uninstall mysql@5.6 を実行すればいいがゴミが残ってしまった事で何度もインストールを繰り返したので、きちっときれいにした方がいい。

$ brew uninstall mysql@5.6

どうしよう!困った時のMac上のMySQLのアンインストール&再インストール、動作確認手順

これの「Community Editionを削除する」「brew で入れたものを削除する」は何度やったか分からんぐらいやった。内容的に、「Community Editionを削除する」はやらんでいいかもしれんが、一応。

更にまた一応、Macを再起動。

インストール

// homebrewをアップデート
$ brew update
// インストールできるmysqlのバージョン確認
$ brew infomysql
// インストール
$ brew install mysql

my.cnf設定

ファイルの場所は覚えられないのに、my.cnfの候補ディレクトリを探すコマンドだけ覚えた

$ mysql --help | grep my.cnf
                      order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf /usr/local/etc/my.cnf ~/.my.cnf 

この内、自分は /usr/local/etc/my.cnfを使った。なぜなら4か所の内、そこにだけデフォルトでファイルがあったから。

/usr/local/etc/my.cnf
# Default Homebrew MySQL server config
[mysqld]
# Only allow connections from localhost
bind-address = 127.0.0.1
mysqlx-bind-address = 127.0.0.1
character-set-server=utf8
default_authentication_plugin=mysql_native_password
skip-slave-start
log_timestamps=SYSTEM

mysqlx-bind-address = 127.0.0.1
まではデフォルトで入力されてるので触らないようにする。

character-set-server=utf8
mysqlで日本語入力を可能にする

default_authentication_plugin=mysql_native_password
Mysql8.0からユーザー認証方法のデフォルトがcaching_sha2_passwordになってるらしい。これをやっておかないと多分うまくインポートできないし、Railsなんかに影響出そう。

skip-slave-start
なんかMysqlのログにエラー表示されてたので入れたが、結局ログにはエラーが残り続けてるのでよく分からない。入れなくてもいいかもしれない。Mysqlのバックアップをとる設定らしい。それを無視する。

log_timestamps=SYSTEM
Mysqlに保存されるログの時刻がこれまたUTCになっていたので日本時間にする為の設定。ちなみにログファイルは、/usr/local/var/mysql/マシン名.local.err にある。

インポートの前にユーザーの認証方式を変更

MySQL8系のDB接続エラーを解決する

ここを参考に、pluginの部分を全部mysql_native_passwordに。
ひょっとするとrootだけでいいかもしれない。

変え終わった後に他のコマンドを打とうとすると、確か警告が出てきてた。パスワードを設定しなさい、という。一旦適当なパスワードを設定して他のコマンドを実行できることを確認した上で、またパスワード無しを設定したが、いきなりパスワード無しでもいいかもしれない。

MySQL8でユーザーのパスワードの変更 / リセット方法

mysql> ALTER USER 'root'@'localhost' identified BY 'hoge';
mysql> ALTER USER 'root'@'localhost' identified BY '';

インポートの前にファイル修正

エクスポートの段階でとったバックアップファイルを三段階で修正(部分削除)した。
vi操作を調べとかないと厳しい。特に行削除操作。

viの基本操作

innodbに関する部分を削除

どこを見たのだったか忘れてしまった。。。これかな?
AWS Auroraでダンプしたデータをmysqlにインポートしようとしたらはまった

$ vi 保存したログファイル名.sql

削除した部分は、
-- Table structure for table `innodb_index_stats`
-- Dumping data for table `innodb_index_stats`
-- Table structure for table `innodb_table_stats`
-- Dumping data for table `innodb_table_stats`
の部分。

columns_privに関する部分を削除

これがさっきのページの情報だったか・・・
AWS Auroraでダンプしたデータをmysqlにインポートしようとしたらはまった

削除した部分は
-- Table structure for table `columns_priv`
-- Dumping data for table `columns_priv`
の部分。

mysqlデータベースのuserテーブルに関する部分を削除

これのヒントは、ユーザー認証の部分を説明してくれてたページ。

MySQL8系のDB接続エラーを解決する

削除した部分は
-- Table structure for table `user`
-- Dumping data for table `user`

バックアップデータの修正は以上。

:w 一応別名で保存.sql
:q!

バックアップをインポート

さっき保存したファイルを読み込み

$ mysql -uroot < 一応別名で保存.sql

これで、最新バージョンが使えるハズだけど、railsアプリを起動して問題なくMysqlが動くか確認しておくと安心。

Sequel Proが・・・

どういうわけか、Mysql8.0ではSequel Proが使えなくなるのでテストビルド版をインストールしないといけない・・・

MySQL8.0.x に Sequel Pro で接続する

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Macのhomebrewでmysqlクライアントのみインストールする

Macのローカルに作った開発環境のmysqlに接続はしたいけどサーバーはインストールしたくなかったのでメモ

homebrewの確認

homebrewはインストール済みであることが前提です

$ brew -v
Homebrew 2.2.2
Homebrew/homebrew-core (git revision fdb53; last commit 2020-01-03)
Homebrew/homebrew-cask (git revision d9c8; last commit 2020-01-03)

mysql確認

$ mysql --version
-bash: mysql: command not found

入ってません。

インストール

brew install mysql --client-only
...
Error: invalid option: --client-only

あれ、エラーになってしまうようですね。どうやらこのコマンドだと私の環境ではインストールできないようです。

以下のコマンドでインストール出来ました。

brew install mysql-client

インストールできました。

...
######################################################################## 100.0%
==> Pouring mysql-client-8.0.18.high_sierra.bottle.tar.gz
==> Caveats
mysql-client is keg-only, which means it was not symlinked into /usr/local,
because it conflicts with mysql (which contains client libraries).

If you need to have mysql-client first in your PATH run:
  echo 'export PATH="/usr/local/opt/mysql-client/bin:$PATH"' >> ~/.bash_profile

For compilers to find mysql-client you may need to set:
  export LDFLAGS="-L/usr/local/opt/mysql-client/lib"
  export CPPFLAGS="-I/usr/local/opt/mysql-client/include"

パスを通す

ログにもありますが、パスを通さないと、「mysql」コマンドで呼び出せないようです。

$ mysql --version
-bash: mysql: command not found

以下のように.bash_profileに書き込んで、sourceコマンドで即時反映させればOKです。

$ echo 'export PATH="/usr/local/opt/mysql-client/bin:$PATH"' >> ~/.bash_profile
$ source ~/.bash_profile

確認

$ mysql --version
mysql  Ver 8.0.18 for osx10.13 on x86_64 (Homebrew)

おつかれさまでした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MySQL Access denied for user 'root'@'localhost' の対応

MySQLでエラーが出てハマったのでその対応。

まずは権限なしで立ち上げられるように設定

$ mysqld_safe --skip-grant-tables &
[1] 11541
2020-02-11T04:59:48.6NZ mysqld_safe Logging to '/usr/local/var/mysql/***
2020-02-11T04:59:48.6NZ mysqld_safe Starting mysqld daemon with databases from /usr/local/var/mysql

MySQLにログイン

$ mysql -u root

root@localhost のユーザーを一旦削除してから作り直し、全ての権限を与える。

mysql> DROP USER root@localhost;
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE USER 'root'@'localhost' IDENTIFIED BY 'password';
Query OK, 0 rows affected (0.01 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost';
Query OK, 0 rows affected (0.00 sec)

その後、下記コマンドを打つとパスワードを求められるので、パスワードを入れてログインできればOK!

$ mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker-composeでLaravel環境構築

はじめに

dockerによってLaravelの環境構築を行います。laradockは使いません。
以前はlaradockを使っていましたが、
・プロジェクトが必要以上に大きくなる
・dockerの知識がほとんどなくても環境構築できでしまう
これらの点からlaradockを使わない方法を試していきます。

laradockはとりあえずdockerでLaravelを立ち上げたい方、知識が全くない方は使うとよいかもしれません。

以前にlaradockによるlaravelの環境構築の記事を書きましたので、laradockを使いたい方はこちらを→https://qiita.com/rope19181/items/da31dc2cd6097315fa10

環境・仕様

・nginx上でPHP実行環境を構築し、Laravel新規プロジェクト作成。
・mysqlとwebGUIとしてphpmyadminも使えるようにします。

環境、仕様は以下の通りです。
Docker version 19.03.5
docker-compose version 1.24.1
php 7.2-fpm
mysql 5.7

構成

最終的にこのような構成となります。

project
├ docker
│  ├ db
│  │ ├ data
│  │ ├ my.conf
│  │ └ sql
│  │
│  ├ nginx
│  │  └ default.conf
│  │  
│  └ php
│   ├ Dockerfile
│   └ php.ini  
├ myapp
└ docker-compose.yml

今回はprojectをルートディレクトリとしています。

./myappはlaravelのプロジェクトを置くディレクトリとなります。

docker-compose.ymlの作成

docker-composeでは複数のコンテナを管理、構築するためにdocker-compose.ymlに各コンテナの環境設定を定義します。

docker-compose.yml
version: '3'

services:
  php:
    container_name: php
    build: ./docker/php
    volumes:
      - ./myapp/:/var/www

  nginx:
    image: nginx
    container_name: nginx
    ports:
    - 80:80
    volumes:
    - ./myapp/:/var/www
    - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
    - php

  db:
    image: mysql:5.7
    container_name: db-host
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: database
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
    - ./docker/db/data:/var/lib/mysql
    - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
    - ./docker/db/sql:/docker-entrypoint-initdb.d
    ports:
    - 3306:3306

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: phpmyadmin
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOST=db-host
      - PMA_USER=docker
      - PMA_PASSWORD=docker
    links:
      - db
    ports:
      - 8080:80
    volumes:
      - /sessions

各項目について簡単に説明します。
詳しくは公式リファレンスを見てみましょう。https://docs.docker.com/compose/compose-file/

image

ローカルやリモートにあるイメージを指定します。ローカルにない場合リモートからpullされます。

今回はnginx、mysql、phpmyadminはローカルのイメージを指定しています。

build

イメージをbuildする際に参照するファイルを指定します。
要はイメージを構築する場合はこちらを使うわけです。またbuildとimageを両方指定することはできません。

今回はphpコンテナの構築でDockerfileを使うため、そのディレクトリのパスを指定しています。

volumes

ボリュームとしてマウントするパスを指定します。ホスト:コンテナまたアクセスモードを読み取り専用する場合ホスト:コンテナ:roとします。

今回はアクセスモードを指定しないためrwとなり、書き込みもできるボリュームです。

ports

公開(expose)するポートをします。ホスト:コンテナとします。

ポートが被る場合はここを変更します。

links

コンテナにリンクさせるサービス名を指定します。
注)コンテナ名(container_name)ではなくサービス名

今回はphpmyadminのコンテナにてdb-hostコンテナのサービス名であるdbを指定しています。

phpのDockerfileの作成

phpコンテナではLaravelの実行のためにcomposerのインストールします。
公式(https://getcomposer.org/download/) から下の部分を#Composer installのところに貼り付けます。

スクリーンショット 2020-02-10 18.55.21.png

Dockerfile
FROM php:7.2-fpm
COPY php.ini /usr/local/etc/php/

RUN apt-get update \
  && apt-get install -y zlib1g-dev mariadb-client \
  && docker-php-ext-install zip pdo_mysql

#Composer install
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php -r "if (hash_file('sha384', 'composer-setup.php') === 'c5b9b6d368201a9db6f74e2611495f369991b72d9c8cbd3ffbc63edff210eb73d46ffbfce88669ad33695ef77dc76976') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer

ENV COMPOSER_ALLOW_SUPERUSER 1

ENV COMPOSER_HOME /composer

ENV PATH $PATH:/composer/vendor/bin


WORKDIR /var/www

RUN composer global require "laravel/installer"

PHP設定ファイルの作成

docker/php/にphp.iniを作成します。

php.ini
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

nginxの設定ファイルの作成

docker/nginxにdefault.confを作成します。

default.conf
server {
  listen 80;
    index index.php index.html;
    root /var/www/public;

  location / {
    root /var/www/public;
    index  index.html index.php;
    }

  location ~ \.php$ {

    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass php:9000;
    fastcgi_index index.php;
    include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
  }
 }

dockerの起動

下記コマンドでdockerを起動させます。初回は結構時間がかかります。
docker-composeではupによってイメージの構築、コンテナの起動を行いますが、初回はキャッシュがないため--buildをつけます。-dオプションによってバックグラウンドで起動させます。

$ docker-compose up -d --build

laravelプロジェクトの作成

まずはphpコンテナに入ります。コンテナに入る場合はexecコマンドを実行します。

$ docker-compose exec php bash

laravelの新規プロジェクトを作成します。

composer create-project --prefer-dist "laravel/laravel myapp

laravelプロジェクトの環境設定

laravelプロジェクト内の.envやconfig/detabase.phpのデータベースの設定を変更します。
DB名、ユーザ名、パスワードなどを先ほどdocker-compose.ymlに設定した値に変更しましょう。

動作確認

nginx、php

http://localhost にアクセスしlaravelのホームページが表示されればOK。

スクリーンショット 2020-02-11 00.24.57.png

mysql、phpmyadmin

phpコンテナに入り、migrateします。

$ docker-compose exec php bash

$ php artisan migrate

http://localhost:8080 にアクセスし、phpmyadminが立ち上がりDB内に2つのテーブルが作成されていれば成功。

スクリーンショット 2020-02-11 00.23.37.png

最後に

laradockも簡単にできますが、少しの知識があればこちらの方法のほうがシンプルで分かりやすいと思います。

laradockを使いたい方はこちら→https://qiita.com/rope19181/items/da31dc2cd6097315fa10

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

dockerでLaravel環境構築

はじめに

dockerによってLaravelの環境構築を行います。できるだけシンプルな構成を目指します。laradockは使いません。

自分は以前laradockを使っていましたが、
・プロジェクトが必要以上に大きくなる
・dockerの知識がほとんどなくても環境構築できでしまう
これらの点からlaradockを使わない方法を試していきます。

laradockはとりあえずdockerでLaravelを立ち上げたい方、知識が全くない方は使うとよいかもしれません。

以前にlaradockによるlaravelの環境構築の記事を書きましたので、laradockを使いたい方はこちらを→https://qiita.com/rope19181/items/da31dc2cd6097315fa10

環境・仕様

・nginx上でPHP実行環境を構築し、Laravel新規プロジェクト作成。
・mysqlとwebGUIとしてphpmyadminも使えるようにします。

・環境、仕様は以下の通りです。
Docker version 19.03.5
docker-compose version 1.24.1
php 7.2-fpm
mysql 5.7

構成

最終的にこのような構成となります。

project
├ docker
│  ├ db
│  │ ├ data
│  │ ├ my.conf
│  │ └ sql
│  │
│  ├ nginx
│  │  └ default.conf
│  │  
│  └ php
│   ├ Dockerfile
│   └ php.ini  
├ myapp
└ docker-compose.yml

今回はprojectをルートディレクトリとしています。

./myappはlaravelのプロジェクトを置くディレクトリとなります。

docker-compose.ymlの作成

docker-composeでは複数のコンテナを管理、構築するためにdocker-compose.ymlに各コンテナの環境設定を定義します。

docker-compose.yml
version: '3'

services:
  php:
    container_name: php
    build: ./docker/php
    volumes:
      - ./myapp/:/var/www

  nginx:
    image: nginx
    container_name: nginx
    ports:
    - 80:80
    volumes:
    - ./myapp/:/var/www
    - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
    - php

  db:
    image: mysql:5.7
    container_name: db-host
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: database
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
    - ./docker/db/data:/var/lib/mysql
    - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
    - ./docker/db/sql:/docker-entrypoint-initdb.d
    ports:
    - 3306:3306

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: phpmyadmin
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOST=db-host
      - PMA_USER=docker
      - PMA_PASSWORD=docker
    links:
      - db
    ports:
      - 8080:80
    volumes:
      - /sessions

各項目について簡単に説明します。
詳しくは公式リファレンスを見てみましょう。https://docs.docker.com/compose/compose-file/

image

ローカルやリモートにあるイメージを指定します。ローカルにない場合リモートからpullされます。

今回はnginx、mysql、phpmyadminはリモートのイメージを指定しています。

build

イメージをbuildする際に参照するファイルを指定します。
要はイメージを構築する場合はこちらを使うわけです。またbuildとimageを両方指定することはできません。

今回はphpコンテナの構築でDockerfileを使うため、そのディレクトリのパスを指定しています。

volumes

ボリュームとしてマウントするパスを指定します。ホスト:コンテナまたアクセスモードを読み取り専用する場合ホスト:コンテナ:roとします。

今回はアクセスモードを指定しないためrwとなり、書き込みもできるボリュームです。

ports

公開(expose)するポートをします。ホスト:コンテナとします。

ポートが被る場合はここを変更します。

links

コンテナにリンクさせるサービス名を指定します。
注)コンテナ名(container_name)ではなくサービス名

今回はphpmyadminのコンテナにてdb-hostコンテナのサービス名であるdbを指定しています。

phpのDockerfileの作成

phpコンテナではLaravelの実行のためにcomposerのインストールします。
公式(https://getcomposer.org/download/) から下の部分を#Composer installのところに貼り付けます。

スクリーンショット 2020-02-10 18.55.21.png

Dockerfile
FROM php:7.2-fpm
COPY php.ini /usr/local/etc/php/

RUN apt-get update \
  && apt-get install -y zlib1g-dev mariadb-client \
  && docker-php-ext-install zip pdo_mysql

#Composer install
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php -r "if (hash_file('sha384', 'composer-setup.php') === 'c5b9b6d368201a9db6f74e2611495f369991b72d9c8cbd3ffbc63edff210eb73d46ffbfce88669ad33695ef77dc76976') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer

ENV COMPOSER_ALLOW_SUPERUSER 1

ENV COMPOSER_HOME /composer

ENV PATH $PATH:/composer/vendor/bin


WORKDIR /var/www

RUN composer global require "laravel/installer"

PHP設定ファイルの作成

docker/php/にphp.iniを作成します。

php.ini
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

nginxの設定ファイルの作成

docker/nginxにdefault.confを作成します。

default.conf
server {
  listen 80;
    index index.php index.html;
    root /var/www/public;

  location / {
    root /var/www/public;
    index  index.html index.php;
    }

  location ~ \.php$ {

    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass php:9000;
    fastcgi_index index.php;
    include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
  }
 }

dockerの起動

下記コマンドでdockerを起動させます。初回は結構時間がかかります。
docker-composeではupによってイメージの構築、コンテナの起動を行いますが、初回はキャッシュがないため--buildをつけます。-dオプションによってバックグラウンドで起動させます。

$ docker-compose up -d --build

laravelプロジェクトの作成

まずはphpコンテナに入ります。コンテナに入る場合はexecコマンドを実行します。

$ docker-compose exec php bash

laravelの新規プロジェクトを作成します。

composer create-project --prefer-dist "laravel/laravel myapp

laravelプロジェクトの環境設定

laravelプロジェクト内の.envやconfig/detabase.phpのデータベースの設定を変更します。
DB名、ユーザ名、パスワードなどを先ほどdocker-compose.ymlに設定した値に変更しましょう。

動作確認

nginx、php

http://localhost にアクセスしlaravelのホームページが表示されればOK。

スクリーンショット 2020-02-11 00.24.57.png

mysql、phpmyadmin

phpコンテナに入り、migrateします。

$ docker-compose exec php bash

$ php artisan migrate

http://localhost:8080 にアクセスし、phpmyadminが立ち上がりDB内に2つのテーブルが作成されていれば成功。

スクリーンショット 2020-02-11 00.23.37.png

docker-composeコマンド小まとめ

よく使うものをまとめます。

up

コンテナの構築、起動をします。

似たものとしてイメージの構築のみを行うbuild、コンテナの起動のみを行うstartなどがありますが、docker-composeではとりあえずupをしとけばいいと思います。
Dockerfileを更新した時などはbuildしましょう。

$ docker-compose up -d  
$ docker-compose up -d --build #初回の起動などbuildもしたいとき

down

upで作られたものを削除します。downだけだとコンテナとネットワークの削除を行います。オプションによってその範囲を指定します。

$ docker-compose down

コンテナ、イメージ、ボリュームそしてネットワークすべてを削除したい場合は

$ docker-compose down --rmi all --volumes

exec

起動中のコンテナでコマンドを実行

$ docker-compose exec コンテナ名 実行するコマンド

$ docker-compose exec コンテナ名 bash #コンテナに入る場合

最後に

laradockも簡単にできますが、少しの知識があればこちらの方法のほうがシンプルで分かりやすいと思います。

laradockを使いたい方はこちら→https://qiita.com/rope19181/items/da31dc2cd6097315fa10

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Knexあれこれ(雑多メモ)

はじめに(次の見出しまで飛ばしてOK)

最近仕事に対する楽しみ方を意識するようになり、今のつまらない仕事が続くのも嫌だったので、6月で辞めますと退職連絡を済ませてきた。
コーディングしてる最中はプライベートでも仕事でも楽しいので、コードをびっしり書くような会社に転職したいと思ったが、個人での活動実績はない。
とりあえず就活に繋がる作品を何か作ってみようと思い立ちこれ1本で大体何とか済ませちゃうNode.jsの勉強を1週間前に始めた。
が、DB処理があまり好きになれなかった。

適当に買った参考書に書いてたDB処理は以下のようなもの

sql.js
connection.query('SELECT * FROM hoge ', function (error, results, fields) { //取得結果に対する処理 });

新卒配属された闇プロジェクトのシステム構成がこれに近い形式で実装されていたことが大体の原因ではあるが。

便利なnpmパッケージ Knex

PHP/Laravelあたりに言語/フレームワークを変更しようかなとこっそり考えつつ、何かいいnpmパッケージはないものかと探してみた。
あった(Knex公式)
記事を書いてくれている方もいた

個人的に良いなと思った点

  • チェーン形式で処理を書ける
  • マイグレーションにも対応してる

軽く記事を流し読みるするだけでも結構便利に思えたのでリファレンス読みつつ色々試してみた。
で、ちょっと一々リファレンスを見に行くのもあれなのでちょっとメモを残そうと思いこの記事を書き始めた。正直公式リファレンスのは読みづらかった
割と参考記事とかぶってる点が多いので、多分knex回りを調べてこの記事を開いてくれた方は↑の参考記事を見ることをお勧めします。

マイグレーションのあれこれメモ(本題)

実行前準備

初期構築 マイグレーションをするためのアレコレの準備

$ knex init 

マイグレーション実行に当たる必要となる設定

module.exports = {
  // 開発環境の設定(デフォルトで参照される設定 NODE_ENVを書き換えればデフォルトではなくなる)
  development: {
    // データベースの種類
    client: 'mysql', 

    // DB接続設定
    connection: {
      host     : '127.0.0.1',
      user     : 'root',
      password : '',
      database : 'node_app'
    },
    // コネクションプールの設定
    pool: {
      min: 2,
      max: 10
    },
    // マイグレーション設定
    migrations: {
      // マイグレーションファイルの配置先(knexfile.jsからの相対)
      directory:'./db/migrations',
      // マイグレーションを管理するテーブル名 (マイグレーションの実行と同時にDBに作成される)
      tableName: 'knex_migrations'
    }
  },
  // 開発環境とは異なる環境のマイグレーション実行設定定義 (本番環境,検証環境の差別化等)
  staging: { ... },
  production: { ... },
};

マイグレーションファイルの作成

<タイムスタンプ>_<ファイル名>.jsというファイルが、migrations.directoryで設定したパス配下に配置される

$ knex migrate:make <ファイル名>

マイグレーションファイルの中身の設定

細かく解説すると助長になるので、コメント参照

20200208161057_items.js
// 後述する実行コマンドで呼び出されるメソッド
exports.up = function(knex, Promise) {
  // connection.databaseで設定しているスキーマに引数で渡したテーブルがあるかチェック
  return knex.schema.hasTable('テーブル名')
    // hasTableのチェーンメソッド 判定結果を引数existsに渡して無名関数をコールバック
    .then(function(exists) {
      if (!exists) {
           // 接続先のスキーマに指定した名前でテーブルを作成する
          return knex.schema.createTable('テーブル名', 
            // 作成したテーブルにカラムを作成する
            function(table) {
               // テーブルの要素設定 別途記載
              table.increments('id').primary();
              table.string('name', 100);
              table.integer('price');
          });
      }else{
          return new Error("The table already exists. 2");
      }
  });
};

// 後述する切り戻しコマンドで呼び出されるメソッド
exports.down = function(knex, Promise) {
  return knex.schema.hasTable('items').then(function(exists) {
      if (exists) {
          // 指定したテーブルを削除する
          return knex.schema.dropTable('items');
      }
  });
};

接続先データベース/スキーマに対して実行するメソッド各種 (使いそうな奴だけ)

function(knex, Promise) {
    // テーブル作成メソッド コールバック内でカラム設定を忘れずに
    knex.schema.createTable(tableName, callback)

    // 指定したテーブル名を変更する
    knex.schema.renameTable(from, to)

    // 指定したテーブルを削除する           
    knex.schema.dropTable(tableName)

    // 指定したテーブルが存在しないか確認する 上例のように.then()でチェーンするとスマート
    knex.schema.hasTable(tableName)

    // 指定したテーブルが存在すれば、そのテーブルを削除する. has,dropをチェーンしなくて済む
    knex.schema.dropTableIfExists(tableName)

    // 指定したテーブルに関する変更処理を実行する
    knex.schema.table(tableName, callback)
};

接続先のデータベース/スキーマが持つテーブルに対して実行するメソッド各種

createTableや、table関数のコールバック内で利用する

knex.schema.createTable('posts', function(table) {
    // 指定したカラムを削除する
    table.dropColumn(name)

    // 指定した複数のカラムを削除
    table.dropColumns(*columns)

    // 指定したカラム名を変更
    table.renameColumn(from, to)

    // オートインクリメント形式のカラムを追加
    table.increments(name)

    // 文字列型のカラムを追加 オプション引数で長さも指定できる
    table.string(name, [length])

    // 数値型のカラムを追加
    table.integer(name)
});

主キーとか外部キーとかindexとかの使い方

カラム設定の関数にチェーンする

knex.schema.createTable('posts', function(table) {
    // 主キーの設定
    table.increments(name).primary()

    // knexインスタンスがMySQLとPostgreSQLの場合のみ使える
    table.index(columns, [indexName], [indexType])

    // 外部キーの設定 table.foreign(カラム名).references('参照テーブル.カラム名')
    table.string(name)
    table.foreign(name).references(table.name) 
});

実行手順

未実行のマイグレーションファイルのupメソッドを、タイムスタンプの古い順に全ファイル実行

$ knex migrate:latest

envオプション: 実行対象の環境を指定してマイグレーションを実行する

$ knex migrate:latest --env production

直前に実行した全てのマイグレーションファイルのdownメソッドを、タイムスタンプの新しい順に実行する

Latestでバッチ実行したなら、すべてのファイルをタイムスタンプの新しい順に実行する。
Upで個別実行したなら、そのマイグレーションファイルのみを実行する

$ knex migrate:rollback

allオプション:過去に実行した全てのマイグレーションファイルのdownメソッドを実行する

$ knex migrate:rollback --all

タイムスタンプが最も古い未実行のマイグレーションファイルのUpメソッドを実行する

$ knex migrate:up 

マイグレーションファイルを指定してそのUpメソッドを実行する

$ knex migrate:up <ファイル名>.js

タイムスタンプが最も新しい実行済のマイグレーションファイルのdownメソッドを実行する

$ knex migrate:down

マイグレーションファイルを指定してそのdownメソッドを実行する

$ knex migrate:down <ファイル名>.js

マイグレーションファイルを一覧表示する

実行済みのものと未実行のものに分割してリスト表示してくれる

$ knex migrate:list
Using environment: development
Found 1 Completed Migration file/files.
20200208145923_items.js 
Found 1 Pending Migration file/files.
20200208161057_items.js 

作成日の異なるマイグレーションファイルがある場合のmigrate:latestの挙動

タイムスタンプの古い方から実行される

/project
|--migration
|  |--20200208161057_items.js
|  |--20200208161542_items.js
20200208161057_items.js
exports.up = function(knex, Promise) {
  console.log('items oldest');
}
20200208161542_items.js
exports.up = function(knex, Promise) {
  console.log('items lastest');
}
実行結果
$ knex migrate:latest
Using environment: development
items oldest
items latest

作成日の異なるマイグレーションファイルがある場合のmigrate:rollbackの挙動

タイムスタンプの新しい方から実行される

/project
|--migration
|  |--20200208161057_items.js
|  |--20200208161542_items.js
20200208161057_items.js
exports.up = function(knex, Promise) {
  console.log('items oldest');
}
20200208161542_items.js
exports.up = function(knex, Promise) {
  console.log('items lastest');
}
実行結果
$ knex migrate:rollback
Using environment: development
items latest
items oldest

オプション引数類は一例で上げてるだけになります。詳細は公式へ

migrate:latestの後にもう1回migrate:latestをした場合のmigrate:rollbackの挙動

上述した通り、migrate:rollback は直前の1回の実行を戻す
2回に分けた場合は2回実行するか、--allオプション を使う

ぼやき

結構前からあるパッケージなのにknexの日本語記事少ないってことは、
割とNode.jsを書いてる人からは不人気なのだろうか。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WindowsでグローバルIPアドレスを確認する方法

確認したい理由

Azure で Azure Database for MySQL を立てたのだが、接続するためにファイアウォール規制に許可サービスとして自IPアドレスを登録する必要があった。

環境

Windows10 Home
XAMPP 7.3.11
Azure Database for MySQL 5.7

ipconfig /all ではわからない

ipconfig /all 叩けばわかるだろうと思ったのだが、載っていなかった。

Webサービスで調べる

以下のサイトで調べる。アクセスすれば載っている。
アクセス情報【使用中のIPアドレス確認】
https://www.cman.jp/network/support/go_access.cgi

結果

無事にわかり接続できた

余談

ちなみにコマンドラインからMySQLで接続しようとしたら、、、

C:\xampp\mysql\bin>mysql --host mysql-hogehoge.mysql.database.azure.com --user hogehoge@mysql-hogehoge -p
Enter password: ********

あなたのグローバルIPは許可されてないよ!と出るのでこれでもわかる。

ERROR 9000 (HY000): Client with IP address 'xxx.xxx.xxx.xxx' is not allowed to connect to this MySQL server.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む