【MySQL】トランザクションの分離レベルって?

はじめに

業務で複数トランザクションを走らせる処理をしていた時にふと、
「別トランザクションでINSERTされたデータをこのトランザクションでSELECTしたらどうしよう....」と不安になってしまいました。
そこでトランザクションの分離レベルについて調べたのでまとめていきたいと思います。

トランザクションとは

トランザクションとは、SELECTやUPDATEなど単一または複数のSQLクエリを含む一連の処理の単位を指します。
この単位でコミットやロールバックをする事ができます。

ACIDとは

innoDB 1トランザクション処理の特性のことです。

種類 説明
原子性(Atomicity) トランザクション内の処理は「全部処理される」か「全部処理されない」のどちらかである
一貫性(Consistency) トランザクションの前後でデータは整合性がとれている
分離性(Isolation) トランザクション実行中は他のトランザクションに影響を与えない
永続性(Isolation) トランザクションが完了すれば障害があってもデータは保持される

分離性という性質から、トランザクションは他トランザクションの変更の影響を受けないように互いに分離されています。
この分離性は分離レベルとして段階に分けられており、用途に応じて調整する事ができます。

分離レベルとは

トランザクションの変更が他のトランザクションでどのように見えるのか、トランザクション同士の影響レベルのことです。
MySQLではREPEATABLE READがデフォルトに採用されています。
OraclePostgreSQLSQL ServerではREAD COMMITTED。

🚩READ UNCOMMITTED
コミットされていない更新(UPDATE)・追加(INSERT)が他のトランザクションから見えてしまう状態です。
そのため、ダーティリード(コミット前のデータを参照する現象)を引き起こす可能性があります。
f:id:mmmnn1257:20181118173802p:plain

🚩READ COMMITTEDOraclePostgreSQLSQL Server
コミットされた更新(UPDATE)・追加(INSERT)が他のトランザクションから見えてしまう状態です。
コミット前のデータは参照できないのでダーティリードは起こりませんが、コミット後のデータは参照できるため、アンリピータブルリード/ファジーリード(コミット後の更新データを参照する現象)を引き起こす可能性があります。 f:id:mmmnn1257:20181118173452p:plain

🚩REPEATABLE READMySQL
コミットされた追加(INSERT)が他のトランザクションから見えてしまう状態です。
更新(UPDATE)に対しては他のトランザクションの影響を受けないため値そのものの整合性は保証されています。
しかし、追加(INSERT)については影響を受けてしまうため、ファントムリード(コミット後の追加データを参照する現象)を引き起こす可能性があります。
f:id:mmmnn1257:20181118173227p:plain

MySQLではファントムリードを防いでいます。

🚩SERIALIZABLE
トランザクションにロックをかけることで直列に扱っている状態です。
そのため、トランザクション内でSELECTされる値や数の整合性が保証されます。
しかし、同じデータに対して複数のトランザクションが変更を行う場合、一方のトランザクションは待機しければなりません。

おわりに

MySQLではREPEATABLE READを採用しており、さらにファントムリードも防いでいます。
そのため1つのデータに対して複数のトランザクションをかけていても特に気にする必要はなさそうです。

参考

データベースの信頼性と速度を左右する、トランザクション分離レベルについて
MySQLでトランザクションの4つの分離レベル
トランザクション分離レベルを理解するために実際に試してみる
MySQL 用語集


  1. データベースにおいてデータの読み書きを担当するストレートエンジン

【egit】コミットのリセットからリセットの戻し方まで

はじめに

EclipseでGitを使用しているのですが、コミットを間違えてしまうことや、Non Fast Forwardでプッシュできないことがよくあります...。 そんな時にはよくリセットにお世話になるので違いをまとめていこうと思います。
さらにこの間謝って必要なコミットをハードリセットしてしまって冷や汗をかいたので、その対処法などもメモしていきます ✏︎

Non Fast Forward についてはこちらの記事で詳しく説明されていますので参考にどうぞ
Non-Fast-Forward Push の解決

リセットとは

あるコミットにリセットを行うと、その時点までのコミットをなかったことにしてくれる機能です。
リセットにはソフト・混合・ハードの3種類があります。

