20200914のMySQLに関する記事は9件です。

【初心者向け】LaravelアプリケーションをHerokuで公開しよう!【MySQL】

はじめに

Laravelアプリケーションを作成し、Herokuでいざ公開しようと思ったものの、これが意外や初心者には難しい。私はアプリケーションを公開するだけで3日間も悪戦苦闘してしまいました。同じ初心者の方には辛い思いをして欲しくないので、備忘録も兼ねてマニュアル記事を作成しました。

使用環境

・PHP7.2
・Laravel5.5
・mysql5.7
・Docker
※本記事では環境構築については解説いたしません
※PCはMacを使用しています

①アプリケーションをGitリポジトリに入れよう

HerokuはGitの情報を用いてアプリケーションを公開します。そのため、まずはアプリケーションをGitリポジトリに入れる必要があります。
Gitについては以下のサイトが分かりやすいです。

https://backlog.com/ja/git-tutorial/intro/01/

Gitの設定

まずは名前とメールアドレスを設定しましょう。以下のコマンドをターミナルに入力します。
※ご自身の名前とメールアドレスを入力してください。

$ git config --global user.name "haruto.takahashi"
$ git config --global user.email "haruto.takahashi@gmail.com"

設定した内容は以下のコマンドで確認できます。

$ git config --global -l

core.editor=/usr/bin/nano
user.name=haruto.takahashi
user.email=haruto.takahashi@gmail.com

リポジトリの作成

まずはアプリケーションのあるディレクトリに移動します。

$ cd アプリケーション

次に以下のコマンドを入力することでリポジトリが作成されます。

$ git init

「Initialized empty Git repository in〜」と表示された場合は、指定のディレクトリに「.git/」というGitリポジトリが設置されたということになります。
以下のコマンドで現在のステータスを確認してみましょう。

$ git status

「No commits yet」と表示されるはずです。コミットされたファイルがないという意味です。

ステージの実行

以下のコマンドを入力し、全てのファイルのステージを実行します。

$ git add .

再び以下のコマンドで現在のステータスを確認してみましょう。

$ git status

今度は「new file:」としてステージされたファイルが無数の羅列となって表示されているかと思います。

コミットの実行

以下のコマンドを入力し、コミットを実行します。

$ git commit -m "first-commit"

「first-commit」の部分は何でも良いのですが、git commit のコマンドの後に、-m "(メッセージ)" と付けることで、どんな変更を行ったかというコミットメッセージを入力することが可能です。
「create mode」と書かれた羅列が表示されていればコミット完了です。今後アプリケーションに変更を反映させる時は、同じようにコミットを実行しましょう。Herokuで公開後も同じです。

②Herokuの設定をしよう

Gitの設定が完了したところで、次にHerokuの設定を行っていきます。Herokuへアプリケーションを公開(デプロイ)するためにはいくつか準備が必要です。

アカウントの作成

以下のページよりアカウントを作成してください。今回は無料版の使用を前提とします。
Heroku

設定については以下のページが参考になります。
https://blog.proglus.jp/1438/

Heroku-CLIの導入

Herokuをターミナルから操作できるようにするためのツールとしてHeroku-CLIを導入します。
まずは以下のコマンドを実行します。

$ wget https://cli-assets.heroku.com/heroku-linux-x64.tar.gz -O heroku.tar.gz
$ sudo mkdir -p /usr/local/lib/heroku
$ sudo tar --strip-components 1 -zxvf heroku.tar.gz -C /usr/local/lib/heroku

なお「-bash: wget: コマンドが見つかりません」と表示された場合は、以下のコマンドでwgetをインストールしましょう。

$ brew install wget

brewも使用できない場合は同様にインストールが必要です。インストール方法はネットで検索すれば出てくるのでぜひ探してみてください。

シンボリックリンクの作成

導入が完了したら、次にシンボリックリンクを作成します。シンボリックリンクとは特定のファイルを別の場所から参照できるようにするためのもので、簡単に言うとWindowsのショートカットのようなものです。

シンボリックリンクとは

シンボリックリンクを設定するには以下のコマンドを実行します。

$ sudo ln -s /usr/local/lib/heroku/bin/heroku /usr/local/bin/heroku

なお余談ですが、シンボリックリンクを削除したい時は以下のコマンドを実行します。

