- 投稿日:2021-06-15T22:37:51+09:00
dockerのmysqlがメモリ不足で落ちたらホストのmysqlもkillされてた
初投稿。 自身のメモも兼ねてこれから書いていく。 何が起きたか 知らない間にoom-killerがmysqlをkillしていた oom-killer (out-of-memory killer): メモリが不足した場合に、適当(適切?)なサービスを選択して問答無用にkillしてくるやつらしい 前提 conoha vpsを使用(メモリ1G) いくつかのwebサービスをvps上に公開 iPadで開発しているので、開発環境もvps上にあり、ssh接続してvimでプログラミングしている vps上の開発環境はdockerを利用 経緯 前提に記載の通り、お金をケチって開発環境と本番環境をひとつのvps上において個人開発をしている。 メモリが1Gのプランなので、docker内で少し重い処理をしたりdocker imageをビルドしまくってたりするとメモリがギリギリになることが多々ある状態。 dockerのmysqlでエラーコード137が発生 普段通り開発を進めていると、dockerのmysqlとアプリとの接続がよく切れるように。 ログを見ると docker mysql exited with code 137 メモリ不足のため落ちてしまっているよう。 dockerを再起動したり不要なプロセスをkillしたりして凌いでいた(vpsのプランを上げる発想はない)。 本番のアプリでエラーが発生 リリース済みアプリでエラーが出ていると利用者のメールにて発覚。 調べてみるとDBにアクセスできていない状態で、本番側のmysqlが落ちていた。 oom-killerという存在を知る dockerのmysqlが落ちることは認識していたが、本番環境のmysqlは触ってないし、なぜ落ちていたのかわからないでいた。 ポートがバッティングしているのかと確認したが、dockerのポートも開いておらず。 とりあえずmysqlを再起動して復帰したのち、とりあえずdockerが落ちないようにする方法を調べていると、その過程でoom-killerという存在を知る。 メモリが枯渇すると、osがメモリを消費しているサービスを良しなに選択してkillし、メモリを確保するらしい。 topコマンドでメモリ使用状況を確認しても、本番環境のmysqlは特に問題なさそうだったが、ログを調査しきれていないので詳しくはわかっていないが、 dockerでメモリを過剰に使用 mysqlのdockerがメモリ不足で落ちる ホストのoom-killerも動き、何故かmysqlが狙われてkillされる という流れが起きているぽい(1度だけじゃなく何度も遭遇) 対策 メモリ削減のためmy.confに追記 メモリをなるべく消費しなければoom-killerの対象ではなくなるはずなので、 本番環境とdocker双方のmysqlの設定を見直す。 # /etc/my.conf performance_schema = off table_definition_cache = 400 performance_shcema いろんな情報が見れる設定らしい(詳しくまだ調べてない)が、メモリをかなり食うらしい。 offにしてメモリ消費量を減らす。 table_definition_cache これもメモリ対策でよく取り上げられているぽい。 デフォルト2000らしいが、400にしている方が多いので倣う。 oom-killerの対象からmysqlを外す ちゃんと調べられてないが、任意のサービスをoom-killerの対象から外せるらしい。 DBは絶対に落とせないサービスの一つなので、調べて設定しよう。 本番と開発でサーバを分ける そもそもだが、開発中にdockerのリビルドやコード不備によるメモリ使用量増はやり得るはずなので、 それが本番環境に影響を与えるのはそもそも不味い。 多少お金がかかっても開発は開発用で別途サーバを用意しましょう(戒め)。 awsのec2で従量課金にすれば少しは費用が抑えられる認識。 まとめ docker使っとけば何をしても棄てれば許されると思って本番環境と開発環境を一つのサーバで運用してしまっていたが、 メモリ枯渇で本番環境に影響を与えてしまうとは思ってなかった。 開発環境は本番環境から外だししましょう。
- 投稿日:2021-06-15T19:30:46+09:00
MySQL CLIでrootログインできなくなった時の話
MySQLでrootのパスワード忘れたという話は結構あると思いますが、自分の場合、パスワード忘れたわけでもないのにログインできなくなってハマったという話です。一言で結論を言うと、認証のplugin欄がなぜかrootだけ空になってました。なんでや。rootパスワード再設定してもログインできない人はpluginのカラムを見てみましょう。 それだけではなんなので。 rootパスワードがわからなくなった場合のよくある対処法は、セーフモードで起動してmysql.userテーブルのpassword(場合によってはauthentication_string)を手動でUPDATEするという感じです。うちはDebian(stretch)なので多少よそとコマンドが違うかもしれないから、手順を備忘録として書き記しておきます。 具体的な手順 1.MySQLの停止 $ sudo service mysql stop 2.セーフモードでの起動 $ mysqld_safe --skip-grant-tables & &はバックグラウンドでプロセスを走らせておくと言う意味。--skip-grant-tablesで権限に関する動作を停止する。この間はMySQLでSHOW GRANTなどの権限関係のコマンドは実行できない。 ここで'/var/run/mysqld' for UNIX socket file don't exists.というエラーが出るときは次の操作をしてから再度上を実行する。 $ sudo mkdir /var/run/mysqld $ sudo chown mysql:mysql /var/run/mysqld 3.MySQLへログイン $ mysql -u root 4.パスワードとpluginをUPDATE USE mysql UPDATE user SET authentication_string='パスワード' WHERE User='root'; UPDATE user SET plugin='mysql_native_password' WHERE User='root'; FLUSH PRIVILEGES; 2行目のauthentication_stringが古いバージョン(確かMySQL 5.7.5以前らしい)の場合はカラム名が違うので2行目はこちらを実行 UPDATE user SET password=password('パスワード') WHERE User='root'; 5.確認してMySQLからログアウト SELECT User, Host, plugin FROM user WHERE User='root'; これでplugin欄にmysql_native_passwordになっていることを確認する。なお、認証Pluginは最新のものにcaching_sha2_passwordがあるが、これに対応していないソフトがある様子。PhpMyAdminとか。 確認して問題無かったらMySQLから出る。 quit 6.セーフモードのバックグラウンドプロセスを停止させる このままMySQLを停止〜再起動させる手順もあるようだが、自分の環境ではセーフモードのバックグラウンンドプロセスが走ったままだったので、これを停止させてからでないと再起動しなかった。 $ sudo pkill -f mysql 7.MySQLを起動し、rootでログインできるかどうか試す $ sudo service mysql start $ mysql -u root -p パスワードを入力 これでログインできたらOK。いやしかしなんで認証pluginが空欄になったのか全くわからない。CMS用に作ったユーザーとかは消えてないのに。 参考 大変参考になりました。多謝。 - Ubuntu 18.04 で MySQL 8 で root パスワードを忘れたときの再設定方法 - How To Reset Your MySQL or MariaDB Root Password *こちらはMariaDBの場合やバージョン違いの場合も丁寧に書いています。
- 投稿日:2021-06-15T17:57:40+09:00
DockerでMySQLコンテナがRestartingになる現象
発生した事象 Remove MYSQL_USER="root" and use one of the following to control the root user password: - MYSQL_ROOT_PASSWORD - MYSQL_RANDOM_ROOT_PASSWORD ログにこんなのが出てステータスはRestartingのまま。 解決方法 バージョンを固定する。 Dockerfile FROM mysql:5.6 ↓ FROM mysql:5.6.XX
- 投稿日:2021-06-15T17:46:17+09:00
Raspberry PIでPython WEB#3(DB編)
概要 今回はMySQLDBを利用して簡単なCRUDコードを作成したいと思います。 MySQLライブラリはSQLAlchemyというものを使用します。 ※MySQLサーバーのバージョンが「5.5.54」ですが、下記の事前作業には最新MySQLをインストールするコマンドをいれました。 事前作業 ①次のコマンドでSQLAlchemyをインストールします。 # Python環境駆逐 sudo apt-get install python2.7-dev python3-dev # MySQLサーバインストール sudo apt-get install mariadb-server-10.0 sudo apt-get install python-mysqldb # DBライブラリ pip3 install sqlalchemy # 次のエラーが発生し、インストールします。 # ModuleNotFoundError: No module named 'MySQLdb' pip3 install mysqlclient ②データベース及びテーブル作成 ※テーブル作成についてはboard.pyからも作成ができます。 # データベース作成 CREATE DATABASE testDB; # テーブル作成SQL CREATE TABLE `boards` ( `id` INTEGER NOT NULL AUTO_INCREMENT, `title` varchar(100) DEFAULT NULL, `body` varchar(200) DEFAULT NULL, `writer` varchar(50) DEFAULT NULL, `email` varchar(100) DEFAULT NULL, `password` varchar(50) NOT NULL, PRIMARY KEY(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; サンプルソース作成 ①以下3つのファイルを作成します。 # file name : setting.py # pwd : /home/pi/work/setting.py from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declarative_base # mysqlのDBの設定 DATABASE = 'mysql://%s:%s@%s/%s?charset=utf8' % ( "flaskweb", # username "flaskweb123", # password "192.168.1.25", # host "testDB", # database name ) ENGINE = create_engine( DATABASE, encoding = "utf-8", echo=True # Trueだと実行のたびにSQLが出力される ) # Sessionの作成 session = scoped_session( # ORM実行時の設定。自動コミットするか、自動反映するなど。 sessionmaker( autocommit = False, autoflush = False, bind = ENGINE ) ) Base = declarative_base() Base.query = session.query_property() # file name : board.py # pwd : /home/pi/work/board.py import sys from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, Float, DateTime from setting import Base from setting import ENGINE class Board(Base): __tablename__ = 'boards' id = Column('id', Integer, primary_key = True) title = Column('title', String(100)) body = Column('body', String(200)) writer = Column('writer', String(50)) email = Column('email', String(100)) password = Column('password', String(50), nullable=False ) # NOT NULLの指定方法 def main(args): Base.metadata.create_all(bind=ENGINE) if __name__ == "__main__": main(sys.argv) # file name : main.py # pwd : /home/pi/work/main.py from setting import session from board import * board = Board() board.title = 'title1' board.body = 'test body1' board.writer = 'tester' board.email = 'test@localhost' board.password = '1111' session.add(board) session.commit() # query関連の条件指定は参考サイトを参照してください。 boards = session.query(Board).all() for board in boards: print(board.title) ~ テーブル作成 次のコマンドでテーブル作成ができます。 ※テーブル作成後に該当DDLも表示ができました。 pi@raspberrypi:~/work $ python3 board.py 2021-06-15 09:04:06,377 INFO sqlalchemy.engine.Engine SHOW VARIABLES LIKE 'sql_mode' 2021-06-15 09:04:06,378 INFO sqlalchemy.engine.Engine [raw sql] () 2021-06-15 09:04:06,380 INFO sqlalchemy.engine.Engine SHOW VARIABLES LIKE 'lower_case_table_names' 2021-06-15 09:04:06,380 INFO sqlalchemy.engine.Engine [generated in 0.00040s] () 2021-06-15 09:04:06,383 INFO sqlalchemy.engine.Engine SELECT DATABASE() 2021-06-15 09:04:06,384 INFO sqlalchemy.engine.Engine [raw sql] () 2021-06-15 09:04:06,386 INFO sqlalchemy.engine.Engine BEGIN (implicit) 2021-06-15 09:04:06,388 INFO sqlalchemy.engine.Engine SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = %s AND table_name = %s 2021-06-15 09:04:06,388 INFO sqlalchemy.engine.Engine [generated in 0.00043s] ('testDB', 'boards') 2021-06-15 09:04:06,392 INFO sqlalchemy.engine.Engine CREATE TABLE boards ( id INTEGER NOT NULL AUTO_INCREMENT, title VARCHAR(100), body VARCHAR(200), writer VARCHAR(50), email VARCHAR(100), password VARCHAR(50) NOT NULL, PRIMARY KEY (id) ) 2021-06-15 09:04:06,392 INFO sqlalchemy.engine.Engine [no key 0.00038s] () 2021-06-15 09:04:06,406 INFO sqlalchemy.engine.Engine COMMIT データ登録 次のコマンドで1つのレコードが登録できます。 ※レコードの登録と最後に登録されたレコードのタイトルのみ表示しています。 pi@raspberrypi:~/work $ python3 main.py 2021-06-15 09:07:08,710 INFO sqlalchemy.engine.Engine SHOW VARIABLES LIKE 'sql_mode' 2021-06-15 09:07:08,710 INFO sqlalchemy.engine.Engine [raw sql] () 2021-06-15 09:07:08,713 INFO sqlalchemy.engine.Engine SHOW VARIABLES LIKE 'lower_case_table_names' 2021-06-15 09:07:08,713 INFO sqlalchemy.engine.Engine [generated in 0.00038s] () 2021-06-15 09:07:08,716 INFO sqlalchemy.engine.Engine SELECT DATABASE() 2021-06-15 09:07:08,717 INFO sqlalchemy.engine.Engine [raw sql] () 2021-06-15 09:07:08,719 INFO sqlalchemy.engine.Engine BEGIN (implicit) 2021-06-15 09:07:08,723 INFO sqlalchemy.engine.Engine INSERT INTO boards (title, body, writer, email, password) VALUES (%s, %s, %s, %s, %s) 2021-06-15 09:07:08,723 INFO sqlalchemy.engine.Engine [generated in 0.00045s] ('title1', 'test body1', 'tester', 'test@localhost', '1111') 2021-06-15 09:07:08,725 INFO sqlalchemy.engine.Engine COMMIT 2021-06-15 09:07:08,733 INFO sqlalchemy.engine.Engine BEGIN (implicit) 2021-06-15 09:07:08,740 INFO sqlalchemy.engine.Engine SELECT boards.id AS boards_id, boards.title AS boards_title, boards.body AS boards_body, boards.writer AS boards_writer, boards.email AS boards_email, boards.password AS boards_password FROM boards 2021-06-15 09:07:08,740 INFO sqlalchemy.engine.Engine [generated in 0.00045s] () title1 DBを確認 次のコマンドで登録されたレコードを確認します。 pi@raspberrypi:~/work $ mysql -uflaskweb -pflaskweb123 testDB Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 62 Server version: 5.5.54-0+deb8u1 (Raspbian) Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> select * from boards; +----+--------+------------+--------+----------------+----------+ | id | title | body | writer | email | password | +----+--------+------------+--------+----------------+----------+ | 1 | title1 | test body1 | tester | test@localhost | 1111 | +----+--------+------------+--------+----------------+----------+ 1 row in set (0.00 sec) mysql> 参考 ①【PythonのORM】SQLAlchemyで基本的なSQLクエリまとめ https://qiita.com/tomo0/items/a762b1bc0f192a55eae8 ・DB接続及びテーブルのモデル作成、データの登録及び条件指定方法など参照 ②SQLAlchemy で Update するには? https://qiita.com/nskydiving/items/745f985a42da89a16934 ・全データ削除、一括登録、更新内容を参照 終わりに 午前中まではPyMySQLを利用して調べていましたが、 SQLAlchemyの方が以下のメリットがありましたので、このライブラリに決めました。次回はWEBに連動してCRUDの掲示板を作成してみたいと思います。 ■メリット ・SQLに該当するロジックを書くこと。 ・MYSQL、SQL、PostgreSQLの特殊なSQL文を気にしなくてもよいこと。 ・DBMSが変更されてもSQL内容の変更は不要。(接続文字列関連のロジックは修正が必要) ■デメリット ・SQLをコードで書いてあるため、デバッグするのがちょっと不便かもです。
- 投稿日:2021-06-15T16:52:16+09:00
[SQL]すっきりわかるSQL入門のまとめ
はじめに 昨日から「スッキリわかるSQL入門」を参考に学び始めたのでこちらにまとめていきます。 以前書いた記事と似ている部分がありますが、復習と捉えていただければと思います。 ※こちらは教材ではないので、ストーリー性のないまとまり方をしてます。 ※参考図書を丸写しするなどはしておりません。 基本の4大命令 SQLにおける基本的な4大命令文 SELECT SELECT カラム名 FROM テーブル名 WHERE 条件~~ INSERT INSERT INTO テーブル名(カラム1,カラム2....) VALUES(値1,値2....) UPDATE UPDATE テーブル名 SET カラム=値 WHERE 条件〜〜〜 DELETE DELETE FROM テーブル名 検索結果の加工 WHEREのような修飾の中で、SELECTにしかつけられないものを紹介します。 DISTINCT 結果表内で内容が重複しているものを除く SELECT DISTINCT カラム FROM テーブル名 ORDER BY 並び替えを行う。デフォルトでは昇順になっていて指定は省略できるが、降順にする際は指定が必要。また、複数の列を基準に並び替えを行うことも可能。 なお、列番号による指定も可能。 SELECT カラム名 FROM テーブル WHERE ~~ ORDER BY カラム名 DESC(ASC) OFFSET -FETCH 先頭から○行目を起点に、△行だけ表示する。LIMITとよく似ている。 SELECT * FROM テーブル名 WHERE ~ ORDER BY ~ OFFSET 先頭から除外する行数 ROWS FETCH NEXT 表示する行数 ROWS ONLY 集合演算子 検索結果の加工では集合演算子なるものがある。 UNION 和集合を求める。 SELECT ~~ UNION (ALL) SELECT ~~ ORDER BY ~~ EXCEPT 差集合を求める。 SELECT ~~~ EXCEPT SELECT ~~~ INTERSECT 積集合を求める。 SELECT ~~ INTERRSECT SELECT ~~ 演算子と関数 CASE演算子 これはもうRubyでもC言語でもさんざんぱらやってきたので説明は割愛。 記述例は以下。 SELECT 費目, 出金額, CASE 費目 WHEN '家賃' THEN '固定費' WHEN '光熱費' THEN '固定費' ELSE '変動費' END AS 出費の分類 FROM 家計簿 SELECT 費目,入金額, CASE WHEN 入金額 < 10000 THEN '仕送り' WHEN 入金額 < 20000 THEN 'バイト代' ELSE `一時的な収入` END AS 収入ジャンル FROM 家計簿 関数 LENGTH関数 文字列の長さを返す。 LENGTH(引数) TRIM 対象文字列の左右の空白を削除 TRIM(文字列) REPLACE 置換する REPLACE(置換対象文字列(カラムとか),置換前の文字列,置換後の文字列) SUBSTRING 文字の抽出。 SUBSTRING(対象文字列,抽出開始位置,抽出終了位置) CONCAT 文字列を連結する関数 CONCAT(文字列,文字列) ROUND 指定桁で四捨五入 ROUND(数値、有効桁数) --有効桁数は正の場合は少数部分の桁数、負の場合は整数桁数 TRUNC 指定桁で切り捨てる TRUNC(数値、有効桁数) POWER べき乗する POWER(数値、何乗するかを指定する数値) CURRENT_DATE 現在の日付を得る関数で、現在の時刻を得たい場合は、CURRENT_TIME関数を使用する。 COALESCE関数 最初に登場するNULLでない値を返す。これについては、以下が分かりやすい。 書体コードがもともと割り振られており、一部のレコードではそれが欠損してNULLとなっている。 二行目のコアレス関数では、欠損がなければそのままの値を返し、欠損(NULL)していれば1を返す仕組みとなっている。 SELECT 受注日, 受注ID, 文字数, CASE COALESCE(書体コード, '1') WHEN '1' THEN 'ブロック体' WHEN '2' THEN '筆記体' WHEN '3' THEN '草書体' END AS 書体名, FROM 受注 ORDER BY 受注日, 受注ID おわり かなりざっくりまとめました。 引き続き学習を進めていきます。
- 投稿日:2021-06-15T16:52:16+09:00
[SQL]すっきりわかるSQL入門のまとめ①
はじめに 昨日から「スッキリわかるSQL入門」を参考に学び始めたのでこちらにまとめていきます。 以前書いた記事と似ている部分がありますが、復習と捉えていただければと思います。 ※こちらは教材ではないので、ストーリー性のないまとまり方をしてます。 ※参考図書を丸写しするなどはしておりません。 基本の4大命令 SQLにおける基本的な4大命令文 SELECT SELECT カラム名 FROM テーブル名 WHERE 条件~~ INSERT INSERT INTO テーブル名(カラム1,カラム2....) VALUES(値1,値2....) UPDATE UPDATE テーブル名 SET カラム=値 WHERE 条件〜〜〜 DELETE DELETE FROM テーブル名 検索結果の加工 WHEREのような修飾の中で、SELECTにしかつけられないものを紹介します。 DISTINCT 結果表内で内容が重複しているものを除く SELECT DISTINCT カラム FROM テーブル名 ORDER BY 並び替えを行う。デフォルトでは昇順になっていて指定は省略できるが、降順にする際は指定が必要。また、複数の列を基準に並び替えを行うことも可能。 なお、列番号による指定も可能。 SELECT カラム名 FROM テーブル WHERE ~~ ORDER BY カラム名 DESC(ASC) OFFSET -FETCH 先頭から○行目を起点に、△行だけ表示する。LIMITとよく似ている。 SELECT * FROM テーブル名 WHERE ~ ORDER BY ~ OFFSET 先頭から除外する行数 ROWS FETCH NEXT 表示する行数 ROWS ONLY 集合演算子 検索結果の加工では集合演算子なるものがある。 UNION 和集合を求める。 SELECT ~~ UNION (ALL) SELECT ~~ ORDER BY ~~ EXCEPT 差集合を求める。 SELECT ~~~ EXCEPT SELECT ~~~ INTERSECT 積集合を求める。 SELECT ~~ INTERRSECT SELECT ~~ 演算子と関数 CASE演算子 これはもうRubyでもC言語でもさんざんぱらやってきたので説明は割愛。 記述例は以下。 SELECT 費目, 出金額, CASE 費目 WHEN '家賃' THEN '固定費' WHEN '光熱費' THEN '固定費' ELSE '変動費' END AS 出費の分類 FROM 家計簿 SELECT 費目,入金額, CASE WHEN 入金額 < 10000 THEN '仕送り' WHEN 入金額 < 20000 THEN 'バイト代' ELSE `一時的な収入` END AS 収入ジャンル FROM 家計簿 関数 LENGTH関数 文字列の長さを返す。 LENGTH(引数) TRIM 対象文字列の左右の空白を削除 TRIM(文字列) REPLACE 置換する REPLACE(置換対象文字列(カラムとか),置換前の文字列,置換後の文字列) SUBSTRING 文字の抽出。 SUBSTRING(対象文字列,抽出開始位置,抽出終了位置) CONCAT 文字列を連結する関数 CONCAT(文字列,文字列) ROUND 指定桁で四捨五入 ROUND(数値、有効桁数) --有効桁数は正の場合は少数部分の桁数、負の場合は整数桁数 TRUNC 指定桁で切り捨てる TRUNC(数値、有効桁数) POWER べき乗する POWER(数値、何乗するかを指定する数値) CURRENT_DATE 現在の日付を得る関数で、現在の時刻を得たい場合は、CURRENT_TIME関数を使用する。 COALESCE関数 最初に登場するNULLでない値を返す。これについては、以下が分かりやすい。 書体コードがもともと割り振られており、一部のレコードではそれが欠損してNULLとなっている。 二行目のコアレス関数では、欠損がなければそのままの値を返し、欠損(NULL)していれば1を返す仕組みとなっている。 SELECT 受注日, 受注ID, 文字数, CASE COALESCE(書体コード, '1') WHEN '1' THEN 'ブロック体' WHEN '2' THEN '筆記体' WHEN '3' THEN '草書体' END AS 書体名, FROM 受注 ORDER BY 受注日, 受注ID おわり かなりざっくりまとめました。 引き続き学習を進めていきます。
- 投稿日:2021-06-15T13:20:11+09:00
Node.jsのMySQLでINSERTしたレコードを取得したい時
課題 Node.jsのMySQLライブラリで INSERTした後のレスポンスにレコードの情報が返却されるのかと思っていたら そうでは無かったので、調べました。 テーブル情報 テーブル名 table_name カラム情報 id:Auto increments age:Int 解決方法 const [result] = await mysql.execute( `INSERT INTO table_name age VALUES 26`,[]); const [rows] = await mysql.execute( `SELECT * FROM table_name WHERE id = ${result.insertId};`,[]); console.log(rows[0]); 解説 INSERTのSQLのレスポンス値にinsertIdという項目があり、 これがテーブルのidの値が返ってくるようだったので、 それを使用してSELECTしている。
- 投稿日:2021-06-15T08:06:17+09:00
SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\x8D\xB8 !...' for column 'message' at row 1 in ...
はじめに PDOでデータベースに絵文字が含まれている文字列をデータベースに保存しようとした際にSQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\x8D\xB8 !...' for column 'message' at row 1 in ...というエラーがでしまいました。 こちらの方の対応方法を備忘録として残しておこうと思います。 対応方法 原因としてはutf8のデータベースにutf8mb4の絵文字を保存しようとしていたのエラーが出ていました。 utf8は3バイトしか対応していない 絵文字は4バイト PDOのインスタンスを作るときにcharsetをutf8mb4で指定してあげると無事に保存することができました。 try { $dbh = new PDO('mysql:host=localhost; dbname=procir_suizu266; charset=utf8mb4', 'suizu266', 'c3mbe7kmfj'); } catch (PDOException $e) { echo 'DB接続エラー:' . $e->getMessage(); die(); }