20200310のMySQLに関する記事は11件です。

【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

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

中間テーブルとは 〜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.rb
has_many :tweet

has_manyの記述を加えます。

Tweetモデル(子モデル)に

Tweet.rb
belongs_to :user

belongs_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.rb
has_one :profile

has_oneの記述を加えます。

Profileモデル(子モデル)に

Tweet.rb
belongs_to :user

belongs_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.rb
has_many :group, through: :member
group.rb
has_many :user, through: :member

モデルファイルに以上の記述を行えば、多対多のアソシエーションが設定されます。

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

SQLのJOINが苦手という人に向けて

はじめに

この仕事に携わっていると、結構な経験者でもSQL、特にテーブル同士の結合が苦手という人によく会います。
で、話を聞くと苦手な理由はテーブル同士のリレーションを視覚的にイメージ出来ないことにあるのかと。。

かつて自分もSQLは大の苦手でした。
2、3年目の時に某電力の大規模Javaプロジェクトに放り込まれました。
テーブル同士の多重度が多対多、オンラインPGで1SELECTあたり3000〜5000行という変態的なSQL。
MVCモデルが出始めの頃、Webフレームワークなんて言葉が流行り出す前
バックエンドからフロントエンドまで全てをベタ書き。
期日までに徹夜・休出しながら直したり書かないといけなかったものですから、それはもう大変な苦労と挫折を味わいました。

そんな環境下でテーブル同士のリレーションを図に整理しながら、書いたり、手直ししたりする内に、視覚的にイメージ出来るようになり、SQLへの苦手意識はほとんど無くなりました。

「乗り越えた壁はいつしか自分を守る盾になる」と誰かが言ってたアレです(笑)

SQLが苦手な方向けの説明になってます。
ある程度のSQL経験者には退屈な内容になっておりますので、あしからず。

3つのJOIN

INNER JOINLEFT (OUTER) JOINFULL (OUTER) JOINの3つのJOINについて説明します。

※他にもRIGHT (OUTER) JOINCROSS JOIN等があります。
ただし、RIGHT (OUTER) JOINLEFT (OUTER) JOINをただ左右反転させたもの、CROSS JOINはよっぽど切羽詰まった状況使うか、使う時点で処理フローを変えることを検討した方が良い、どちらも実務で使うことは稀なので割愛します。

INNER JOIN

説明するまでもありませんが、最も一般的でよく使われるJOINですね。
内部結合っていわれるやつです。
仮にABというテーブルを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_APK_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

ですね。
AB両方に存在する001009のみが抽出されます。

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

完全外部結合と言われます。
実務で使われる頻度は少ないですが、覚えておいて損はないです。

ABを重なり合う部分も含めて全件取ってきます。

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

ABの全件が取得されていることがわかります。
そしてお互いの歯抜けの部分については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

ABLEFT OUTER JOINさせてから、
WHERE句でBの主キーPK_BNULLのレコードを指定しています。

結果は

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歯抜けレコードを指定することで
AB両方にある001009のレコードが除外され、
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歯抜けレコードを指定することによって
AB両方にある001009のレコードが除外され、
お互い重なり合わないABのレコードを取得できます。

さいごに

最近主流のアーキテクチャでは(バッチ処理を除いて)複雑なクエリを書くのはアンチパターンです。
なので上記のようなクエリを組む事も稀かと思いますが、テーブル同士を比較してアンマッチリストを抽出したい時や、ゴミデータ・不正データを調査したい時などにJOINを使いこなせると色々と便利です。

あと気をつけなくてならないのはSELECT文はF・W・G・H・S・Oの順番に評価されます。
何かというとFROMWHEREGROUP BYHAVINGSELECTORDER BYの頭文字です。
JOINFROM句中で書くため、一番最初に評価されます。
なので大量データを保持したテーブル同士をJOINさせるとパフォーマンスの劣化に繋がったりします。
サブクエリやWITH句を使って比較に必要なデータに絞ってからJOINさせる等のパフォーマンスの考慮は必要です。

ただし、最近はOracleMySQLのオプティマイザによって実行計画が最適化されるので、トンチキなSQLを書いても大体は動いてくれます。
自分が走り出しの頃は変なSQL書いたら幾度となく先輩にブッ◯されそうになりました(笑)

で、自分が言いたいのはテーブル同士のリレーションを視覚的にイメージできれば、どんなSQLがやって来ても怖くない、
何千行というSQLも結局はテーブルのJOINの組み合わせに過ぎないということです。

最後までお読み頂きありがとうございました。

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

Amazon Linuxを利用している場合のMySQL

IT未経験のスクール生が学んだことをアウトプットします:confused:

データベース

データベースは沢山の情報が入っている箱のようなものです。この中には様々な種類のデータが入っていて、データを格納したり、取り出したりすることができます。
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 mysql56

MySQLの起動

MySQLを起動するために service コマンドを利用します。これは、Amazon LinuxやCentOSに含まれているもので、インストールしたソフトウェアの起動を一括して行えるツールです。

[ec2-user@ip-172-31-25-189 ~]$ sudo service mysqld start

mysqldになっていることに注意しましょう。dはLinuxの用語で「サーバ」を意味する「デーモン(daemon)」の頭文字です。

起動できたか確認

[ec2-user@ip-172-31-25-189 ~]$ sudo service mysqld status
mysqld (pid  15692) is running...

runningとなっていれば起動成功です:v:

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

Enter 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.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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テーブルに保存。

GIF 2020-03-10 16-04-37.gif

また、入力欄が空、すでに登録済みメールアドレスを入力したなどの場合、error[]という配列に値を代入します。そして、error[]があるばあいは同じページに、error[]が空ばあいは確認画面に飛びます。また、error[]の要素とその値によってメッセージを赤字でページ内に表現します。