$ unlink /usr/local/bin/heroku

シンボリックリンクの設定が完了したら、以下のコマンドでHerokuへログインします。アカウント作成時に設定したメールアドレスとパスワードを聞かれるので入力しましょう。

$ heroku login -i

heroku: Enter your login credentials
Email: Herokuに登録済みのメールアドレスを入力
Password: Herokuに登録済みのパスワードを入力

③Herokuアプリケーションを作成しよう

アプリケーションの作成

Herokuで公開するためのアプリケーションを作成します。下記のコマンドで実行されます。この時、アプリケーションの名前も設定しましょう。

$ heroku create 任意のアプリ名

なお同じ名前のアプリケーションが既に作成されていた場合は、他者と重複しないよう名前を変更する必要があります。またその他の名前のルールとして、大文字やアンダーバー(_)はNGです。
作成後は以下のコマンドで名前が正しく登録されているかを確認します。

$ heroku apps

Procfileファイルの作成

Procfileファイルとは、Herokuのプラットフォーム上にあるWebアプリがどのようなコマンドで実行されるのかを記述するファイルのことです。以下のコマンドで作成できます。

$ echo "web: vendor/bin/heroku-php-apache2 public/" > Procfile

Herokuのapache2(Webサーバソフト)を使用するという記述になります。
ここで一度、Gitでコミットを実行します。

$ git add .
$ git commit -m 'add procfile'

④アプリケーションを公開しよう

いよいよ最終段階...ですが設定しなければいけないことがまだいくつかあります。

データベースの設定

Herokuでは、PostgreSQLが標準のデータベースとなっています。MySQLを利用するにはClearDBというクラウドサービスを活用します。以下のコマンドで追加できます。

$ heroku addons:add cleardb

環境変数の設定

Gitコミットを実行したファイルには.envファイルが含まれていないため、これまでとは別途で環境変数を設定する必要があります。
まず以下のコマンドを実行することで、Herokuでローカル環境と同じAPP_KEYが生成されます。

$ heroku config:set APP_KEY=$(php artisan --no-ansi key:generate --show)

以下のコマンドでHerokuアプリケーションの環境変数を確認できます。

$ heroku config

=== youtube-curation Config Vars
APP_KEY:      base64:設定されたAPP_KEYが表示
CLEARDB_DATABASE_URL: mysql://ユーザ名:パスワード@ホスト名:5432/データベース名

「DATABASE_URL」に表示されている内容を元に、以下のコマンドで環境変数の設定を行います。それぞれコピペしましょう。

$ heroku config:set DB_USERNAME=ユーザ名
$ heroku config:set DB_PASSWORD=パスワード
$ heroku config:set DB_HOST=ホスト名
$ heroku config:set DB_DATABASE=データベース名

またデータベースの設定も行います。使用するデータベースはMySQLなので以下のコマンドを実行します。

heroku config:set DB_CONNECTION=mysql

最後にもう一度、環境変数が正しく設定されているかを確認しましょう。

$ heroku config

=== youtube-curation Config Vars
APP_KEY:       base64: APP_KEY
CLEARDB_DATABASE_URL:  mysql://ユーザ名:パスワード@ホスト名:5432/データベース名
DB_CONNECTION: mysql
DB_USERNAME:   ユーザ名
DB_PASSWORD:   パスワード
DB_HOST:       ホスト名
DB_DATABASE:   データベース名

確認ができたら以下のコマンドでHerokuアプリケーションのマイグレーションを実行します。

$ heroku run php artisan migrate

以下のように

Do you really wish to run this command? (yes/no) [no]:

と聞かれた場合は「y(yes)」と答えます。

またシーダーを挿入する場合は以下のコマンドも実行します。

$ heroku run php artisan db:seed

Herokuアプリケーションへのアクセス

設定は以上です。お疲れ様でした。
以下のURLからアプリケーションへアクセスしましょう。

https://Herokuアプリ名.herokuapp.com/

アプリケーションへの接続がうまくいかない場合は環境変数を見直してみましょう(私もここでミスがありました)
先ほどと同じ「heroku config:set」のコマンドを用いることで、環境変数を上書きすることができます。

【補足①】Heroku公開後にアプリケーションの更新を反映する方法

復習になりますが、以下のコマンドでHerokuアプリケーションに変更が反映されます。

