Minecraft+SpigotサーバーでMySQLを使ってユーザーデータを保存する

# 目的
Minecraft + spigot + MySQLを組み合わせてログインしたユーザーのデータを保存します。

RPGサーバーを作っているときに、ユーザーのデータを保存する必要が出てきたため、下記のような方法で行いました。

# MySQL

## インストール

Macの場合は

```
brew install mysql
```

Windowsの場合は
[Windows環境でMySQL - Qiita](http://qiita.com/yuann/items/6d4a93139315a485e127)

## データベース&テーブルを作成

この後書くサンプルプログラムは以下のようにデータベースとテーブルを作成しています。

MySQLにログイン後

データベース作成

```sql
create database test_database;
```

テーブル作成

```sql
create table players(name varchar(20), uuid varchar(20));
```

# Plugin
※ importは省略して書いてあります

```Main.java
public class Main extends JavaPlugin {

    @Override
    public void onEnable() {
        new PlayerListener(this);
    }

    @Override
    public void onDisable() {
    }


}
```

MainでPlayerListenerを宣言しておきます。


```PlayerListener.java
public class PlayerListener implements Listener {
    public PlayerListener(Main plugin) {
        plugin.getServer().getPluginManager().registerEvents(this, plugin);
    }

    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent event) {
        Player player = event.getPlayer();
        StatusRecord statusRecord = new StatusRecord();
        Status status = statusRecord.savePlayer(player);
    }
}
```


これによってプレイヤーがログインした時にonPlayerJoinに書いてある部分が実行されるようになります。
getPlayer()でログインしたプレイヤーを取得して、
このあと説明するStatusRecordクラスのsavePlayer(player)でユーザーのデータをMySQLに保存しています。


```StatusRecord.java
public class StatusRecord {

    private Connection connection;
    private String host, database, username, password;
    private int port;

    public StatusRecord() {
        host = "localhost";
        port = 3306;
        database = "test_database";
        username = "root";
        password = "";
    }

    public void savePlayer(Player player) {
        try {
            openConnection();
            String name = player.getName();
            UUID uuid = player.getUniqueId();

            String sql = "INSERT INTO players (name, uuid) VALUES (?, ?);";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, name);
            preparedStatement.setString(2, uuid.toString());

            preparedStatement.executeUpdate();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private void openConnection() throws SQLException, ClassNotFoundException {
        if (connection != null && !connection.isClosed()) {
            return;
        }

        synchronized (this) {
            if (connection != null && !connection.isClosed()) {
                return;
            }
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database, this.username, this.password);
        }
    }
}
```

MySQLのユーザー名とパスワード等の設定は以下のところを変えてください

```java
    public StatusRecord() {
        host = "localhost";
        port = 3306;
        database = "test_database";
        username = "root";
        password = "";
    }
```


SQLのINSERT文は個々で発行しています

```java
            String sql = "INSERT INTO players (name, uuid) VALUES (?, ?);";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, name);
            preparedStatement.setString(2, uuid.toString());

            preparedStatement.executeUpdate();
```

?はプレースホルダです。

ここで発行したいSQL文は

```sql
INSERT INTO players (name, uuid) VALUES (ユーザーの名前, ユーザーのUUID);
```

なので、

`preparedStatement.setString(1, name)`といった感じでプレースホルダに代入しています。


# 確認

Spigotのpluginディレクトリにbuildしたjarファイルを入れて、サーバーを起動しログインすると、データが保存されているはずです

```sql
mysql> use test_database;
Database changed

mysql> select * from players;
+-------+--------------------------------------+
| name  | uuid                                 |
+-------+--------------------------------------+
| User  | de6e193c-1a04-436d-ad2a-87727d0df335 |
+-------+--------------------------------------+
3 rows in set (0.00 sec)
```

# 拡張
これを利用してユーザーのいろいろな情報を保存できるようになります。
（RPGサーバーなら、パラメータ値など）
その場合、DBからデータを取り出す作業が必要になるのですが、別の機会にまとめてみようと思います。（現在試行錯誤中です；；）

あと、DBをガリガリつかうサーバーならO/Rマッパー導入したほうが良いかもしれないです。

こうすればいいよとかあればアドバイスお願いします！

# 参考
* [Connecting to databases - MySQL | SpigotMC - High Performance Minecraft](https://www.spigotmc.org/wiki/connecting-to-databases-mysql/)
* [SQLインジェクション対策(Java編) | Webセキュリティの小部屋](https://www.websec-room.com/2013/03/03/387)