MySQLのConnector/J (JDBC)のconnectTimeoutとsocketTimeout #MySQL

MySQLのConnector/J (JDBC)にはconnectTimeoutとsocketTimeoutのパラメータがあり、JDBCの接続文字列に追加することで設定できる。

MySQL :: MySQL Connector/J 5.1 Developer Guide :: 5.1 Driver/Datasource Class Names, URL Syntax and Configuration Properties for Connector/J

設定例

値はどちらもミリ秒で設定できる。

どちらも30秒で設定する場合、下記のようになる。

jdbc:mysql://localhost:3306/sample?connectTimeout=30000&socketTimeout=30000

socketTimeoutの注意事項

socketTimeoutはアプリケーションからMySQLの応答が設定値を超えて待機すると、java.net.SocketTimeoutException に類する例外が発生するようになる。

こんな感じ。

Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet successfully received from the server was 30,031 milliseconds ago.  The last packet sent successfully to the server was 30,030 milliseconds ago.

ここで注意しないといけないのは、単純に重いクエリを投げた場合でも、SocketTimeoutとして扱われてしまうこと。

例えばバッチ処理なんかで30秒以上かかるクエリをアプリから放り投げると例外が発生してしまう。

感想

DBはDBで死活監視、アプリはアプリで死活監視を入れてあるのを前提とすると、JDBCのパラメータでタイムアウト設定するよりは、アプリ側で使っているDBCP管理のAPIを経由する使うのがよいと思う。

ConnectTimeoutの設定値は大体ある気がするし、DBの死活監視がされているならアプリ側ではクエリタイムアウトの管理でよいかと思う。

JDBCのパラメータまで使い始めると、ただでさえ繁雑になりがちなタイムアウト値の管理がもっと複雑になってしまうような気がする。

mysqlのdockerイメージを使ってみた #MySQL #docker

概要

DockerHubにあるMySQLの公式イメージを使ってみた。

※Docker for Mac使用

https://hub.docker.com/_/mysql/

イメージを持ってくる

5.6のイメージを使ってみることにする。

$ docker pull mysql:5.6

ダウンロードを確認

$ docker images

起動する

とりあえず13306ポートでrunしてみる

docker run \
  -d \
  --name mysql-docker \
  -p 13306:3306 \
  --env MYSQL_ALLOW_EMPTY_PASSWORD=yes \
  mysql:5.6

MYSQL_ALLOW_EMPTY_PASSWORD=yes としておくことで、パスワード無しで接続できる。

dockerで初期設定っぽいものをパラメータ的に渡すのは環境変数を使うのがセオリーなのかな?

mysqlコマンドで繋いでみる

MySQLはデフォルトポート以外を使う場合、localhostでは接続できないので、IPでつなぐ。

$ mysql -u root -h 127.0.0.1 -P 13306
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.37 MySQL Community Server (GPL)

設定ファイルを使う

自前の設定を使う場合、設定ファイルの配置場所をDocker側にマウントさせる。

たとえば設定ファイルが /my/custom/config-file.cnf の場合なら --volume /my/custom/config-file.cnf:/etc/mysql/conf.d を指定する。

volumeオプションは相対パスだとうまく動かなくて、どうやら絶対パスじゃないとダメなようだ。

docker run \
  -d \
  --name mysql-docker \
  -p 13306:3306 \
  --env MYSQL_ALLOW_EMPTY_PASSWORD=yes \
  --volume /my/custom/config-file.cnf:/etc/mysql/conf.d \
  mysql:5.6

mysqlにつないだら show variables とかで設定ファイルの内容が反映されているか確認できる。

パス系の設定は注意

無邪気に出来合いの設定ファイルを渡すとうまく動かなかったり、コンテナが終了したりする。

ログファイルの場所など、パスが絡む設定はそのままだと使えなそう。

とりあえず必要ならコンテナの中に入って参照すればいいと思うので、渡す設定からは外すことにした。

まとめ

他にも起動時にデータベースを作成することもできたり、初期SQLを流し込んだりもできるみたい。