$ git add .
$ git commit -m 'メッセージ'
$ git push heroku master

【補足②】Heroku公開後にエラーが発生した場合

Herokuアプリケーションはエラー発生時に「something went wrong.」というメッセージのみ表示されます。しかしこれではエラーの原因が分からないままです。以下のコマンドを実行することで、エラーの詳細を表示することができます。

$ heroku config:set APP_DEBUG=true

先ほどのメッセージが表示された画面を更新すると、エラーの詳細が表示されるはずです。
エラーが解決したら以下のコマンドでエラーの詳細が表示されないように設定を戻しておきましょう。

$ heroku config:set APP_DEBUG=false

あとがき

私は初めてアプリケーションを作成した時に、ネットで公開するだけでまさかこんなにたくさんの手順があるとは思いもよらず絶望していました。この記事がそんな辛い思いをしている駆け出しエンジニアの方のお役に立てば幸いです。最後までお読みいただきありがとうございました!

参照サイト

https://yu-nocode.com/wp/entry/laravel-quest-6/#i
https://qiita.com/yu731994/items/86e03c5ff91aa3ba7e9d
https://qiita.com/fukkun/items/dfa7002371b9f6e1abae
https://laraweb.net/environment/4115/

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

HerokuにデプロイしたLaravelアプリでDBのレコード表示(日本語)が文字化け

問題

先日、Laravelで制作しているクチコミ投稿サイトをHerokuにデプロイしました。データベースにはClearDB MySQLを使用していますが、日本語の文字化けが発生しました。YouTube万屋エンジニアチャンネル様の多大な協力のおかげで解決できました。

状況整理

  • MacターミナルのMySQLでINSERTしたデータはブラウザで表示するとƒ–ルーノート最高のミïみたいに文字化けする
  • 一方ブラウザ上のフォームから投稿した内容はターミナルで表示すると?????????となる
  • ただし、ターミナルでINSERTしたデータはターミナル上ではきちんと表示され、ブラウザのフォームから投稿したデータはブラウザ上ではきちんと表示される

ちなみに、teratailにも質問投稿していました→ https://teratail.com/questions/291553?reply=true

環境確認

Heroku, ClearDB MySQL, Laravel 7, MacOS

原因は何か?

上のteratailを見ていただくとわかりますが、私は文字コードに関連しそうな箇所の見当をつけるべくviewの

のやdatabase.phpなど見当違いな箇所を見てましたが、今回に関しては関係ありませんでした。

原因はMySQLクライアントの文字コード設定でした。ターミナルでMySQLにログインして下記コマンドで確認できます↓

mysql> show variables like 'character%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

↑このlatin1をutf8に変更する必要があります。変更にはMySQLの設定ファイルをいじることが必要です。

MySQLの設定ファイルを探せ!

設定ファイルは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

1つめのディレクトリにはファイルが存在しませんでした...↓

$ cd /etc/my.cnf
-bash: cd: /etc/my.cnf: No such file or directory

2つめはディレクトリが存在しませんでした...↓

$ cd /etc/mysql
-bash: cd: /etc/mysql: No such file or directory

3つめのディレクトリにはありました...↓

$ cd /usr/local/etc
$ ls
bash_completion.d   freetds.conf        locales.conf        odbc.ini        openldap        php
fonts           gitconfig       my.cnf          odbcinst.ini        openssl@1.1     pool.conf

catコマンドでファイルを閲覧します↓catは、concatenate(連結するの意)の略でファイルを閲覧したり連結コマンド。

$ cat 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(文字)に関する設定がありません。これを使っていきます!

その前に一応4つめも↓...ありません。

$ cd ~/.my.cnf
-bash: cd: /Users/私のユーザー名/.my.cnf: No such file or directory

番外編で下記の方法でも探しました。大量の結果が出てきて、しかも長かったので途中でCtrl+cでキャンセルしましたが、2点ほど気になる結果が。

$ find / -name "my*.cnf"
find: /usr/sbin/authserver: Permission denied
/usr/local/etc/my.cnf
/usr/local/Cellar/mysql/8.0.21_1/.bottle/etc/my.cnf

一応中を覗いてみるとこんな感じ↓でもこれは一旦無視。