GIF 2020-03-10 16-20-53.gif

5.4ログイン機能

入力したemailとpasswordがmemberテーブルに保存されている値と一致した場合には、ログインします。エラーが発生した場合は赤字でメッセージをだします。
自動的にログインするをチェックした場合はcookieに値を2週間保存します。

5.5メッセージの送信、削除、返信機能

メッセージを送信してデータベースに保存。そして、メッセージを新しい順に写真、名前、日付をつけて表示しました。

GIF 2020-03-10 19-40-46.gif

また、削除の機能を追加して、返信機能も追加しました。
返信機能では「RE」を押すことで、そのメッセージとそのメッセージを送信主の名前をメッセージの入力欄に記載

GIF 2020-03-10 19-43-14.gif

5.6いいね機能

いいね追加、削除機能
データーベースに、coutsテーブルを作成。もしそのメッセージにいいねをしていない場合にいいねをクリックしたら、countデータベースにユーザーのidとメッセージのid、時間を保存する。逆に、そのメッセージにいいねをしている状態でいいねをクリックしたら、countデータベースから登録あったしてカラム(ユーザーのidとメッセージのid、時間を保存したもの)を削除する。

いいね表示機能
そして、countsテーブルから、メッセージのidの数だけいいねの数を表示する

GIF 2020-03-10 19-54-12.gif

5.7

htmlspecialcharsでセキュリティ対策をしました

課題点

・全体のレイアウトのいびつさ
htmlをその都度に入力していたので、いびつなレイアウトになりました。設計をしっかりしてその通りに形を整えることができなかったのが原因と思われます

・ユーザーに配慮した設計
ユーザーの使いやすいような、見た目や機能にできてない。スマートフォンに対応したりしていない。

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

Laravelのインストール後の設定

概要

前回記事でmacOSにインストールしたLarvelの設定を行う

設定

ローカリゼーション

 タイムゾーン(時刻設定)とロケール(地域、言語設定)、フェイカー(ダミーデータ言語)を日本に変更。
 作成したプロジェクトフォルダ配下のconfigフォルダに、設定ファイル app.php があります。

 timezoneで検索(70行目)、値を Asia/Tokyo へ、続くブロックにある local の値を ja へ、 faker_localeja_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.html

Laravelをインストールしたディレクトリにて、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 park

Laravelサイトを作成

$ laravel new blog

ブラウザから http://blog.test を開く

必要なのはこれだけです。 これで"parked"ディレクトリ内に作成されたLaravelプロジェクトは、http://フォルダ名.test規約に従い、自動的に動作します。

前回と同様サイトが表示されればOKです。

blog.png

Valetの停止

起動したサービスを停止する場合

$ valet stop
MySQL
$ /usr/local/opt/mysql@5.7/bin/mysql.server stop
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ありの~ままの~DBスキーマを、go言語ソースコードに自動変換【xorm/reverse】

はい:clap:
今回ご紹介するのは、こちらの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/reversegit cloneしてくる

https://gitea.com/xorm/reverse にgit用URLが(githubと同じように)載っているので、ありがたくgit cloneしましょう。:pray:

$ cd ~
$ git clone https://gitea.com/xorm/reverse.git
$ cd reverse

sqlite3 を対応DBから外す

sqlite3は今回使わないし、
gcc見つからないエラーをちゃっちゃと回避したいので、↓をコメントアウトしちゃいます。

  • go.mod
    require宣言の github.com/mattn/go-sqlite3

  • main.go
    import宣言の _ "github.com/mattn/go-sqlite3"

reverse設定ファイルを作る

reverse/examples/goxorm.ymlmy-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"`
}

素晴らしい…:heart_eyes_cat:

ちなみに「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)
);

改造

と、ここまでは良かったのですが、実際使ってみるとつまづきが・・・
この続きは、また!

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

外部キーエラーが出た人へ「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で治りました。

名前変更前
migrate2.jpg

名前変更後
migrate.jpg

治ったー!

[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)

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

外部キーを複数設定したい場合のテーブル設計

概要

以下のようなテーブルを想定する。

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

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

Mac(HomeBrew)でMySQL起動できない時

要約

  • ググると色々出てくるがどれもダメで、自分の環境の場合はHomeBrewでMySQLインストールする時に参照されるフォルダのアクセス権が軒並み「取得中」でバグってて必要なものがインストールできていなかったのが原因だったので備忘録。

直し方

  • 下記URLを参考にbrew関連のフォルダのアクセス権チェック。変になってるのを直したら、一度MySQL関連ファイルは全て消す。
    • ※フォルダのアクセス権は「内包している項目に適用」押しても「取得中」バグには対応してないようなので、chownで頑張った。けど、一度「取得中」のユーザーを消してから「内包している項目に適用」なら修復してくれたかもしれない。

$sudo chown root:admin /usr/local/xxx

余談

  • おそらくMojaveからCatalinaに上げた時に変になったっぽいので、出来ればOSのメジャーアップデート時にはクリーンインストールしたいところ。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.server

config/dev.exsを修正

postgresの時と同様にhostnameをdbに設定します。

config/dev.exs
use 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_k8s

docker-compose.ymlの修正

docker-compose.yml
version: "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: r00t

dbの設定を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.yaml
apiVersion: 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.yaml
apiVersion: 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.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pv-claim
spec:
  storageClassName: standard
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

db-deployment.yamlの方も変更しておきます。

db-deployment.yaml
apiVersion: 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.yaml
apiVersion: 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にアクセスして以下のページが表示されれば成功です。
スクリーンショット 2020-03-10 0.09.08.png

終わりに

記事にまとめる必要がないレベルで簡単でした。
メモ程度ですがどなたかの役に立てれば幸いです。

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