MySQL – 文字コードを変更したのにエラー

概要

MySQLで日本語入力対策でロケールや文字コードを設定変更しても、なお日本語入力でエラーが出ることがある。

これは、設定変更前にデータベースやテーブルを作成し、後から設定を変更してもcharacter_set_databaselatin1のような状態で残ってしまうため。

また、他の環境で作成したデータベースをCSVで取り込もうとしたとき、文字コードを合わせたのにcollation(照合順序)が違うと怒られてインポートできないという場合がある。

ここでは、既作成のデータベースやテーブルの文字コード、照合順序を変更する手順をまとめる。

現象

文字コードを変更したのに入力できない

ロケールも変更して

MySQLの文字コードも変更して

再起動もしたのに、日本語が入力できてもデータベースに登録できない。

確認

character_set

MySQLの文字コードを確認するのにUSEでデータベースを指定する前に確認したが、データベース指定後に確認した結果が以下。

既作成のデータベースでは、作成時の文字コード設定が残っている。

データベースの文字コード

既作成データベースの文字コード確認。文字コードがlatin1になっている。

テーブルの文字コード

既作成テーブルの文字コード確認。こちらも文字コードがlatin1になっている。

対応

データベースを作りなおす

文字コードがlatin1でまだデータ未入力の段階で発覚したようなときは、一旦dropでデータベースを消して新たに作りなおせば、全体の文字コードに従ったデータベース、テーブルが作成される。

設定を変更する

既にデータが入力されているときに設定を変更したいときは、データベース、テーブルの別に文字コードを変更する。

データベースの文字コードセットを変更する。

テーブルの文字コードセットを変更する。

これでやっと日本語の入力のエラーがなくなった。

 

MySQL – 日本語入力ができない

概要

LinuxのMySQLクライアントからMySQLに対して日本語を入力したとき、以下のような状況となった。

  • 変換中は表示されるが、確定のためEnterを押すと消えてしまう
  • 下記のようにデータベースに登録できない

これを解決するため、OSのロケール設定とMySQLの文字コード設定を変更する。

OSのロケール設定

localeコマンドで現在のロケール設定を確認。デフォルトでCロケールが設定されている。

/etc/profileに以下の2行を追加して再読み込みor再起動。=の前後には空白を入れないこと

設定変更後。

MySQLの文字コード設定

確認方法と指定方法

初期状態のMySQLの文字コードは以下のような状況。

my.cnfmysqlセクションとmysqldセクションにそれぞれ以下を追加。my.cnfの場所は以下のような方法で特定。

  • mysql --help | grep my.cnf
  • find / -name my.sql

この結果文字コード設定は以下のようになり、日本語の入力が可能になった。

コンソールの文字コード

なおこのとき、Windowsホスト上のVagrantをコマンドプロンプトで操作していた。コンソールの文字コードは932(shift_jis)だったが、入力時に文字化けはしなかった。

それでも入力できない

なお、この設定変更をしても、変更前に作成したデータベースに対して入力できない場合がある。

そのようなときは、以下の2つのいずれかの方法をとる。

  • 新たな設定の下で、データベースから作りなおす
  • データベースとテーブルの設定を個別に変更する

Linux – shスクリプト

基本形

例として、ファイル名をscript_testとして以下の内容で作成。

1行目は実行するスクリプトの指定(shebang, sha-bang, hashbang, pound-bang)。

ただしこのままでは実行権限がないので、chmodで実行権限をセットする。

実行する場合、パスを通して入ればファイル名のみで実行できるが、パスを通していなければ絶対パス/相対パスでファイル名を指定する。

引数

スクリプト実行時の引数は、変数'1''2'に格納される。参照する場合は$1${1}など。

実行例

条件分岐

以下は条件分岐の例で、ifcaseのそれぞれで引数に応じた処理を行わせている。

実行例

 

MySQL – 起動しない

概要

稼働していたMySQLに突然ログインできなくなり、MySQLサーバーも起動できない状態となった。

これに関しては様々な対応策がネット上にあり、症状によって効くものと効かないものがあるようだ。

今回は、単にMySQLを消してインストールし直したところ元に戻った。

環境

仮想環境:Vagrant + VirtualBox

OS:bento/freebsd-11.2

MySQL:5.7をpkgでインストール

症状

VagrantのFreeBSD仮想環境にMySQLをインストールして動作していたのに、翌日ログインしようとしたらエラーになった。

導入時にも遭遇した現象で、MySQLサーバーが起動していない。

サーバーを起動しようとするとPIDファイルの更新ができないというエラーで起動できない。これはネット上でも頻出の現象だ。

対応~解決せず