$ cd /usr/local/Cellar/mysql/8.0.21_1/.bottle/etc
$ ls
my.cnf
$ cat 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

my.cnfファイルに文字コードの設定を追記する

/usr/local/etc/my.cnfファイルをいじっていきます。
下記のように[mysqld]にcharacter-set-server = utf8、[client]にdefault-character-set = utf8を追記しました。(アンダーバーとハイフンなどスペルミスお気をつけください!汗)
念のため、開くコマンドは$vi my.cnf、開いたらINSERTのiで編集モード、終わったらescボタン :wq Enterボタンです。

my.cnf
[mysqld]
# Only allow connections from localhost
bind-address = 127.0.0.1
mysqlx-bind-address = 127.0.0.1
character-set-server = utf8
[client]
default-character-set = utf8
[mysql]

結果確認

MySQLを再起動($ mysql.server stop $ mysql.server start)して、見てみると...↓

mysql> show variables like "character%";
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

↑character_set_serverがlatin1のままなのは気になりますが、この状態でターミナルからINSERT文で挿入したレコードの日本語はきちんとブラウザで表示され、ブラウザのフォームから投稿して挿入されたレコードはターミナルのMySQLできちんと日本語で表示されるようになりました。

ちなみに、過去に文字化けしたレコードはそのまま文字化けしたままです。

もしこれでうまく行かなかったらぜひコメントください m(_ _)m

YouTube万屋エンジニアチャンネル様、重ね重ねありがとうございました。

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

特定のテーブルスペースにあるテーブルをinnodb_file_per_tableにテーブルを一気に移動したい時に使うSQL

データ容量が不足して、テーブルスペースを削除したいけど、テーブルスペースを削除するにはテーブルスペースに格納されているデータを別のテーブルスペースに移さないといけない!
そんな時に利用するALTER TABEL文を一気に作成するクエリです。
テーブルスペースを利用していたが、innodb_file_per_tableに一括で変換して元の領域に戻したいと思った時に使ってください。
innodb_file_per_tableテーブルスペースの場合だけ、データ削除によってテーブルに空き領域が出来たときには、ちゃんと必要な分だけ容量を確保するようにMysqlは動きます。
テーブルスペースの場合は、空き容量を回収してくれないので、削除しないとダメなので、運用がちょっと面倒。

テーブルの文字コードを一括変換するSQLを作成するSQL

SELECT
    a.NAME AS space_name,
    b.NAME AS table_name,
    REPLACE( CONCAT( "ALTER TABLE " , b.NAME , " TABLESPACE innodb_file_per_table;" ) , "/", ".")
FROM
    information_schema.INNODB_SYS_TABLESPACES a,
    information_schema.INNODB_SYS_TABLES b 
WHERE
    a.SPACE = b.SPACE 
    AND a.NAME LIKE '<テーブルスペース名>'
    AND b.NAME not like "%/FTS%"
    ;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

特定のテーブルスペースにあるテーブルをinnodb_file_per_tableもしくは特定のディレクトリのテーブルスペースに一気に移動したい時に使うSQLを作成するSQL

データ容量が不足して、テーブルスペースを削除したいけど、テーブルスペースを削除するにはテーブルスペースに格納されているデータを別のテーブルスペースに移さないといけない!
そんな時に利用するALTER TABEL文を一気に作成するクエリです。
innodb_file_per_tableテーブルスペースの場合だけ、データ削除によってテーブルに空き領域が出来たときには、ちゃんと必要な分だけ容量を確保するようにMysqlは動きます。
テーブルスペースの場合は、空き容量を回収してくれないので、削除しないとダメなので、運用がちょっと面倒。

特定のテーブルスペースにあるテーブルをinnodb_file_per_tableもしくは特定のディレクトリのテーブルスペースに一気に移動したい時に使うSQLを作成するSQL

SELECT
    a.NAME AS space_name,
    b.NAME AS table_name,
    REPLACE( CONCAT( "ALTER TABLE " , b.NAME , " TABLESPACE innodb_file_per_table;" ) , "/", ".") as "innodb_file_per_tableに移動するSQL",
    CONCAT( "CREATE TABLESPACE `" , REPLACE( b.NAME , "/", "_") , "` ADD DATAFILE '<テーブルスペースを作成するディレクトリ>", REPLACE( b.NAME , "/", "_") , ".ibd' FILE_BLOCK_SIZE=8192 Engine=InnoDB;" ) as "特定のディレクトリにテーブルごとにテーブルスペースを作成するSQL",
    CONCAT( "ALTER TABLE " , REPLACE( b.NAME , "/", "_") , " TABLESPACE = `" , REPLACE( b.NAME , "/", "_") , "`;" ) as "特定のディレクトリのテーブルごとのテーブルスペースにテーブルを移動するSQL"