種類 説明
ソフト リセットまでに変更した内容を「ステージされた変更」に戻す
混合 リセットまでに変更した内容を「ステージされていない変更」に戻す
ハード リセットまでに変更した内容を削除する

リセットの実践

実際にリセットを行って種類の違いを見ていきます。
各リセットをする状況は同じものとして行います。

✧前提

①まず最初のコミットをします。

f:id:mmmnn1257:20181028194938p:plain

②次に変更を追加してコミットをします。

f:id:mmmnn1257:20181028195423p:plain

▼ヒストリーでみると2回コミットされていることが分かります。
f:id:mmmnn1257:20181028195926p:plain

✧ソフトリセットの場合

最初のコミット時点でソフトリセットをすると
▼ヒストリー上から2回目のコミットが消えています。
f:id:mmmnn1257:20181028200330p:plain
内容は変更されたままで、「ステージされた変更」にファイルが入っています。
f:id:mmmnn1257:20181028200623p:plain

✧混合リセットの場合

最初のコミット時点で混合リセットをすると
▼ヒストリー上から2回目のコミットが消えています。
f:id:mmmnn1257:20181028200330p:plain
内容は変更されたままで、「ステージされていない変更」にファイルが入っています。
f:id:mmmnn1257:20181028202527p:plain

✧ハードリセットの場合

最初のコミット時点でソフトリセットをすると
▼ヒストリー上から2回目のコミットが消えています。
f:id:mmmnn1257:20181028200330p:plain
内容の変更は削除されています。
f:id:mmmnn1257:20181028203013p:plain

リセットを戻す

①コミットをします。
f:id:mmmnn1257:20181028212419p:plain ②最初のコミット時点でハードリセットをして変更を削除します。
gitのパースペクティブからリポジトリーを左クリック▶︎表示▶︎Git参照ログを選択します。 f:id:mmmnn1257:20181028211819p:plain
④すると今までのコミットログが参照できます。
リセットしたいリセットコミットを左クリック▶︎リセット▶︎ソフトを選択します。 f:id:mmmnn1257:20181028212154p:plain
⑤ヒストリー上にコミットが復活し、「ステージングされた変更」にファイルが入っています。 f:id:mmmnn1257:20181028212419p:plain

f:id:mmmnn1257:20181028212548p:plain

GIt参照ログからリセットをソフトリセットをすることでコミットを戻すことができました!!

おわりに

ハードコミットだとファイルの変更も削除してしまうので基本的にはソフトコミットを使用するのが良さそうです。

【Java】BigDecimalとint型

はじめに

int型で実装していたのですが、途中で小数も扱うということになり、泣く泣くBigDecimal型に変更。
そのときに使用したBigDecimalクラスのあれこれを書いていきます。

BIGDECIMALクラスとは

用語 説明
精度 整数部分
スケール 小数点以下の桁

この2つを保持しており、正確な計算を提供してくれます。

なぜBIGDECIMALなのか

doubleやlongなどでは、小数部分が勝手に丸まってしまうなど 意図しない計算が起こってしまうようです。 私の場合は、小数点を使用した厳密な計算を行う必要があったのでBigDecimalを採用しました。
参考:なぜBigDecimalを使わなければならないのか | Java好き

INT型をBIGDECIMAL型に変換したい

変換の方法は2つあります。

int a = 1; 
① BigDecimal bd = new BigDecimal(a);
② BigDecimal bd = BigDecimal.valueOf(a);   


INT型のように初期値を0にしたい

BigDecimal db = BigDecimal.ZERO;

BigDecimal.ZEROはスケールが0の値0を戻します。
他にも
BigDecimal.ONE
BigDecimal.TEN
などのフィールドが用意されています。

足し算や引き算、掛け算もしたい

算術 メソッド
足し算 add(BigDecimal augend)
引き算 subtract(BigDecimal subtrahend)
掛け算 multiply(BigDecimal multiplicand)
割り算 divide(BigDecimal divisor)


計算結果の小数点を丸めたい

BigDecimalの算術では、結果の小数点の表記や丸める方法も指定できるので便利です。
割り算で用いられる以下のメソッドで考えてみます。
divide(BigDecimal divisor, int scale, int roundingMode);