pidファイルが消える

sudo touch.pidファイルをつくってみたが、MySQLサーバーを起動すると同じエラーとなった。起動後に確認すると、つくった.pidファイルがなくなっていた。

プロセスはない

mysql関係のプロセスを見てみたが、実行したgrep以外には動いていない。

pkg clean

/var/chache/pkg下の40ほどのtxzファイルが消されたが、PIDファイルが更新できない、というエラーは変わらない。

対応~解決

MySQLサーバーをアンインストールして、my.cnfを消す。

VagrantをリロードしてMySQLサーバーを再インストール。

この段階ではMySQLサーバーは動いていないが、無事起動に成功。

また、

  • 前に作ったデータベースは残っていた
  • そのままexit→Vagrantリロードすると、サーバーが起動(profileにmysql_enable="YES"を記述しているため)

 

PHP – 対話モード

対話モード

開始

-aオプションをつけてphpコマンドを実行する。

php -a

終了

exit

実行例

日本語が入力できない

phpの対話モードで日本語を入力しようとしたところ、変換候補は表示されるが確定すると消えてしまう。

MySQLでもそのような症状があったが、OSのロケール設定とMySQLの文字コード設定で解決した。

OSのロケールは共通でUTF-8、日本語を含むコードをファイルから実行した場合は問題なく表示される。

原因はわかっていない。

phpコマンドのみの場合

オプション-aをつけずにphpコマンドを入力した場合もスクリプト実行ができるが

  • プロンプトが表示されない
  • Enterを入力しても実行されない
  • exitを入力しても終わらない
  • Ctrl-Cで抜け出せるが抜けるだけ

PHPマニュアルに”–with-readline オプションつきで PHP をコンパイルした場合に CLI SAPI で対話シェルが使えるようになりました。”とあるが、このオプションなしでコンパイルされている?

対応策

以下の2点。

  • PHPの実行タグ<?phpで始める
  • 入力終了後にCtrl-Dを入力する(Ctrl-Dで入力を終了させる)

 

 

 

MySQL – ログインとパスワード変更

ログイン

以下のコマンド入力後にパスワードを入力。

mysql -u username -p

たとえばrootで入る場合。”Enter password:”に対してパスワードを入力する。

パスワード変更

OSプロンプトから

OSのプロンプトに対して、以下のコマンド入力後に変更前のパスワードを入力。

mysqladmin password new_password -u root -p

たとえばrootのパスワードを変更する場合。”Enter password:”に対しては変更前のパスワードを入力する。

MySQLログイン中

MySQLのプロンプトで以下のコマンドを入力。

SET PASSWORD FOR user@host=password('new_password');

たとえばrootのパスワードを変更する場合。

 

Vagrant&VirtualBox – 仮想環境構築・利用の流れ

概要

Vagrant、VirtualBoxをインストール済みとして、個別のvirtualboxの仮想環境の導入・利用・削除の流れをまとめる。

Vagrant Cloudのbento/centos-7.7を導入する場合を例にする。

仮想環境の導入

virtualboxの検索と追加

  1. サイトでvirtualboxを探す
    • bento/centos-7.7を確認
  2. virtualboxを加える
    • vagrant box add bento/centos-7.7
      →ここでvirtualboxやvmwareなど複数のプロバイダーの選択肢が出た場合はvirtualboxを選択
  3. 追加後の確認
    • vagrant box list

ディレクトリーの作成と初期化

  1. 仮想環境ディレクトリーを作成
    • mkdir centos7 & cd centos7 
  2. virtualboxの初期化
    • vagrant init bento/centos-7.7
      →Vagrantfileが作成される

仮想環境の利用

仮想環境の起動と接続

  1. 仮想環境ディレクトリーでVagrantを起動
    • vagrant up
  2. 仮想環境に接続
    • vagrant ssh

仮想環境の停止

  1. 仮想環境のOSを終了(exitなど)
  2. vagrant halt

仮想環境の削除

仮想環境の削除

  1. 仮想環境idの確認
    • vagrant global-status
  2. 仮想環境の削除
    • vagrant destroy id

virtualboxの削除

  1. virtualboxの確認
    • vagrant box list
  2. virtualboxの削除
    1. vagrant box remove bento/centos-7.7

 

Java – 配列 – 同一性・等価性

概要

配列の同一性は変数が指しているインスタンスが同じかどうかのみによるが、等価性の場合は末端の要素一つ一つが等価かどうかを判定することになる。

Javaの配列で等価性を判定する場合、1次元配列はArrays.equals()で等価性を判定できるが、2次元以上の配列になるとArrays.deepEquals()で判定しなければならない。