FROM
    information_schema.INNODB_SYS_TABLESPACES a,
    information_schema.INNODB_SYS_TABLES b 
WHERE
    a.SPACE = b.SPACE 
    AND a.NAME LIKE '<テーブルスペース名>' -- テーブルスペース単位で指定したい場合はこちら
    #AND b.NAME LIKE '<データベース名>%' -- データベース単位で指定したい場合はこちら
    ;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

テーブルをinnodb_file_per_tableもしくは特定のディレクトリのテーブルスペースに一気に移動したい時に使うSQLを作成するSQL

データ容量が不足して、テーブルスペースを削除したいけど、テーブルスペースを削除するにはテーブルスペースに格納されているデータを別のテーブルスペースに移さないといけない!
そんな時に利用するALTER TABEL文を一気に作成するクエリです。
innodb_file_per_tableテーブルスペースの場合だけ、データ削除によってテーブルに空き領域が出来たときには、ちゃんと必要な分だけ容量を確保するようにMysqlは動きます。
テーブルスペースの場合は、空き容量を回収してくれないので、削除しないとダメなので、運用がちょっと面倒。

テーブルをinnodb_file_per_tableもしくは特定のディレクトリのテーブルスペースに一気に移動したい時に使うSQLを作成するSQL

SELECT
    a.NAME AS space_name,
    b.NAME AS table_name,
    CONCAT( "ALTER TABLE " , REPLACE( b.NAME , "/", "_") , " TABLESPACE innodb_file_per_table;" ) as "innodb_file_per_tableに移動するSQL",
    CONCAT( "DROP TABLESPACE " , a.NAME , " ENGINE=INNODB;" )  as "テーブルスペースを削除るSQL",
    CONCAT( "CREATE TABLESPACE `" , REPLACE( b.NAME , "/", "_") , "` ADD DATAFILE '<テーブルスペースを作成するディレクトリ>", REPLACE( b.NAME , "/", "_") , ".ibd' FILE_BLOCK_SIZE=8192 Engine=InnoDB;" ) as "特定のディレクトリにテーブルごとにテーブルスペースを作成するSQL",
    CONCAT( "ALTER TABLE " , REPLACE( b.NAME , "/", "_") , " TABLESPACE = `" , REPLACE( b.NAME , "/", "_") , "`;" ) as "特定のディレクトリのテーブルごとのテーブルスペースにテーブルを移動するSQL"
FROM
    information_schema.INNODB_SYS_TABLESPACES a,
    information_schema.INNODB_SYS_TABLES b 
WHERE
    a.SPACE = b.SPACE 
    AND a.NAME LIKE '<テーブルスペース名>' -- テーブルスペース単位で指定したい場合はこちら
    #AND b.NAME LIKE '<データベース名>%' -- データベース単位で指定したい場合はこちら
    #AND b.NAME NOT IN ('<除外したいテーブル名>')
    ;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【第二回】SpringとMySqlとMyBatisの連動方法

はじめに

DreamHanksの松下です。今回はSpringとMySqlとMyBatisの連動方法を解説していきます。

連載記事まとめ

xmlファイルの設定

新規でプロジェクトを作った際にデフォルトで生成される3つのxmlファイルをカスタマイズしていきます。

◆pom.xmlの設定

下記のdependency(依存するライブラリ)をデフォルトで生成されたpom.xmlの<dependencies>タグの中にコピペしてください。

pom.xmlの詳しい内容は下記の記事で解説しています。
Mavenの解説

        <!-- MySQL -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>

        <!-- MyBatis 3.4.1 -->
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.1</version>
        </dependency>

        <!-- MyBatis-Spring -->
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>

        <!-- Spring-jdbc -->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>

        <!-- Mybatis log -->
        <!-- https://mvnrepository.com/artifact/org.bgee.log4jdbc-log4j2/log4jdbc-log4j2-jdbc4.1 -->
        <dependency>
            <groupId>org.bgee.log4jdbc-log4j2</groupId>
            <artifactId>log4jdbc-log4j2-jdbc4</artifactId>
            <version>1.16</version>
        </dependency>

