【MySQL】PacketTooBigExceptionの回避方法

## 要約
* MySQLに大きなデータをInsertしようとすると発生する例外“PacketTooBigException“の対応方法を紹介します。
* 記事の後半はMySQL各バージョンの設定値と、関連記事を紹介します。

## PacketTooBigExceptionの発生
MySQLの設定“max_allowed_packet“の設定値を超えた容量のデータをInsertしようとすると発生します。BLOB形式でデータ突っ込むときによく見ますね。

```
Caused by: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (6395830 > 4194304).
You can change this value on the server by setting the max_allowed_packet' variable.
```

## 対応方法
### 1. 設定値の確認
まずは現在の設定値から確認して行きましょう。
`mysql`コマンドでMySQLに接続します。

```shell
mysql -u {ユーザ名} -p -h {ホスト名} -P {ポート番号}
```

MySQLにログイン後、以下のコマンドを実行します。

```shell
mysql> show variables like 'max_allowed_packet';
```

現在の’max_allowed_packet’の設定値が表示されます。

```
+————————————————————+——————————+
| Variable_name      | Value    |
+————————————————————+——————————+
| max_allowed_packet | 4194304  |
+————————————————————+——————————+
1 row in set (0.01 sec)
```

Valueの単位はbyteです。つまり上記は4194304byteですので、4MBですね(4 * 1024 * 1024)。

さて、お次は’max_allowed_packet’の設定値を変更していきましょう。

### 2. MySQLへの設定

ここではコマンドラインでの設定と、設定ファイルmy.cnfを使った設定方法を説明します。

#### コマンドラインでの設定

SET文を使って設定します。
MySQLにログインしたあと、以下のコマンドを実行しましょう。

```shell
# max_allowed_packetを40MBに設定する
mysql> set global max_allowed_packet = 40 * 1024 * 1024;
```

SET文での設定にはグローバル変数、セッション変数の２種類があります。グローバル変数に設定した値は以後接続した全クライアントに影響を与えます。対して、セッション変数は現在の接続中のみの設定です。

ここではmax_allowed_packetの設定を以後も反映させるため、グローバル変数で設定します。`set global`とすることでグローバル変数での設定となります。

値には式を入れることもできますので、41943040（40MB）と入力するより、上記のように“40 * 1024 * 1024“としたほうが見やすくオススメです。

コマンドでの設定は以上です。
コマンドラインでの設定は手軽さが便利ですね。取り急ぎ確認のためだったり、実施が一度きりのときに使えます。

#### プロパティファイルmy.cnfでの設定

プロパティファイルに設定後、MySQLを再起動することによって設定を反映できます。`mysql --help`と入力すると、コマンドの説明とともにmy.cnfの配置場所について記述されています。

```
Default options are read from the following files in the given order:
/etc/my.cnf /etc/mysql/my.cnf /usr/local/etc/my.cnf ~/.my.cnf 
```

左から優先的に採用されるようですね。特になにも無ければ"/etc/my.cnf"でよいと思います。なければ`touch /etc/my.cnf`でa新規にファイルを作成しましょう。作成したファイルに、次のように記載します。

```
[mysqld]
max_allowed_packet=40MB
```

最後にMySQLを再起動して設定値を反映します。

```shell
mysql.server restart
```

プロパティファイルでの設定方法は以上です。
my.cnfは設定値をファイルで管理できるので、複数のサーバで使いまわせる点で便利ですね。

## MySQLバージョン毎の“max_allowed_packet“デフォルト値
MySQLの各バージョンでデフォルト値が異なります。以下、リファレンスマニュアルからの抜粋です。

### MySQL5.6

> サーバーのデフォルトの max_allowed_packet 値は 1M バイトです。

引用元：[MySQL :: MySQL 5.6 リファレンスマニュアル :: B.5.2.10 パケットが大きすぎます](https://dev.mysql.com/doc/refman/5.6/ja/packet-too-large.html)

### MySQL5.7

> The server’s default  [max_allowed_packet](https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_max_allowed_packet)  value is 4MB. 

引用元：[MySQL :: MySQL 5.7 Reference Manual :: B.4.2.9 Packet Too Large](https://dev.mysql.com/doc/refman/5.7/en/packet-too-large.html)

### MySQL8.0

> The server’s default  [max_allowed_packet](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_max_allowed_packet)  value is 64MB.

引用元：[MySQL :: MySQL 8.0 Reference Manual :: B.4.2.9 Packet Too Large](https://dev.mysql.com/doc/refman/8.0/en/packet-too-large.html)

## 関連記事
### Qiita
* [mysql max_allowed_packetを変更する - Qiita](https://qiita.com/_am_/items/91824da643256d46b847)
* [RDSでmax_allowed_packetの値を変更する - Qiita](https://qiita.com/okisanjp/items/7ee6508956e3e0e3914f)
* [mysqldumpのmax_allowed_packetのデフォルト値は24MB - Qiita](https://qiita.com/miyazato_te/items/4a5218d1f54b86375993)

### StackOverflow
* [blob - com.mysql.jdbc.PacketTooBigException - Stack Overflow](https://stackoverflow.com/questions/11320236/com-mysql-jdbc-packettoobigexception)

### 技術系ブログ
* [MySQL　 PacketTooBigException が発生したら、 - Oboe吹きプログラマの黙示録](https://oboe2uran.hatenablog.com/entry/2010/11/01/230828)
* [MySQLで大きなデータを登録しようとするとcom.mysql.jdbc.PacketTooBigException: 発生 - on the center line.](https://kenpoco.hatenadiary.org/entry/20080625/1214375217)
* [MySQLのPacketTooBigException - R42日記](https://takahashikzn.root42.jp/entry/20101112/1289535608)