配列のコピーでもディープコピーができるメソッドがなくループで回さないといけないなど、Javaの配列は使いにくい。というよりも、下手に使うと思わぬところでミスの要因になりそう。

1次元配列

同一性(==)

配列変数が指している対象が同じかどうか。内容が同じでも変数が指しているインスタンスが異なる場合は同一にならない。

以下の例ではarray1array2が同じ配列インスタンスを指している(ハッシュ値が等しい)ので、内容が変わっても同一。

一方で変更前のarray1array4、変更後のarray1array3は、内容が同じでも配列のインスタンスが異なるため、同一とは判定されない。

等価性(Array.equals)

配列の内容が同じかどうか。異なる配列インスタンスでも内容が同じなら等価。同値性とも。

配列の等価性をチェックするにはArrays.equals()メソッドを使う。

以下の例では、array1array2は同一であり等価。array1の変更前はarray3と等価だが、変更後にはarray4と等価になる。

equals()メソッドは要注意

配列もオブジェクトとしてequals()メソッドを備えているが、これは同一性の判定しかせず、等価性の判定には使えない。

以下の例で、結果が==のときと同じになっているのが確認できる。

多次元配列

Array.equals()も要注意

Arrays.equals()clone()の挙動と似ていて、

  • 1次元目の各要素が同一なら結果はtrue
  • 1次元目の各要素のいずれかが同一でないなら結果はfalse

多次元配列でArray.equals()を使うと、2次元目の要素配列が同一であればtrueとなり、同一でなければ内容が同じでもfalseとなる。

以下の例では、

  • array2d1array2d2は元のインスタンスが同一であり等価
  • array2d1からclone()で作られたarray2d3は、元のインスタンスは異なるが、それが指している要素が同じなので同一ではないが等価
  • array2d3array2d4も、元のインスタンスから要素に至るまでarray2d1と異なるため、変更前/変更後に内容が同じになっても等価と判定されない

Arrays.equals()の等価性判定は1次元配列にしか使えない

深層比較(deepEquals)

Arrays.deepEquals()は、引数の2つの配列の要素の等価性を再帰的に判定する。

 

 

Java – 配列 – コピー

概要

Javaにおける配列のコピーについて整理する。

  • 1次元配列はclone()メソッドかSystem.arraycopy()メソッド
  • 多次元配列は次元分forでネストしてclone()System.arraycopy()

Javaの配列は扱いづらく、deepToString()deepEquals()はあるのにdeepCopy()がないのが不思議。

代入(assignment)

配列変数を他の変数に代入した場合、代入先の変数が元の変数と同じ配列を参照する。一方での変更が他方の結果にも反映される。

下記コードで、2つの配列のハッシュ値が同じこと、片方の変更が他方にも反映されることが確認できる。

clone()

clone()メソッドは配列の要素の「内容」を順次コピーして新たな配列を返す。一方の配列への変更は他方に影響しない。プリミティブ型の配列でも使える。

以下のコードで、2つの変数のハッシュ値が異なること、一方の変更が他方に影響していないことが確認できる。

System.arraycopy()

System.arraycopy()メソッドは引数にコピー元・コピー先の配列とコピー位置、コピー長さを指定して、コピー先にはコピー元の要素が複製された新たな配列が与えられる。clone()と同じく、一方の配列への変更は他方に影響しない。

System.copy(元配列, 元開始位置, 先配列, 先開始位置, コピー長)

clone()はシャローコピー

多次元配列をclone()でコピーしてもディープコピーにはならない。一方の配列への変更が他方に影響する。

以下のコードで、1次元目は違うハッシュ値でコピーされているが、それぞれが持っている要素配列はそのままのハッシュ値でコピーされている。

これは、clone()で元の配列の要素(配列)が新たなインスタンスとして複製されるが、その要素は単に代入されるだけで再帰的に複製されないため。

多次元配列のディープコピー

多次元配列をディープコピーするには、最後の要素までclone()で複製する必要がある。

2つの配列を同時に扱うのにPythonのzipのような機能がないので、カウンターで回さないといけない。

 

Java – 配列 – Object配列

概要

Object配列は、任意のオブジェクトを要素とすることができ、異なる型の要素を持つことができる。

1次元のObject配列

イニシャライザー

配列の型をObject[]とすると、任意の型・クラスの値を要素に持つことができる。

newによる初期化

多次元のObject配列

多次元のObject配列をイニシャライザーで宣言することもできるが、ダイナミックに要素を追加していくこともできる。

以下の例では、まず1次元のObject配列を要素数を与えて生成し、1つ目の要素はString型の要素、2つ目と3つ目はObject配列を要素配列として生成してセットしている。