上記pomの解説

<!-- MySQL -->      Mysql(DB)と接続するためのdependency
<!-- MyBatis 3.4.1 -->   MyBatisを使うためのdependency
<!-- MyBatis-Spring -->   MyBatisとSpringフレームワークを連動するためのdependency
<!-- Spring-jdbc -->    SpringJdbcで使うためのdependency
<!-- Mybatis log -->    MyBatisのログを出すためのdependency

◆root-context.xmlの設定

デフォルトの状態
root-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- Root Context: defines shared resources visible to all other web components -->

</beans>

設定後の状態
root-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
    xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">

    <!-- Root Context: defines shared resources visible to all other web components -->
    <context:component-scan
        base-package="com.dreamhanks" />
    <context:component-scan
        base-package="com.dreamhanks.service" />



    <!-- MySQL dataSource -->
    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName"
            value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
        <property name="url"
            value="jdbc:log4jdbc:mysql://localhost:3306/work_db?useSSL=false&amp;serverTimezone=UTC"></property>
        <property name="username" value="root"></property>
        <property name="password" value="Daiki8863"></property>
    </bean>

    <!-- mybatis SqlSessionFactoryBean -->
    <bean id="sqlSessionFactory"
        class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation"
            value="classpath:/mybatis-config.xml"></property>
        <property name="mapperLocations"
            value="classpath:mappers/**/*Mapper.xml"></property>
    </bean>

    <!-- mybatis -->
    <bean id="sqlSession"
        class="org.mybatis.spring.SqlSessionTemplate"
        destroy-method="clearCache">
        <constructor-arg name="sqlSessionFactory"
            ref="sqlSessionFactory"></constructor-arg>
    </bean>
</beans>

 ①設定後の状態のroot-context.xmlをコピペしてください。

 ②<!-- MySQL dataSource -->の設定
  ・下記のvalue値を自分のmysqlの環境に合わせる

       <property name="url"
            value="jdbc:log4jdbc:mysql://localhost:3306/work_db?useSSL=false&amp;serverTimezone=UTC"></property>
        <property name="username" value="root"></property>
        <property name="password" value="Daiki8863"></property>

   特にみるべきところ
    ・work_db → カレントスキーマ
    ・username, passwordを自分のmysqlの環境に合わせる。

 ③パッケージ名などは自分の環境にあわせること

root-context.xmlの詳しい内容は「xmlファイルの解説」という記事内で解説しています。(2020/09/11工事中)

    <context:component-scan
        base-package="com.dreamhanks" />
    <context:component-scan
        base-package="com.dreamhanks.service" />

◆servlet-context.xmlの設定

servlet-context.xml
  <?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

    <!-- Enables the Spring MVC @Controller programming model -->
    <annotation-driven />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>

    <context:component-scan base-package="com.dreamhanks.workmanager" />



</beans:beans>

 ①特に設定すべき個所はありませんが、下記の内容が自分の環境と合っているかを確認してください

  <context:component-scan base-package="com.dreamhanks.workmanager" />

servlet-context.xmlの詳しい内容は「xmlファイルの解説」という記事内で解説しています。(2020/09/11工事中)

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

EC2内でローカルと同じGemをインストールしようとしたらエラーが起きた

ポートフォリオ用に作成したアプリをAWSにデプロイする際にEC2環境にGemをインストールしようとした時に下記のエラーが発生したので、解決方法をメモしておく。

bundle installを実行して、ローカルと同じGemをインストールしようとしたら下記のエラーが発生した。

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
    current directory: /home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/mysql2-0.5.3/ext/mysql2