公式のイメージを使ってやりたいことは一通りできそうなので、とても便利である。

忘れそうなのでGitHubに残しておいた。

GitHub - su-kun1899/mysql: mysql 関連の置き場

参考

dqn.sakusakutto.jp

Macにdelveを導入する #golang

goのデバッグができるというdelveの導入を試みる。

基本こいつにしたがってやってみた。

github.com

brewしてみる

$ brew install go-delve/delve/delve

キーチェインに証明書を追加

こちらを参考に。

github.com

dlv-cert.cfg を作成

[ req ]
default_bits            = 2048                  # RSA key size
encrypt_key             = no                    # Protect private key
default_md              = sha512                # MD to use
prompt                  = no                    # Prompt for DN
distinguished_name      = codesign_dn           # DN template
[ codesign_dn ]
commonName              = "dlv-cert"
[ codesign_reqext ]
keyUsage                = critical,digitalSignature
extendedKeyUsage        = critical,codeSigning

鍵を作ってキーチェインに追加

$ openssl req -new -newkey rsa:2048 -x509 -days 3650 -nodes -config dlv-cert.cfg -extensions codesign_reqext -batch -out dlv-cert.cer -keyout dlv-cert.key
$ sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain dlv-cert.cer
$ sudo security import dlv-cert.key -A -k /Library/Keychains/System.keychain

インストールを確認

$ dlv version
Delve Debugger
Version: 1.0.0-rc.1
Build:

VSCodeで使いたい

どうも使えるらしいのだけれど、なんかうまく行かなくて挫折した。

↓の記事を参考にやってみてもいいかもしれない(試してない) dev.classmethod.jp

VSCodeで発生したエラー

could not launch process: exec: “lldb-server”: executable file not found in $PATH

このエラーはxcode-selectをインストールすると直るらしい。

$ xcode-select --install

JJUG CCC 2017 Fall CfPに応募してみた #jjug_ccc

初心者枠があったので、ダメ元で応募してみた。

JJUG CCC 2017 Fall CfP 募集開始しました | 日本Javaユーザーグループ

参考にしたもの

CfPどうやって書くのがいいかな、って思ってたら同僚が色々教えてくれた。

その中でも特に参考になったもの。

blog.builderscon.io

builderscon.io

yapcasia.org

なんとなく、分かりやすくて聞いてみたいと思うものは下記の流れになっている気がする。

  1. 想定している聴講者の多くが気にしているであろうことを挙げる
  2. そこに対して問題提起をする
  3. 問題に対する意見であったり解決策を話すよ

誰に何を話したいかが明確になっているから、分かりやすいのだろう。

最終的に提出したもの

恥ずかしいけど、残しておく。

タイトル

SpringBootとMyBatisでデータベースを可視化する

概要

レガシーで大規模なシステムを目の前にした時、まずデータ構造を抑えるのは最重要事項ともいえます。 しかしそういった現場ではドキュメントが追いついていないことも多く、情報のサルベージにそもそも時間を取られてしまうのが実情ではないでしょうか。 私が参画したプロジェクトにも、メンテナンスが行き届いているとはいえないExcelのエンティティ定義書があるだけでした。

ドキュメントは多くの場合プロダクト開発のインプットとして生まれますが、サービスが継続していくに従って現状を可視化する役割へと変化していきます。 現在は多くの可視化ツール・サービスがありますが、とはいえレガシーなシステムではそのスキームに乗れないことも数多くあります。

そんなとき、SpringBootは強力な味方になりえます。 私はSpringBootとMyBatisを使ってデータベースのメタ情報を可視化するWebアプリケーションを作成しました。

本発表ではその経験を元に、現状を技術で可視化することの重要性、SpringBootやMyBatisの強力さ、現場改善のヒントをお話できればと思います。

SpringBoot+MyBatisでRDBMS毎にSQLを切り替える #mybatis

概要

RDBMS毎(例えばMySQLPostgreSQL)で同じ目的のSQLでも構文に違いがあったりする。

