- 投稿日:2020-03-10T22:56:39+09:00
【MySQL】Geometry型で位置情報を扱う
はじめに
MySQL8.0では位置情報に関する機能が充実した...という情報を見かけたので、試しにGeometry型というデータ型を使って、位置情報を格納するテーブルを作ってみることにしました。
※GIS関連は全く詳しくないので、誤りがありましたらご指摘頂けると幸いです。
使用した環境
- OS
- CentOS7.7(1908)
- RDBMS
- MySQL8.0.19
テーブルの作成
- 駅の位置を表す
stationというテーブルをnkojimaデータベース内に作成しました。- 位置情報は
locationというGeometry型のカラムに持たせています。- 位置情報を表すデータ型はGeometry以外にも幾つか用意されており、以下に示したものは「OpenGIS クラスに対応するデータ型」となっています。
- POINT:地点を表す。
- LINESTRING:地点間を直線で結んだ線分を表す。
- POLYGON:多辺の幾何図形を表す。
- GEOMETRY:POINT、LINESTRING、POLYGONのいずれにも対応するルートクラス。
テーブルの作成-- 駅情報テーブルの作成。 CREATE TABLE `nkojima`.`station` ( `id` INT AUTO_INCREMENT comment '駅ID', `name` VARCHAR(50) NOT NULL comment '駅名', `location` GEOMETRY NOT NULL comment '駅の座標', `note` VARCHAR(200) comment '備考', PRIMARY KEY (id), INDEX name_idx(name) ) ENGINE = InnoDB, default charset=utf8mb4 comment='駅情報';データの登録
- 都内のJRの駅から主要なものを選んで、大まかな座標を国土地理院の地図で取得しました。
- Geometry型として利用するにはSRID(空間参照系識別子)が必要になりますが、ここでは4326(WGS84)にセットしました。
- MySQL5.7では
GeomFromText関数が使われていましたが、MySQL8.0以降はGeomFromText関数は非推奨となっているため、ST_GeomFromTextを使うことになります。
GeomFromTextという名称はおそらく「Geometry From Text」の略で、「テキストからGeometry型に変換する」という処理がそのまま名称になっているのだと思われます。INSERT文USE nkojima; INSERT INTO station (name, location, note) VALUES ("東京", ST_GeomFromText('POINT(35.681300 139.767165)', 4326), "23区"), ("新橋", ST_GeomFromText('POINT(35.666471 139.758357)', 4326), "23区"), ("品川", ST_GeomFromText('POINT(35.628829 139.739141)', 4326), "23区"), ("大崎", ST_GeomFromText('POINT(35.619131 139.728563)', 4326), "23区"), ("渋谷", ST_GeomFromText('POINT(35.658177 139.701741)', 4326), "23区"), ("新宿", ST_GeomFromText('POINT(35.688803 139.700925)', 4326), "23区"), ("池袋", ST_GeomFromText('POINT(35.730114 139.711053)', 4326), "23区"), ("日暮里", ST_GeomFromText('POINT(35.728163 139.770598)', 4326), "23区"), ("上野", ST_GeomFromText('POINT(35.713756 139.776950)', 4326), "23区"), ("四ツ谷", ST_GeomFromText('POINT(35.684834 139.730204)', 4326), "23区"), ("三鷹", ST_GeomFromText('POINT(35.702727 139.560978)', 4326), "多摩地区"), ("立川", ST_GeomFromText('POINT(35.698170 139.413671)', 4326), "多摩地区"), ("八王子", ST_GeomFromText('POINT(35.655370 139.339921)', 4326), "多摩地区"), ("北千住", ST_GeomFromText('POINT(35.749612 139.805059)', 4326), "23区"), ("赤羽", ST_GeomFromText('POINT(35.777732 139.721031)', 4326), "23区"), ("蒲田", ST_GeomFromText('POINT(35.562491 139.715924)', 4326), "23区");データの検索
ST_AsText関数を使うことで、Geometry型のカラムを人が見て理解できる形式で取得できます。
ST_AsText関数を使わないと、Geometry型のカラムは16進数のデータとして表示されます。mysql> SELECT -> name AS 駅名, -> ST_AsText(location) AS 緯度経度 -> FROM station -> WHERE note='多摩地区'; +-----------+-----------------------------+ | 駅名 | 緯度経度 | +-----------+-----------------------------+ | 三鷹 | POINT(35.702727 139.560978) | | 立川 | POINT(35.69817 139.413671) | | 八王子 | POINT(35.65537 139.339921) | +-----------+-----------------------------+まとめ
- ここまでの内容だとGeometry型などのデータ型を使うメリットがほとんど感じられませんが、「地点間の距離を計測する」「最寄りの地点を調べる」などの処理で力を発揮してくれるそうです。
- この辺りについては次に投稿する記事で触れたいと思います。
参考URL
- 投稿日:2020-03-10T22:17:32+09:00
中間テーブルとは 〜DB設計〜
概要
アソシエーションの中で多対多の関係性で使われる中間テーブル。
今回、中間テーブルとは何か? 自分の復習用に記事を執筆しようと思います。
そもそもアソシエーションとは?
Railsで使われているテーブルとテーブルを関連づける機能。
例えば、TwitterではUserとtweetがあるとして、
二つはUserがtweetすることでtweetが生じる関連付いた関係性である。
アソシエーションを組まないとどうなるのか?
AさんがtweetしたtweetがAさんと関連づけされなくなる。
AさんのtweetもBさんのtweetも一緒くたに扱われるため、外部キーのIDを取得する必要が出てきます。
一対多、一対一の関係性
アソシエーションの中には一対多、一対一
最後に中間テーブルが使われる多対多の関係性が存在する。
一対多
最初に一対多とは親モデルが子モデルに対して多数の要素を持つこと。
Twitterの場合、一つのUser(親モデル)は沢山のtweet(子モデル)をします。
Userモデル(親モデル)
ID Username 1 tarou 2 jirou 3 saburou 4 sirou 5 gorou Tweetモデル(子モデル)
ID User_id text 1 1 あいうえお 1 1 たろうです 2 2 かきくけこ 3 3 さしすせそ 4 4 たちつてと 5 5 なにぬねの railsでUserモデル(親モデル)に
User.rbhas_many :tweethas_manyの記述を加えます。
Tweetモデル(子モデル)に
Tweet.rbbelongs_to :userbelongs_toの記述を加えます。
一対一
一対一は関連するモデルの立場が対等です。
Userモデル
ID Username 1 tarou 2 jirou 3 saburou 4 sirou 5 gorou Profileモデル
ID User_id text 1 1 よろしく 2 2 じろうです 3 3 さぶろうです 4 4 しろうです 5 5 ごろうです Userモデルに対するProfileといった具合に同等の関係を示す場合に使われます。
railsでUserモデル(親モデル)に
User.rbhas_one :profilehas_oneの記述を加えます。
Profileモデル(子モデル)に
Tweet.rbbelongs_to :userbelongs_toの記述を加えます。
中間テーブルとは?
二つのモデルが多対多の関係性の時に使われるモデル。
ChatアプリのDB設計をする際、UserモデルとGroupモデルがあるとします。
Userは複数のチャットGroupに属し、チャットGroupも複数のUserが所属している。
この場合、中間テーブルが必要になってきます。
なんで中間テーブルを使う必要があるの?
例えば、Userが1と3のChatグループに属していたとします。
中間テーブルを挟まない場合、Groupに所属することを示すカラムが2つ必要になります。
Userが1と2と3のChatグループに属していたら、3つのカラムが必要になります。
際限なくカラムが多くなってくるので、それを防ぐために中間テーブルが必要になります。
Memberモデル(中間テーブル)
ID User_id group_id 1 1 1 2 1 2 3 2 1 4 2 3 5 3 2 この様に中間テーブルを挟むことでカラムを増やす必要がなくなります。
User.rbhas_many :group, through: :membergroup.rbhas_many :user, through: :memberモデルファイルに以上の記述を行えば、多対多のアソシエーションが設定されます。
- 投稿日:2020-03-10T21:51:38+09:00
SQLのJOINが苦手という人に向けて
はじめに
この仕事に携わっていると、結構な経験者でもSQL、特にテーブル同士の結合が苦手という人によく会います。
で、話を聞くと苦手な理由はテーブル同士のリレーションを視覚的にイメージ出来ないことにあるのかと。。かつて自分もSQLは大の苦手でした。
2、3年目の時に某電力の大規模Javaプロジェクトに放り込まれました。
テーブル同士の多重度が多対多、オンラインPGで1SELECTあたり3000〜5000行という変態的なSQL。
MVCモデルが出始めの頃、Webフレームワークなんて言葉が流行り出す前
バックエンドからフロントエンドまで全てをベタ書き。
期日までに徹夜・休出しながら直したり書かないといけなかったものですから、それはもう大変な苦労と挫折を味わいました。そんな環境下でテーブル同士のリレーションを図に整理しながら、書いたり、手直ししたりする内に、視覚的にイメージ出来るようになり、SQLへの苦手意識はほとんど無くなりました。
「乗り越えた壁はいつしか自分を守る盾になる」と誰かが言ってたアレです(笑)
SQLが苦手な方向けの説明になってます。
ある程度のSQL経験者には退屈な内容になっておりますので、あしからず。3つのJOIN
INNER JOIN・LEFT (OUTER) JOIN・FULL (OUTER) JOINの3つのJOINについて説明します。※他にも
RIGHT (OUTER) JOIN、CROSS JOIN等があります。
ただし、RIGHT (OUTER) JOINはLEFT (OUTER) JOINをただ左右反転させたもの、CROSS JOINはよっぽど切羽詰まった状況使うか、使う時点で処理フローを変えることを検討した方が良い、どちらも実務で使うことは稀なので割愛します。INNER JOIN
説明するまでもありませんが、最も一般的でよく使われるJOINですね。
内部結合っていわれるやつです。
仮にAとBというテーブルをINNER JOINした場合の関係性をベン図に表すとこんな感じです。
「テーブルAにも存在し、かつ、テーブルBにも存在するレコードを取ってくる」とゆうJOINです。
真ん中の赤く重なり合ってるところをとります。
テーブルA・Bがこんな状態だったとします。
- テーブルA
PK_A VAL_A 001 AAA 002 BBB 004 CCC 005 DDD 007 EEE 009 FFF
- テーブルB
PK_B VAL_B 001 GGG 003 HHH 006 III 008 JJJ 009 KKK
PK_A・PK_Bがそれぞれの主キーです。
AのPK_AとBのPK_BでJOINします。SELECT PK_A, VAL_A, PK_B, VAL_B FROM A INNER JOIN B ON A.PK_A = B.PK_B結果は
PK_A VAL_A PK_B VAL_B 001 AAA 001 GGG 009 FFF 009 KKK ですね。
A・B両方に存在する001と009のみが抽出されます。LEFT OUTER JOIN
これもよく使われるJOINです。
左外部結合っていわれます。
たまにレガシーなところ行くといまだに(+)なんて記述もありますが、アレは古いOracleの方言です。
可読性・保守性が著しく低下するので間違っても(+)を記述するのはやめておきましょう。
また、OUTERは省略可能ですが、INNER JOINとの違いを明確にさせるために、あえて省略しないで説明します。ベン図に表すとこんな感じです。
「テーブルAの全てプラス、テーブルAと重なり合うテーブルBのレコードを取ってくる」とゆうJOINです。先ほどと同じように
AのPK_AとBのPK_BでJOINします。SELECT PK_A, VAL_A, PK_B, VAL_B FROM A LEFT OUTER JOIN B ON A.PK_A = B.PK_B結果は
PK_A VAL_A PK_B VAL_B 001 AAA 001 GGG 002 BBB null null 004 CCC null null 005 DDD null null 007 EEE null null 009 FFF 009 KKK
Aの全件と、Aのキーと一致するBが取得されていることがわかります。
Aのキーと一致しないBの歯抜けの部分についてはnullが埋め込まれていますね。FULL OUTER JOIN
完全外部結合と言われます。
実務で使われる頻度は少ないですが、覚えておいて損はないです。
AとBを重なり合う部分も含めて全件取ってきます。SELECT PK_A, VAL_A, PK_B, VAL_B FROM A FULL OUTER JOIN B ON A.PK_A = B.PK_B結果は
PK_A VAL_A PK_B VAL_B 001 AAA 001 GGG 002 BBB null null null null 003 HHH 004 CCC null null 005 DDD null null null null 006 III 007 EEE null null null null 008 JJJ 009 FFF 009 KKK
A・Bの全件が取得されていることがわかります。
そしてお互いの歯抜けの部分についてはnullが埋め込まれていますね。こんなんどうでしょう?
ここまでお読み頂き、JOINの視覚的なイメージが着いたでしょうか?
「
テーブルBと重なり合わないテーブルAのレコードを取ってくる」とゆうJOIN、、
もちろん、そんなJOINありません。ではどうすれば良いか?
SELECT PK_A, VAL_A, PK_B, VAL_B FROM A LEFT OUTER JOIN B ON A.PK_A = B.PK_B WHERE B.PK_B IS NULL
AとBをLEFT OUTER JOINさせてから、
WHERE句でBの主キーPK_BがNULLのレコードを指定しています。結果は
PK_A VAL_A PK_B VAL_B 002 BBB null null 004 CCC null null 005 DDD null null 007 EEE null null 歯抜けレコードを利用するのがポイントです。
前述のLEFT OUTER JOINの結果からBの歯抜けレコードを指定することで
A・B両方にある001・009のレコードが除外され、
Bと重なり合わないAのレコードを取得できます。これが「歯抜け」という文字をあえて太字にした理由です。
じゃあ、こんなのも
理屈が分かっちゃえば、こんなのも簡単ですね。
「重なり合わない部分のテーブルAとテーブルBのレコードを取ってくる」
同じように歯抜けレコードをうまく使いましょう。SELECT PK_A, VAL_A, PK_B, VAL_B FROM A FULL OUTER JOIN B ON A.PK_A = B.PK_B WHERE A.PK_A IS NULL OR B.PK_B IS NULL結果は
PK_A VAL_A PK_B VAL_B 002 BBB null null null null 003 HHH 004 CCC null null 005 DDD null null null null 006 III 007 EEE null null null null 008 JJJ 前述の
FULL OUTER JOINの結果からAまたはBの歯抜けレコードを指定することによって
A・B両方にある001・009のレコードが除外され、
お互い重なり合わないA・Bのレコードを取得できます。さいごに
最近主流のアーキテクチャでは(バッチ処理を除いて)複雑なクエリを書くのはアンチパターンです。
なので上記のようなクエリを組む事も稀かと思いますが、テーブル同士を比較してアンマッチリストを抽出したい時や、ゴミデータ・不正データを調査したい時などにJOINを使いこなせると色々と便利です。あと気をつけなくてならないのは
SELECT文はF・W・G・H・S・Oの順番に評価されます。
何かというとFROM・WHERE・GROUP BY・HAVING・SELECT・ORDER BYの頭文字です。
JOINはFROM句中で書くため、一番最初に評価されます。
なので大量データを保持したテーブル同士をJOINさせるとパフォーマンスの劣化に繋がったりします。
サブクエリやWITH句を使って比較に必要なデータに絞ってからJOINさせる等のパフォーマンスの考慮は必要です。ただし、最近は
Oracle・MySQLのオプティマイザによって実行計画が最適化されるので、トンチキなSQLを書いても大体は動いてくれます。
自分が走り出しの頃は変なSQL書いたら幾度となく先輩にブッ◯されそうになりました(笑)で、自分が言いたいのはテーブル同士のリレーションを視覚的にイメージできれば、どんなSQLがやって来ても怖くない、
何千行というSQLも結局はテーブルのJOINの組み合わせに過ぎないということです。最後までお読み頂きありがとうございました。
- 投稿日:2020-03-10T21:48:55+09:00
Amazon Linuxを利用している場合のMySQL
IT未経験のスクール生が学んだことをアウトプットします
データベース
データベースは沢山の情報が入っている箱のようなものです。この中には様々な種類のデータが入っていて、データを格納したり、取り出したりすることができます。
webアプリケーションフレームワークにとって、データベースは必ずセットになって必要だと言えます。
webアプリケーションに関連する全てのデータを保存しておく場所となるためです。
例えばTwitterでデータベースが無ければ、ユーザの情報も、ツイートの情報も保存しておくことができません。データベースの種類
・階層型データベース
・ネットワーク型データベース
・リレーショナルデータベースこの中で最も利用されるのが、リレーショナルデータベースです。
エクセルの表のような形式で情報を整理し、管理します。リレーショナルデータベースを管理する
ソフトウェアをリレーショナル・データ・ベース・マネジメント・システム(RDBMS)と呼びます。
そんなRDBMSの中でも代表的なものの一つが、MySQLです。MySQL
MySQLは、Oracle社が開発、提供しているRDBMSです。データベースの作成、編集、削除ができます。
オープンソースソフトウェアとして公開されており、誰でも無償で利用することができます。特徴
・拡張性と柔軟性が高い
MySQLは小さいアプリケーションから巨大なアプリケーションまで対応できるたく調整があります。
さらに、オリジナルの機能を追加するなど、自由なカスタマイズも可能になってます。・高い信頼性
24時間稼働するために多くの機能があります。
バックアップ機能やリカバリー機能など、大事なデータを守ることができます。・トランザクション
トランザクションとは、データに一貫性を持たせるために、一連の処理が完了するまでデータを変更しない機能。
途中でトラブルがあった場合は、データの相違が出ないようにするため、一連の処理を破棄します。
MySQLでは、このトランザクションをサポートする機能が多くあるので、完全にデータの一貫性を保つことが可能なのです。・強力なセキュリティ
データを確実に保護するために、セキュリティ機能が用意されています。
データベースへのアクセス制御や、安全な接続を保証する[SSH][SSL]といったセキュリティ技術をサポートします。MySQLのインストール
Amazon Linuxを利用している場合、MySQLは yum コマンドからインストールすることができます。
EC2インスタンスへログインしてください。*ターミナル(サーバ) [ec2-user@ip-172-31-25-189 ~]$ sudo yum -y install mysql56-server mysql56-devel mysql56MySQLの起動
MySQLを起動するために service コマンドを利用します。これは、Amazon LinuxやCentOSに含まれているもので、インストールしたソフトウェアの起動を一括して行えるツールです。
[ec2-user@ip-172-31-25-189 ~]$ sudo service mysqld startmysqldになっていることに注意しましょう。dはLinuxの用語で「サーバ」を意味する「デーモン(daemon)」の頭文字です。
起動できたか確認
[ec2-user@ip-172-31-25-189 ~]$ sudo service mysqld status mysqld (pid 15692) is running...runningとなっていれば起動成功です
MySQLのパスワード設定
yum でインストールしたMySQLには、デフォルトで root というユーザーでアクセス出来るようになっていますが、パスワードは設定されていません。
0から始まるpasswordは読み込んでくれないケースが多いので、避けましょう![ec2-user@ip-172-31-25-189 ~]$ sudo /usr/libexec/mysql56/mysqladmin -u root password 'ここを設定したいパスワードに変更してからコマンドを実行してください'設定したパスワードが使えるか確認しましょう。
以下のコマンドを実行しましょう。[ec2-user@ip-172-31-25-189 ~]$ mysql -u root -pEnter password: とパスワードを入力するように表示されるので、先程設定したパスワードを入力して、Enterしてください。以下のように表示されれば、MySQLの設定は終了です。
Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 4 Server version: 5.6.33 MySQL Community Server (GPL) Copyright (c) 2000, 2016, 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.
- 投稿日:2020-03-10T20:49:25+09:00
PHPでポートフォリオ作成
記事の概要
私が作成したポートフォリオ解説をします
作った背景、工夫したところ、機能、などをまとめました
Udemy PHP+MySQL(MariaDB) Webサーバーサイドプログラミング入門
を参照に作成しています背景
簡単な掲示板のようなものを作ろうと思いましたが、掲示板なので盛り上がったり、人がもう一度来たくなる要素のある掲示板を作ろうと思いました。
目的
・PHPを用いてwebアプリケーションを作成する
・webアプリの基本的な構成、動作を知る
・就活目的なので、自分の技術のレベルを知ってもらうスペック
言語
PHP 7.4.2
データーベース
MariaDB 10.4.11
開発環境
Apache 2.4.41ビジュアルスタジオコード使用
主な機能
会員登録した人がログインしたら掲示板メッセージを送信できます。
・会員登録
会員のお名前、メールアドレス、パスワード、画像を選択することで会員登録ができます。・会員登録におけるエラー表示
名前に関しては空のときにエラー、メールアドレスに関しては空の時とすでに登録済みの時はエラー、パスワードに関しては空の時と4文字以下の時はエラー・ログイン機能
メールアドレス、パスワードを入力します。
データベースにある情報と一致したらログインして、一致しなければログインできないという機能です
次回からログインの欄にチェックをすると、cookieに2週間の間情報が保存されます。・メッセージ送信機能
メッセージを入力するとデーターベースにメッセージが保存されて、それを作成日の新しい順に表示しています。・削除機能
そのメッセージを投稿した人だけが削除したメッセージを削除できるようにしました・返信機能
返信したいメッセージに対して返信が可能です・いいね機能
いいねは一人の会員に対して1回可能で、もう一度いいねしようとすると、いいねを削除します開発手順
1、要件定義
2、環境選定
3、データベース設計
4、設計
5、コーディング1、要件定義
今回作成するアプリに必要な機能は
・会員登録
・ログイン機能
・メッセージ表示機能そのために情報が保存できるデーターベースが必要です
また、メッセージに関しては
・メッセージ送信者がメッセージを削除できる
・すべての会員がどんなメッセージに対しても返信できる
・すべての会員がどんなメッセージに対しても1回だけ「いいね」ができ、その「いいね」が削除できる環境選定
PHPを使用。
「PHP+MySQL(MariaDB) Webサーバーサイドプログラミング入門」に従って、環境選定したのでPHP,MySQL,apacheに関してその教材の流れに従い使用
上記環境はWindowsローカル上に構築しました。
データーベース設計
どんな情報が必要かを考えてデータベースの設計しました。
データベース設計のやり方は「PHP+MySQL(MariaDB) Webサーバーサイドプログラミング入門」に従い設計をすすめました
正規化に関しても、一応理解しているつもりです。
「いいね」機能をつけるときに、追加でテーブルが必要になり付け加えました。
※画像追加
設計
設計に関してはノートに書きました。
会員登録→ログイン→掲示板→ログアウト→ログイン
の順に移動するように設計しました
5.コーディング
設計が固まったところで、コーディングをスタート。
※しかし設計とおりにコーディングいかず、設計を変更しながらコーディングしました。いいねの機能は、コーディング中に追加したので、最初の設計通りには行きませんでした。
htmlはその都度記入
5.1データーベース作成
ローカル環境のMysqlサーバーに
専用ユーザーを作成して、データーベースを作成。そのあと、テーブルを作成。5.2データーベース接続確認
PDOを用いて、データーベースの接続。
try~catchを用いて、成功しているか判断5.3・会員登録機能
入力した値をmemberテーブルに保存。
また、入力欄が空、すでに登録済みメールアドレスを入力したなどの場合、error[]という配列に値を代入します。そして、error[]があるばあいは同じページに、error[]が空ばあいは確認画面に飛びます。また、error[]の要素とその値によってメッセージを赤字でページ内に表現します。
5.4ログイン機能
入力したemailとpasswordがmemberテーブルに保存されている値と一致した場合には、ログインします。エラーが発生した場合は赤字でメッセージをだします。
自動的にログインするをチェックした場合はcookieに値を2週間保存します。5.5メッセージの送信、削除、返信機能
メッセージを送信してデータベースに保存。そして、メッセージを新しい順に写真、名前、日付をつけて表示しました。
また、削除の機能を追加して、返信機能も追加しました。
返信機能では「RE」を押すことで、そのメッセージとそのメッセージを送信主の名前をメッセージの入力欄に記載5.6いいね機能
いいね追加、削除機能
データーベースに、coutsテーブルを作成。もしそのメッセージにいいねをしていない場合にいいねをクリックしたら、countデータベースにユーザーのidとメッセージのid、時間を保存する。逆に、そのメッセージにいいねをしている状態でいいねをクリックしたら、countデータベースから登録あったしてカラム(ユーザーのidとメッセージのid、時間を保存したもの)を削除する。いいね表示機能
そして、countsテーブルから、メッセージのidの数だけいいねの数を表示する5.7
htmlspecialcharsでセキュリティ対策をしました
課題点
・全体のレイアウトのいびつさ
htmlをその都度に入力していたので、いびつなレイアウトになりました。設計をしっかりしてその通りに形を整えることができなかったのが原因と思われます・ユーザーに配慮した設計
ユーザーの使いやすいような、見た目や機能にできてない。スマートフォンに対応したりしていない。
- 投稿日:2020-03-10T16:56:10+09:00
Laravelのインストール後の設定
概要
前回記事でmacOSにインストールしたLarvelの設定を行う
設定
ローカリゼーション
タイムゾーン(時刻設定)とロケール(地域、言語設定)、フェイカー(ダミーデータ言語)を日本に変更。
作成したプロジェクトフォルダ配下のconfigフォルダに、設定ファイル app.php があります。timezoneで検索(70行目)、値を Asia/Tokyo へ、続くブロックにある local の値を ja へ、 faker_locale は ja_JP へ変更。
config/app.php'timezone' => 'Asia/Tokyo', 'locale' => 'ja', 'faker_locale' => 'ja_JP',データベース
データベースを使わない場合は不要ですが、使う場合はローカルにインストールするか仮想サーバをインストールします。Laravelの開発環境向けに、前者はMac用のValet、後者はHomesteadがあります。今回は軽量で動作するValet(ベレット)を使います。
Valetインストール
公式サイト
https://readouble.com/laravel/6.x/ja/valet.htmlLaravelをインストールしたディレクトリにて、Composerを使って実行
(artisanでローカルサーバを起動している場合は停止しておきます)$ composer global require laravel/valet $ valet installメッセージ確認
Valet installed successfully!ping確認
任意のxxx.testにpingを打つと127.0.0.1から応答確認その他
他のドメインの使用
デフォルトでValetは.test TLDをプロジェクトのドメインとして処理します。他のドメインを使いたい場合、valet tld tld-nameコマンドを使ってください。
たとえば、.testの代わりに.appを使用したければ、valet tld appと実行します。Valetは *.appをプロジェクトのために自動的に使い始めます。MySQLインストール
Homebrewを用いてインストール
$ brew install mysql@5.7インストール後、起動
$ brew services start mysql@5.7 ==> Successfully started `mysql@5.7` (label: homebrew.mxcl.mysql@5.7)その他
PHPバージョン
Valetではvalet use php@versionコマンドにより、PHPバージョンを変更できます。指定されたPHPバージョンがインストールされていない場合、ValetはBrewによりインストールします。
valet use php@7.2
valet use php
Note: 複数のPHPバージョンをインストールしている場合でも、Valetは一度に一つのPHPバージョンのみを提供します。インストレーションのリセット
Valetインストレーションが正しく動作せずに問題が起きた時は、composer global updateの後に、valet installを実行してください。これによりインストール済みのValetがリセットされ、さまざまな問題が解決されます。稀にValetを「ハードリセット」する必要がある場合もあり、その場合はvalet installの前にvalet uninstall --forceを実行してください。
アップグレード
Valetインストールをアップデートするには、ターミナルでcomposer global updateコマンドを実行します。アップグレードできたら、valet installコマンドを実行し、必要な設定ファイルの追加アップグレードを行うのは、グッドプラクティスです。
サイト動作確認
ディレクトリを作成し、parkコマンド実行
$ mkdir ~/DIR $ cd DIR/ $ valet parkLaravelサイトを作成
$ laravel new blogブラウザから http://blog.test を開く
必要なのはこれだけです。 これで"parked"ディレクトリ内に作成されたLaravelプロジェクトは、http://フォルダ名.test規約に従い、自動的に動作します。
前回と同様サイトが表示されればOKです。
Valetの停止
起動したサービスを停止する場合
$ valet stopMySQL$ /usr/local/opt/mysql@5.7/bin/mysql.server stop
- 投稿日:2020-03-10T12:25:36+09:00
ありの~ままの~DBスキーマを、go言語ソースコードに自動変換【xorm/reverse】
はい
今回ご紹介するのは、こちらのxorm/reverseです。
https://gitea.com/xorm/reverseなんと!
DBのテーブル構造を直接見に行って、go言語の構造体ソースコードに自動変換してくれます。
対象DB種類も、MySQL以外に色々対応しています。ライセンスは、MITかな?
LICENSEファイルには明示的には書いてないですが、xorm公式ページではMITとなっているので。
https://xorm.io/こちら、実は2年以上前から開発されているようです。
以前はリポジトリはgithubだったんですが、親プロジェクトxormと共にgiteaに移籍したみたいですね。また当時のバージョンではC言語や他の言語ソースへもリバースできたんですが、リニューアル以降はまだ
language/golang.go以外の出力プラグインは作られてないみたいですね。パブリックリポジトリなので、gitea のアカウントを持ってなくてもマイPCからgit cloneできました。
ただ、EC2インスタンスからのgit cloneは失敗しました。AWSはブロックしてるのかしら?
ままエアロ。使い方
・・・をご紹介しようと思ったのですが、早速失敗しました。
READMEどおり
$ go get xorm.io/reverseしたら
# xorm.io/reverse/vendor/github.com/mattn/go-sqlite3 exec: "gcc": executable file not found in %PATH%
gccがインストールされてないと動かない、と。
gcc入れるのダルいなー。それとちょっと改造する用事もあったので、
git cloneしてソースをいじってxorm/reverseのmainコードを直接実行するようにしちゃいましょう。(下準備)リバース対象のお試しMySQLを用意
https://github.com/yagrush/simple-docker-mysql
↑こちらに、docker-composeですぐ起動できるお試しMySQLをご用意しました。
これをgit cloneして起動します。※
docker-compose自体の設定は割愛します。
あるいはAWS EC2用でよろしければ、こちら https://qiita.com/yagrush/items/e85d2da1b0ef9997fa07 をご参照ください。$ cd ~ $ git clone https://github.com/yagrush/simple-docker-mysql.git $ cd simple-docker-mysql $ docker-compose up --build -d
xorm/reverse実行を試みる
xorm/reverseをgit cloneしてくるhttps://gitea.com/xorm/reverse にgit用URLが(githubと同じように)載っているので、ありがたく
git cloneしましょう。$ cd ~ $ git clone https://gitea.com/xorm/reverse.git $ cd reversesqlite3 を対応DBから外す
sqlite3は今回使わないし、
gcc見つからないエラーをちゃっちゃと回避したいので、↓をコメントアウトしちゃいます。
go.mod
require宣言のgithub.com/mattn/go-sqlite3
main.go
import宣言の_ "github.com/mattn/go-sqlite3"
reverse設定ファイルを作る
reverse/examples/goxorm.ymlをmy-mysql.ymlに改名して、プロジェクトルートreverse/にコピーします。そして、中身を適宜編集します。
例えばこんな感じ。kind: reverse name: my-mysql source: database: mysql conn_str: 'root:hogerootpassword@tcp(127.0.0.1:3306)/hogedb' targets: - type: codes include_tables: - hogetable exclude_tables: - foo language: golang template_path: example/template/goxorm.tmpl output_dir: models実行
早速実行してみます。
$ cd reverse $ go run main.go -f my-mysql.yml $何も表示されないですが、エラーもないし、どうやら無事実行されましたかね。
出力を見てみましょう。
設定ファイルにoutput_dir: modelsと書いていたので、これかな?$ cat models/models.go package models type Hogetable struct { Hogename string `xorm:"not null VARCHAR(32)"` Id int `xorm:"not null pk autoincr INT"` }素晴らしい…
ちなみに「
package modelsはいったいどこから来てん?」というと、
↓設定ファイルから参照しているテンプレートファイルgoxorm.tmplにあります。template_path: example/template/goxorm.tmplこれをいじれば、さらにカスタマイズできます。
あと、構造体のフィールドに
xorm:タグがおまけで付いてますね。
これはxorm/reverseの親プロジェクトでもある、オープンソースORMxorm用みたいですね。ちなみにリバース対象にしたDBスキーマは↓こんな感じです。
(上の方でご紹介したお試しセットまんまです)CREATE DATABASE IF NOT EXISTS hogedb; use hogedb; CREATE TABLE hogetable ( id INT NOT NULL AUTO_INCREMENT, hogename VARCHAR(32) NOT NULL, PRIMARY KEY (id) );改造
と、ここまでは良かったのですが、実際使ってみるとつまづきが・・・
この続きは、また!
- 投稿日:2020-03-10T12:24:31+09:00
外部キーエラーが出た人へ「SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint」
要因
mysqlにてテーブルを外部キーとして連携したときに起こったエラーです。
エラー
php artisan migrateで下記エラー内容
Illuminate\Database\QueryException : SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL: alter table `comments` add constraint `comments_ico_id_foreign` foreign key (`ico_id`) references `icos` (`id`) on delete cascade)解決方法
migrateファイルの生成の順番に問題がありました。
外部キー設定をさせるcomments_tableより後に紐づけたいテーブルであるico_tableがありました。
なので名前を変更してcomments_tableより前に持ってきてphp artisan migrateで治りました。
治ったー!
[vagrant@localhost myblog]$ php artisan migrate Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.02 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.02 seconds) Migrating: 2019_12_05_215839_create_posts_table Migrated: 2019_12_05_215839_create_posts_table (0.01 seconds) Migrating: 2019_12_22_211023_create_icos_table Migrated: 2019_12_22_211023_create_icos_table (0.02 seconds) Migrating: 2019_12_23_071756_create_comments_table Migrated: 2019_12_23_071756_create_comments_table (0.04 seconds) Migrating: 2020_01_12_020348_tests_migrate_table Migrated: 2020_01_12_020348_tests_migrate_table (0 seconds)
- 投稿日:2020-03-10T10:14:43+09:00
外部キーを複数設定したい場合のテーブル設計
概要
以下のようなテーブルを想定する。
userテーブル
id name pet user1 太郎 user2 花子 dogテーブル
id name dog1 ポチ catテーブル
id name cat1 タマ userテーブルのpetカラムに外部キーをdogテーブルのidとcatテーブルのidと2つ設定したいが、
外部キーは1つだけしか設定できない。解決法1:参照先の親テーブルを作成する
userテーブル
id name pet user1 太郎 pet1 user2 花子 pet2 petテーブル
id pet1 pet2 dogテーブル
id name pet1 ポチ catテーブル
id name pet2 タマ petテーブルという親テーブルを作成し
userテーブルのpetカラムの外部キーを1つにする。解決法2:子テーブルを作成する
userテーブル
id name user1 太郎 user2 花子 user_dogテーブル
id dog user1 dog1 user_catテーブル
1 2 user2 cat2 dogテーブル
id name dog1 ポチ catテーブル
id name cat1 タマ user_dogテーブルとuser_catテーブルをというように外部キーによって異なるテーブルを作成する。
ちなみにテーブル情報を取得する際はuser_dogとuser_catをUNIONで和集合を作成しuserテーブルにJOINする。
- 投稿日:2020-03-10T00:46:10+09:00
Mac(HomeBrew)でMySQL起動できない時
要約
- ググると色々出てくるがどれもダメで、自分の環境の場合はHomeBrewでMySQLインストールする時に参照されるフォルダのアクセス権が軒並み「取得中」でバグってて必要なものがインストールできていなかったのが原因だったので備忘録。
直し方
- 下記URLを参考にbrew関連のフォルダのアクセス権チェック。変になってるのを直したら、一度MySQL関連ファイルは全て消す。
- ※フォルダのアクセス権は「内包している項目に適用」押しても「取得中」バグには対応してないようなので、chownで頑張った。けど、一度「取得中」のユーザーを消してから「内包している項目に適用」なら修復してくれたかもしれない。
$sudo chown root:admin /usr/local/xxx
- Ref.) どうしよう!困った時のMac上のMySQLのアンインストール&再インストール、動作確認手順 - Qiita https://qiita.com/akiko-pusu/items/aef52b723da2cb5dc596#brew-%E3%81%A7%E5%85%A5%E3%82%8C%E3%81%9F%E3%82%82%E3%81%AE%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B
余談
- おそらくMojaveからCatalinaに上げた時に変になったっぽいので、出来ればOSのメジャーアップデート時にはクリーンインストールしたいところ。
- 投稿日:2020-03-10T00:11:37+09:00
Phoenix on Kubernetesでpostgresでは無くMySQLを使う時のメモ
はじめに
以下の記事でPhoenix on Kubernetes with postgresの環境は整えることができます。
【Elixir / Phoenix】初心者が流れで学ぶDocker/Kubernetes超入門この記事では上の記事の環境をMySQLで動くように変更してみます。
適当にアプリを作る
$ mix phx.new . --app dododo --database=mysql The directory /Users/nakatakensei/docker-elixir already exists. Are you sure you want to continue? [Yn] y * creating config/config.exs * creating config/dev.exs * creating config/prod.exs * creating config/prod.secret.exs * creating config/test.exs * creating lib/dododo/application.ex * creating lib/dododo.ex * creating lib/dododo_web/channels/user_socket.ex * creating lib/dododo_web/views/error_helpers.ex * creating lib/dododo_web/views/error_view.ex * creating lib/dododo_web/endpoint.ex * creating lib/dododo_web/router.ex * creating lib/dododo_web.ex * creating mix.exs * creating README.md * creating .formatter.exs * creating .gitignore * creating test/support/channel_case.ex * creating test/support/conn_case.ex * creating test/test_helper.exs * creating test/dododo_web/views/error_view_test.exs * creating lib/dododo/repo.ex * creating priv/repo/migrations/.formatter.exs * creating priv/repo/seeds.exs * creating test/support/data_case.ex * creating lib/dododo_web/controllers/page_controller.ex * creating lib/dododo_web/templates/layout/app.html.eex * creating lib/dododo_web/templates/page/index.html.eex * creating lib/dododo_web/views/layout_view.ex * creating lib/dododo_web/views/page_view.ex * creating test/dododo_web/controllers/page_controller_test.exs * creating test/dododo_web/views/layout_view_test.exs * creating test/dododo_web/views/page_view_test.exs * creating lib/dododo_web/gettext.ex * creating priv/gettext/en/LC_MESSAGES/errors.po * creating priv/gettext/errors.pot * creating assets/webpack.config.js * creating assets/.babelrc * creating assets/js/app.js * creating assets/js/socket.js * creating assets/package.json * creating assets/css/app.css * creating assets/static/favicon.ico * creating assets/css/phoenix.css * creating assets/static/images/phoenix.png * creating assets/static/robots.txt Fetch and install dependencies? [Yn] y * running mix deps.get * running cd assets && npm install && node node_modules/webpack/bin/webpack.js --mode development * running mix deps.compile We are almost there! The following steps are missing: $ cd docker-elixir Then configure your database in config/dev.exs and run: $ mix ecto.create Start your Phoenix app with: $ mix phx.server You can also run your app inside IEx (Interactive Elixir) as: $ iex -S mix phx.serverconfig/dev.exsを修正
postgresの時と同様にhostnameを
dbに設定します。config/dev.exsuse Mix.Config # Configure your database config :dododo, Dododo.Repo, username: "root", password: "r00t", #modify database: "dododo_dev", hostname: "db", #modify show_sensitive_data_on_connection_error: true, pool_size: 10 #以下変更なしdocker imageをbuildする
$ docker build .タグ付けしてからdockerhubにpush
$ docker images #image idの確認 $ docker tag <image id> sanposhiho/phoenix_for_k8s $ docker push sanposhiho/phoenix_for_k8sdocker-compose.ymlの修正
docker-compose.ymlversion: "3" services: web: image: sanposhiho/phoenix_for_k8s ports: - '4000:4000' command: mix phx.server depends_on: - db db: #dbの設定を変更 image: mysql:5.7 ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: r00tdbの設定をmysql用に変更します。
Komposeを使って変換
$ kompose convert INFO Kubernetes file "db-service.yaml" created INFO Kubernetes file "web-service.yaml" created INFO Kubernetes file "db-deployment.yaml" created INFO Kubernetes file "web-deployment.yaml" created色々作成されます。(便利)
webの部分は基本的に変更されていないのでdbの二つのファイルを見てみましょうdb-deployment.yaml
db-deployment.yamlapiVersion: apps/v1 kind: Deployment metadata: annotations: kompose.cmd: kompose convert kompose.version: 1.21.0 () creationTimestamp: null labels: io.kompose.service: db name: db spec: replicas: 1 selector: matchLabels: io.kompose.service: db strategy: {} template: metadata: annotations: kompose.cmd: kompose convert kompose.version: 1.21.0 () creationTimestamp: null labels: io.kompose.service: db spec: containers: #以下が変更されている - env: - name: MYSQL_ROOT_PASSWORD value: r00t image: mysql:5.7 imagePullPolicy: "" name: db ports: - containerPort: 3306 resources: {} restartPolicy: Always serviceAccountName: "" volumes: null status: {}postgresの時の
db-deployment.yamlとimageなどは勿論異なりますが、大きく変更はありません。db-service.yaml
db-service.yamlapiVersion: v1 kind: Service metadata: annotations: kompose.cmd: kompose convert kompose.version: 1.21.0 () creationTimestamp: null labels: io.kompose.service: db name: db spec: ports: - name: "3306" port: 3306 targetPort: 3306 selector: io.kompose.service: db status: loadBalancer: {}こちらもpostgresの時と異なるのはportくらいですね
volumeの作成
postgresの時と同様にvolumeを作成します。
pvc-phoenix.yamlをpostgresの時と全く同じ内容で作成します。pvc-phoenix.yamlapiVersion: v1 kind: PersistentVolumeClaim metadata: name: pv-claim spec: storageClassName: standard accessModes: - ReadWriteOnce resources: requests: storage: 1Gi
db-deployment.yamlの方も変更しておきます。db-deployment.yamlapiVersion: apps/v1 kind: Deployment metadata: annotations: kompose.cmd: kompose convert kompose.version: 1.21.0 () creationTimestamp: null labels: io.kompose.service: db name: db spec: replicas: 1 selector: matchLabels: io.kompose.service: db strategy: {} template: metadata: annotations: kompose.cmd: kompose convert kompose.version: 1.21.0 () creationTimestamp: null labels: io.kompose.service: db spec: containers: - env: - name: MYSQL_ROOT_PASSWORD value: r00t image: mysql:5.7 imagePullPolicy: "" name: db ports: - containerPort: 3306 volumeMounts: - mountPath: "/var/lib/mysql" name: mysqldata resources: {} restartPolicy: Always serviceAccountName: "" volumes: - name: mysqldata persistentVolumeClaim: claimName: pv-claim status: {}web-service.yamlの修正
外の世界からアクセスできるようにするため
type: NodePortに指定します。web-service.yamlapiVersion: v1 kind: Service metadata: annotations: kompose.cmd: kompose convert kompose.version: 1.21.0 () creationTimestamp: null labels: io.kompose.service: web name: web spec: ports: - name: "4000" port: 4000 targetPort: 4000 selector: io.kompose.service: web type: NodePort #追加 status: loadBalancer: {}準備完了!
立ち上げてみましょう
$ kubectl apply -f db-deployment.yaml -f web-deployment.yaml -f pvc-phoenix.yaml -f web-service.yaml -f db-service.yaml $ kubectl get pods NAME READY STATUS RESTARTS AGE db-76fb87f99f-xlxm9 1/1 Running 0 9m41s web-87795996-dgtkp 1/1 Running 0 3m49s $ kubectl exec -it web-87795996-dgtkp mix ecto.create The database for Dododo.Repo has been created $ minikube service list |----------------------|---------------------------|--------------|---------------------------| | NAMESPACE | NAME | TARGET PORT | URL | |----------------------|---------------------------|--------------|---------------------------| | default | db | No node port | | default | kubernetes | No node port | | default | web | | http://192.168.64.2:32400 | | kube-system | kube-dns | No node port | | kubernetes-dashboard | dashboard-metrics-scraper | No node port | | kubernetes-dashboard | kubernetes-dashboard | No node port | |----------------------|---------------------------|--------------|---------------------------|
mix ecto.createも成功したのでDBもうまく作成されていることがわかります。webのURLにアクセスして以下のページが表示されれば成功です。
終わりに
記事にまとめる必要がないレベルで簡単でした。
メモ程度ですがどなたかの役に立てれば幸いです。