/home/ec2-user/.rbenv/versions/2.5.1/bin/ruby -r ./siteconf20200913-26933-1jq0rwz.rb extconf.rb
checking for rb_absint_size()... yes
checking for rb_absint_singlebit_p()... yes
checking for rb_wait_for_single_fd()... yes
checking for -lmysqlclient... no
-----
mysql client is missing. You may need to 'sudo apt-get install libmariadb-dev', 'sudo apt-get install libmysqlclient-dev' or 'sudo yum install mysql-devel', and try again.
-----
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/home/ec2-user/.rbenv/versions/2.5.1/bin/$(RUBY_BASE_NAME)
        --with-mysql-dir
        --without-mysql-dir
        --with-mysql-include
        --without-mysql-include=${mysql-dir}/include
        --with-mysql-lib
        --without-mysql-lib=${mysql-dir}/lib
        --with-mysql-config
        --without-mysql-config
        --with-mysql-dir
        --without-mysql-dir
        --with-mysql-include
        --without-mysql-include=${mysql-dir}/include
        --with-mysql-lib
        --without-mysql-lib=${mysql-dir}/lib
        --with-mysqlclientlib
        --without-mysqlclientlib

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/extensions/x86_64-linux/2.5.0/mysql2-0.5.3/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/mysql2-0.5.3 for inspection.
Results logged to /home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/extensions/x86_64-linux/2.5.0/mysql2-0.5.3/gem_make.out

An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  mysql2

どうやらMySQLがインストールできなかったらしく、このどれかのコマンドやったら直るかもとのことらしい。

解決策

mysql client is missing. You may need to 'sudo apt-get install libmariadb-dev', 'sudo apt-get install libmysqlclient-dev' or 'sudo yum install mysql-devel', and try again.

エラーメッセージ内にあった上記の推奨コマンドの一つであるsudo yum install mysql-develを実行したら解決した。

下記が出ればOK

In Gemfile:
  mysql2
[ec2-user@ip-10-0-0-142 trelog_app]$ sudo yum install mysql-devel
読み込んだプラグイン:priorities, update-motd, upgrade-helper
amzn-main                                                                                                                                                | 2.1 kB  00:00:00     
amzn-updates                                                                                                                                             | 3.8 kB  00:00:00     
nodesource                                                                                                                                               | 2.5 kB  00:00:00     
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ mysql-devel.noarch 0:5.5-1.6.amzn1 を インストール
--> 依存性の処理をしています: mysql55-devel >= 5.5 のパッケージ: mysql-devel-5.5-1.6.amzn1.noarch
--> 依存性の処理をしています: /usr/bin/mysql_config のパッケージ: mysql-devel-5.5-1.6.amzn1.noarch
--> トランザクションの確認を実行しています。
---> パッケージ mysql55-devel.x86_64 0:5.5.62-1.23.amzn1 を インストール
--> 依存性の処理をしています: real-mysql55-libs(x86-64) = 5.5.62-1.23.amzn1 のパッケージ: mysql55-devel-
............省略
........
....
..
.
依存性関連をインストールしました:
  mysql55.x86_64 0:5.5.62-1.23.amzn1     mysql55-devel.x86_64 0:5.5.62-1.23.amzn1     mysql55-libs.x86_64 0:5.5.62-1.23.amzn1     mysql56-devel.x86_64 0:5.6.49-1.37.amzn1    

完了しました!

依存関係がいい感じになったっぽいので再度Gemをインストールすると無事にインストールできた。やったぜ。

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

Python + MySQL でコネクションプーリング

Python で MySQL とのコネクションプーリングを行う方法と、そのハマりどころについて。

mysql-connector-python の MySQLConnectionPool の問題

まず、MySQL 公式の Python クライアント mysql-connector-python で単純にコネクションを作成する場合は以下のように書ける。

import mysql.connector

cnx = mysql.connector.connect(host="...", user="...", password="...", database="...")

この mysql-connector-python には MySQLConnectionPool というクラスが用意されており、これを使うと簡単にコネクションプーリングができる。1

from mysql.connector.pooling import MySQLConnectionPool

cnxpool = MySQLConnectionPool(host="...", user="...", password="...", database="...", pool_size=10)

cnx = cnxpool.get_connection()

cnx.close()  # 実際にはコネクションは切断されず、コネクションプールにリリースされる

めでたしめでたし・・・とはいかない。

試しに以下のコードを実行してみる。

from mysql.connector.pooling import MySQLConnectionPool

cnxpool = MySQLConnectionPool(host="...", user="...", password="...", database="...", pool_size=3)

cnxpool.get_connection()
cnxpool.get_connection()
cnxpool.get_connection()
cnxpool.get_connection()  #=> PoolError: Failed getting connection; pool exhausted