MyBatisでは VendorDatabaseIdProvider を使うと、接続先のDBによって発行するSQLを切り替えることができる。

SpringBootで利用する方法についてまとめる。

VendorDatabaseIdProvider をBean登録

適当なConfigurationクラス等に、 org.apache.ibatis.mapping.VendorDatabaseIdProvider をBean登録する。

@Configuration
public class MyBatisConfig {
    @Bean
    public VendorDatabaseIdProvider vendorDatabaseIdProvider() {
        VendorDatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
        Properties vendorProperties = new Properties();
        vendorProperties.put("PostgreSQL", "postgresql");
        vendorProperties.put("MySQL", "mysql");
        vendorProperties.put("H2", "h2");
        databaseIdProvider.setProperties(vendorProperties);
        return databaseIdProvider;
    }
}

Mapper XMLにdatabaseIdを追加する

Mapper XMLで定義しているSQLに、RDBMSに応じたdatabaseIdを追加する。

SQLのIdは同一

  <select id="selectHoge" databaseId="mysql" ...>
    select name from hoge...
  </select>

  <select id="selectHoge" databaseId="postgresql" ...>
    select name from hoge...
  </select>

補足

アプリケーションで一部のSQLだけ方言吸収のために切り替えるにはよさそう。

ただ多くのSQLを切り替えるのであれば、管理が煩雑になってしまう気がする。

その場合は、いっそSpringのプロファイルから切り替えて、Mapper XMLから別で管理した方がいい気がする。
SQLの重複は覚悟の上で)

mybatis:
  mapper-locations: mybatis/postgresql/*.xml

あとはリポジトリレイヤがきちんと抽象化されていないと、SQLだけの吸収が辛くなるので設計大事だなと思う。

参考

PostgreSQLでコマンドラインからSQLファイルを実行する

概要

PostgreSQLコマンドラインから、特定のスキーマに対してSQLを発行する方法

準備

psql postgres 等で適当なデータベースに入ってroleの作成

create role commander with login;

コマンドラインからデータベースの作成

$ createdb --owner commander command_test

スキーマの作成

psql -U commander -d command_test で作成したデータベースに入って、スキーマの作成

create schema sample;

コマンドラインから実行

SQLファイルの作成

test.sql という名前でSQLファイルを作成する。

psqlからスキーマの指定方法がわからなかったので、スキーマ切り替えもSQLファイルで行う。

-- スキーマ切り替え
SET search_path = sample;

-- スキーマ表示
select current_schema();

-- サンプル実行
select 1 as hoge;

実行

# psql -d {データベース名} -U {ユーザ名} -f {ファイル名}
psql -d command_test -U commander -f test.sql

結果

こんな感じになります。

SET

 current_schema
----------------
 sample
(1 row)

 hoge
------
    1
(1 row)

参考

[PostgreSQL] よく使うコマンドまとめ | Developers.IO

Goでコマンドラインオプションを受け取る

概要

Golangコマンドラインオプションを受け取る方法。

go-sample というプログラムがあった場合に、 go-sample -hoge="bbb" と実行して、 bbb を受け取る。

手順

flagパッケージをimportします。

import (
  "flag"
)

flag変数(コマンドラインオプションを格納する)を宣言します。

// flag.String({flag名}, {デフォルト値}, {ヘルプ時のメッセージ})
var optHoge = flag.String("hoge", "aaa", "flag利用のサンプルです")

flagは宣言した後Parseする必要があります。

flag.Parse()

使用する時は *{変数名} です。

*hoge

サンプル

package main

import (
    "fmt" 
    "flag"
)

func main() {
    var optHoge = flag.String("hoge", "aaa", "flag利用のサンプルです")
    flag.Parse()
    fmt.Println(*optHoge)
}
  • go-sample と実行した場合、 aaa を表示
  • go-sample -hoge="bbb" と実行した場合、 bbb を表示
  • go-sample -help と実行した場合、 flag利用のサンプルです を表示