パラメータ 説明
divisror 割る値
scale 小数点第何位まで表示するか(スケールの値)
roundingMode 丸め方

スケール値

BigDecimal divisor = 3;
BigDecimal dividend = 5;
BigDecimal amount = BigDecimal.ZERO;

amount = divisor.devide(dividend,0,ROUND_DOWN);
 //⇒ amount = 1
amount = divisor.devide(dividend,2,ROUND_DOWN);
 //⇒ amount = 1.66

丸め方

BigDecimal divisor = 3;
BigDecimal dividend = 5;
BigDecimal amount = BigDecimal.ZERO;

amount = divisor.devide(dividend,2,ROUND_DOWN);//切り捨て
 //⇒ amount = 1.66
amount = divisor.devide(dividend,2,ROUND_UP);//切り上げ
 //⇒ amount = 1.67

丸め方には他にも様々な方法があるようです。
参考:RoundingMode (Java Platform SE 8)

おわりに

文系出身だからか、小数点を含む計算はちょっと避けたい部分だったのですが、調べてみると意外におもしろかったです。

【mysql】SQL文を高速化するためにEXPLAINを使う

業務で何万件かのデータを取得するselect文を実行したところ、、
あれ?30秒もかかる!!!
もっと速くならないかな〜〜と思った時にしたことをメモします。

はじめに

今回サンプルで使用するテーブル構成はこんな感じです。
・user テーブル
f:id:mmmnn1257:20180520205958p:plain


EXPLAINを使って実行計画をみる

使い方は簡単です。
実行したいクエリにEXPLAINをつけるだけ。

explain select * from user order by user_id; 

すると以下のような結果が返って来ます。
たくさん気になる所はあるのですが、2つに注目してみます。
f:id:mmmnn1257:20180520211011p:plain

type:index
Extra:NULL
typeから見てとれるように、primarykeyのindexが効いているようです。


order byでindexが効かない?

今度は以下のようにorder byの条件を追加したクエリを実行しようと思います。

explain select * from user order by user_id , user_name;

すると以下のような結果が返って来ます。
f:id:mmmnn1257:20180520220604p:plain
あら?indexが効いていません。
複合indexを貼ってみることにしました。

alter table user add index (user_id , user_name);

f:id:mmmnn1257:20180520220908p:plain

ここでもう一度実行してみます。

explain select * from user order by user_id , user_name;

index効いているかな、とドキドキしていると以下のような結果が返って来ました。
f:id:mmmnn1257:20180520221406p:plain
😰効いていない、、!!

type:ALL
Extra:Using filesort

調べてみると、複合indexではwhere句を使用しないとindexが効かないらしいです、、。

複合インデックスを用いた場合に注意しないといけないのは、最も左端にあるインデックス(left-most index)をWHERE句の検索条件として指定しないと、ソート処理においてインデックスを利用できないという点である。


order byをしない選択

indexをはったキーをwhere句で使用することはできない場合、クエリでorder byを指定しない方がいいかもしれません。
selectした後にsortするという方法もあります。

ちなみに私は、order byで4つのキーを指定しなければいけなかったので、取得後にsortしました、、。


参考: 漢(オトコ)のコンピュータ道: MySQLのEXPLAINを徹底解説!!
MySQLでインデックスを追加するSQLと削除するSQLを実行しました

swift3でToDoリストアプリを作ってみた

SQL基礎に受かり気持ち的に余裕ができたのでようやくswiftの勉強を再開しました。(まだDBAがありますが、、、)

今回参考にしたサイトはこちらです↓
http://mosho-developer.blogspot.jp/2015/11/xcode-swifttodo.html
ストーリーボードの実装に関してはこのサイトの通りに進めていきました。
しかし今回はswift3を使用したため変更点などもあり、つまずいた点もいくつかありました。 今回はその辺をまとめていこうと思います。


完成形は今のところこんな感じです。ちょっとずれてますが、、
❶+を押下するとテキストフィールドが現れて、テキストフィールドをクリックするとキーボードが出てきます。
❷キーボード以外のところやreturnを押下するとキーボードが閉じられるようになっています。
❸ADDボタンを押下すると、テーブルリストにテキストが追加されています。