MySQLConnectionPool はプールのコネクションが枯渇した場合、例外を投げる仕様となっている。

このシンプルな仕様は嫌いではないのだけど、実際に Web アプリケーションなどで利用する際は「他のコネクションがリリースされるまで待つ」ような挙動であってくれたほうが嬉しいケースが多い。そうでないと、リクエスト処理の並列数が少しでもプールサイズを上回っただけでエラーが発生してしまう。

SQLAlchemy の QueuePool を使った解決策

この問題は、SQLAlchemy の QueuePool を使うと解決できる。2

from sqlalchemy.pool import QueuePool

cnxpool = QueuePool(lambda: mysql.connector.connect(host="...", user="...", password="...", database="..."), pool_size=10)

cnx = cnxpool.connect()

QueuePool の第一引数は「DB API に対応したコネクションオブジェクト」を返す関数ならなんでもいいらしい。汎用的ですごい。

SQLAlchemy というモジュール自体は ORM だが、今回は ORM 部分を全く使わずに QueuePool という仕組みだけを利用している。

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

laravelでテスト用DBを設定する手順

ほとんどをよしなに手軽にやってくれるLaravelですが、
DBを使うphpunit設定はちょっと分かりにくいです。

SQLSTATE[HY000] [1044] Access denied for user 'user'@'%' to database 'test_db'

↑phpunitのコマンドでこんな表示があった人は、幸せにできる記事です。

※DBはmysql

設定のポイント

・テスト用のDB(スキーマ)を作る必要がある
作成したスキーマに、テスト時に使う接続設定(ユーザー権限)を加える必要がある
・phpunit側に接続情報を加える必要がある

1 テスト用のDBを作成する

ここではrootユーザーで接続している想定です。

CREATE SCEMA test_db;

2 アクセス権限の設定

laravelの接続情報(.envに書くDB_USERNAMEのとこ)がroot以外のユーザーの場合、
デフォルトではrootユーザーが作成したDBへのアクセス権限がない場合がある(rootユーザ以外でSHOW DATABASESしてもDB一覧に表示されない)。

ので、rootユーザーでGRANT文を実行、アクセス権限を与えて、テストで使えるようにしてあげる

GRANT ALL ON test_db.* TO user(ユーザー名);

もし権限を与えたいユーザー名がわからない時は、mysqlスキーマから確認

mysql> SHOW DATABASES; -- スキーマ一覧を表示

+--------------------+
| Database           |
+--------------------+
| information_schema |
| app_db             |
| mysql              |
| performance_schema |
| sys                |
| test_db            |
+--------------------+

mysql> use mysql;

mysql> select * FROM user;
-- ユーザーとHOST(どこからの接続を許容するか)、ユーザーが持つ権限も表示される

※ アプリ用DBユーザとテスト用DBユーザを分けるメリットはそれほどないと思うので、laravelの.envに書いてあるユーザーでいいと思います。

3 phpunit.xmlに接続情報を記入

あとは、.envに書いてある接続情報を、phpunit.xmlに書いてあげればOK!

DB_DATABASE=db # アプリで使うDB
DB_USERNAME=user
DB_PASSWORD=pw

.envに↑みたいに書いてあったら、↓のように書く。

    <php>
        <server name="APP_ENV" value="testing"/>
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <server name="MAIL_DRIVER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <!-- テストで使うDBのスキーマ名 -->
        <server name="DB_DATABASE" value="test_db"/>
        <!-- 接続するuserの名前 -->
        <server name="DB_USERNAME" value="user"/>
        <!-- 接続するuserのパスワード -->
        <server name="DB_PASSWORD" value="pw"/>
    </php>

DBを使うテストファイルを実行してみましょう。

./vendor/bin/phpunit ./tests/Feature/DatabaseTest.php

記事冒頭のエラーで困っていた人は、解決できているハズ!

その他phpunitの準備に役立ちそうな記事

PHPUnitの使い方メモ

MySQLをMacのターミナルで操作するときのメモ

おわりに

DBに接続する時の設定をする、という当然のことをしただけなんですが、人が用意してくれた自動化環境(AWSやらdocke)に慣れてしまうと、触れる機会が少なくなってしまうものです。

こういう基本的なとこに触れるのも、たまにはいいですよね。

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