🌟NSUserDefaultsが変更されていた

変更前

NSUserDefaults.standardUserDefaults().setObject(todoItem, forKey: "todoList")

変更後

UserDefaults.standard.set(todoItem, forKey: "todoList")

🌟シュミレーターでキーボードが出ない

Hardware -> Keyboard オプションの Connect Hardware Keyboard を非選択にすることで解決!

🌟改行(return)でキーボードが閉じない!!

resignFirstResponderメソッドを定義しているのにreturnでキーボードが閉じないのは、delegateを指定していないからでした。

❶classにUITextFieldDelegateを追加

class AddToDo: UIViewController,UITextFieldDelegate{

❷viewDidLoadにテキストフィールドのdelegateを自分自身に設定

//viewDidLoadはインスタンス化された直後に一度だけ呼ばれる
    override func viewDidLoad() {
        super.viewDidLoad()
        itemText.delegate = self
    }

🌟todoItem配列が保持している文字列をテーブルに表示させる

以下のソースコードで正常に動きました
色々と変更点があったようですが詳しくは調べていません😢

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cellValue = UITableViewCell(style:  UITableViewCellStyle.default, reuseIdentifier: "cell")
        cellValue.textLabel?.text = todoItem[indexPath.row]
        return cellValue
    }

🌟リストをスライドして削除機能をする

こちらの記事を参考にしました↓
【Swift3】UITableViewのセルをスワイプで削除する - Qiita

🌟こんにちは、エラー

f:id:mmmnn1257:20170806233157p:plain

このエラーで、シュミレーターに何も表示されなくなりました。
問題はストーリーボードとの接続にあったようです。
ストーリーボードのview controllerを右クリックすると以下のような画面が出てきます。
f:id:mmmnn1257:20170806233514p:plain
黄色いさんかく⚠️印が出てきたらその部分に問題があります!
削除してあげましょう。

こちらの記事を参考にしました↓
【iOS初心者】Xcode8 Swift3 エラー「terminating with uncaught exception of type NSException」「Thread 1: signal SIGABRT」が出たらチェックする2つこと | programming.info


以上が私がつまずいた点です。
delegateなど、まだまだ詳しく調べきれていない箇所が多いので、これからの課題にしていこうと思います。

はじめましてシェルスクリプト

shellとは⁇

f:id:mmmnn1257:20170618201035p:plain

✍️echo $SHELLと入力すると自分が使っているshellが分かる
この画面がまさにシェル

f:id:mmmnn1257:20170618201431p:plain

shell scriptとは??

複数の命令を一気に行うことができるように、たくさんのコマンドで記述されたファイルのこと f:id:mmmnn1257:20170619202335p:plain
ファイルを実行するとシェルクリプトに書かれたコマンドが実行される

SQLローダーとは?

SQLローダー

大量の外部ファイルのデータをデータベースに取り込むときに使うもの f:id:mmmnn1257:20170618180043p:plain

ctlファイル

ctlファイル(制御ファイル)には、csvファイルに書かれたデータをどのようにSQLローダーが読み込むのかを設定する
具体的にはテーブル名とカラム名と型などを書き込む
書き方にはいくつかの注意があり、ハマったのでメモ

  • VARCHAR型はCHAR型と記入
  • NUMBER型はDECIMAL EXTERNAL型と記入
  • 例えば CHAR(1)と指定し、csvファイルでデータを"1"と記入したときはエラーになってしまう
    理由は、ダブルクオーテーションも1文字として換算されているからである
    ダブルクオーテーションを使うときは FIELDS句で囲み文字の設定をする必要がある
    FIELDS [TERMINATED BY (区切り記号)] [OPTIONALLY] [ENCLOSED BY (囲み記号)

csvファイル

カンマで区切られたファイルのこと
ここにテーブルに入れたいレコードのデータを記入していく
shファイルで作られ、ctlファイルで制御される

shファイル

shファイルはコマンドを作るためのファイルでありシェルスクリプトで書かれる
今回は、csvファイルに大量のデータを書き込むように設定する