SlideShare une entreprise Scribd logo
1  sur  126
Reladomoを使った
トランザクション履歴管理を
プロダクトに適用した際の
メリット/デメリット/課題など
JJUG CCC 2019 Spring
#jjug_ccc #ccc_m7
2019-05-18
株式会社オープントーン 渡邉 一夫
#ccc_m7
自己紹介
• 名前:渡邉 一夫 ( Twitter → @nave_kazu )
• エンジニア歴:20年
• 所属:株式会社オープントーン
• 秋葉原
• 勤怠管理システム
• 観光ビッグデータ
• ヘルス・メディテック
• AWSのAPNパートナー
• エンジニア募集中!
#ccc_m7
自己紹介
• 名前:渡邉 一夫 ( Twitter → @nave_kazu )
• Java歴:20年弱
• MS Visual J++ 6.0でアプレットを作ったのが初めてのJava
• 独習Javaで言語仕様やJava SEのAPIを理解
• SJC-P と SJC-WCを取得
#ccc_m7
自己紹介
• 名前:渡邉 一夫 ( Twitter → @nave_kazu )
• Java歴:20年弱
• 今はDB設計してSpring BootでWeb APIを書いたり、
AngularやVue.jsでクライアントを書いたり、
AWSでインフラ構築したり、、、フルスタックエンジニア
• JJUG CCCは2014年ごろから参加
• JJUG CCC 2018 Fallで登壇
• SQL実行ツールを作るのがライフワーク
#ccc_m7
自己紹介
• 名前:渡邉 一夫 ( Twitter → @nave_kazu )
• その他
• 共著 システム開発のための見積りのすべてがわかる本
• AWS 認定ソリューションアーキテクト–アソシエイト取得
#ccc_m7
自己紹介
• HEAVY ROTATION → BAND-MAID
#ccc_m7
自己紹介
• HEAVY ROTATION → BAND-MAID
メイド喫茶のノリをバンドでやってみた
5ピースガールズバンド
コスチューム → メイド服
ライブ → お給仕
ライブ参加 → ご帰宅
ファン → ご主人様・お嬢様
ライブMC
「おかえりなさいませご主人様お嬢様」
#ccc_m7
自己紹介
• HEAVY ROTATION → BAND-MAID
メイド喫茶のノリをバンドでやってみた
5ピースガールズバンド
コスチューム → メイド服
ライブ → お給仕
ライブ参加 → ご帰宅
ファン → ご主人様・お嬢様
ライブMC
「おかえりなさいませご主人様お嬢様」
ゴリッゴリのハードロック
#ccc_m7
アジェンダ
• Reladomoとは?
• 履歴管理のいろいろ
• Reladomoのプロダクト適用例
• Reladomoの実装例
#ccc_m7
Reladomoとは?
• ゴールドマン・サックスが開発するORM
• XMLでテーブル定義をしDDL・エンティティ自動生成
• 履歴管理(バイテンポラル)に特化している
• 型付けされたクエリー言語(SQLは書かない)
• etc
#ccc_m7
履歴管理いろいろ(Chaining)
• 履歴管理なし (Snapshot)
• 「今」しか扱わない
• 営業時間のみ (Business-Only)
• 業務上の意味のある時間(Business date)を管理する
• 処理時間のみ (Audit-Only)
• システムへの反映時間(Processing date)を管理する
• 営業時間・処理時間両方 (Bi-temporal)
• 営業時間と処理時間の両方を管理する
#ccc_m7
履歴管理いろいろ(Chaining)
• シナリオ (ユーザー管理)
• 「小鳩ミク」さんを登録する
• 利用開始は4月1日から (Business date)
• 登録は3月25日に行う(Processing date)
• 住所変更する
• 5月1日に住所変更したい(Business date)
• 申請は5月3日にあった(Processing date)
• 住所変更の訂正をする
• 誤りを5月4日に訂正したい (Processing date)
• 利用停止する
• 申請が5月31日にあった(Business / Processing date)
• 即日停止としたい
#ccc_m7
履歴管理いろいろ(Chaining)
• 履歴管理なし (Snapshot)
• 「小鳩ミク」さんを登録する
• 利用開始は4月1日から (Business date)
• 登録は3月25日に行う(Processing date)
ユーザーID 名前 住所
1 小鳩ミク 東京都
登録した時点でシステムに反映
#ccc_m7
履歴管理いろいろ(Chaining)
• 履歴管理なし (Snapshot)
• 「小鳩ミク」さんを登録する
• 利用開始は4月1日から (Business date)← 表現できない!
• 登録は3月25日に行う(Processing date) ← 表現できない!
ユーザーID 名前 住所
1 小鳩ミク 東京都
登録した時点でシステムに反映
#ccc_m7
履歴管理いろいろ(Chaining)
• 営業時間のみ (Business-Only)
• 「小鳩ミク」さんを登録する
• 利用開始は4月1日から (Business date)
• 登録は3月25日に行う(Processing date)← 表現できない!
ユーザーID 名前 住所 from_z thru_z
1 小鳩ミク 東京都 2019/4/1 9999/12/1
利用開始日を「from_z」で表現
利用終了日を「thru_z」で表現
開始日はBusiness date、終了日はINFINITY(無限)とする
INFINITY はPostgreSQLの場合 9999/12/1 23:59:00.000
#ccc_m7
履歴管理いろいろ(Chaining)
• 処理時間のみ (Audit-Only)
• 「小鳩ミク」さんを登録する
• 利用開始は4月1日から (Business date)← 表現できない!
• 登録は3月25日に行う(Processing date)
システム有効開始日を「in_z」で表現
システム有効終了日を「out_z」で表現
開始日はProcessing date、終了日はINFINITY(無限)とする
ユーザーID 名前 住所 in_z out_z
1 小鳩ミク 東京都 2019/3/25 9999/12/1
#ccc_m7
履歴管理いろいろ(Chaining)
• 営業時間・処理時間両方 (Bi-temporal)
• 「小鳩ミク」さんを登録する
• 利用開始は4月1日から (Business date)
• 登録は3月25日に行う(Processing date)
ユーザーID 名前 住所 from_z thru_z in_z out_z
1 小鳩ミク 東京都 2019/4/1 9999/12/1 2019/3/25 9999/12/1
営業時間のみ (Business-Only)で使った「from_z」と「thru_z」、
処理時間のみ (Audit-Only)で使った「in_z」と「out_z」の両方を使うことで
利用開始日と登録があった日の両方を表現できる
#ccc_m7
履歴管理いろいろ(Chaining)
• 履歴管理なし(Snapshot)
• 住所変更する
• 5月1日に住所変更したい(Business date) ← 表現できない!
• 申請は5月3日にあった(Processing date) ← 表現できない!
ユーザーID 名前 住所
1 小鳩ミク 埼玉県
変更した時点でシステムに反映
#ccc_m7
履歴管理いろいろ(Chaining)
• 営業時間のみ (Business-Only)
• 住所変更する
• 5月1日に住所変更したい(Business date)
• 申請は5月3日にあった(Processing date) ← 表現できない!
ユーザーID 名前 住所 from_z thru_z
1 小鳩ミク 東京都 2019/4/1 2019/5/1
1 小鳩ミク 埼玉県 2019/5/1 9999/12/1
東京都の時の利用終了日を「2019/5/1」に更新
埼玉県のレコードを追加し、利用開始日を「2019/5/1」とする
埼玉県の利用終了日をINFINITY「9999/12/1」とする
最新の情報が欲しい場合はthru_zがINFINITYのものを検索する
#ccc_m7
履歴管理いろいろ(Chaining)
• 処理時間のみ (Audit-Only)
• 住所変更する
• 5月1日に住所変更したい(Business date) ← 表現できない!
• 申請は5月3日にあった(Processing date)
東京都の時のシステム有効終了日を「2019/5/3」に更新
埼玉県のレコードを追加し、システム有効開始日を「2019/5/3」とする
埼玉県のシステム有効終了日をINFINITY「9999/12/1」とする
最新の情報が欲しい場合はout_zがINFINITYのものを検索する
ユーザーID 名前 住所 in_z out_z
1 小鳩ミク 東京都 2019/3/25 2019/5/3
1 小鳩ミク 埼玉県 2019/5/3 9999/12/1
#ccc_m7
履歴管理いろいろ(Chaining)
• 営業時間・処理時間両方 (Bi-temporal)
• 住所変更する
• 5月1日に住所変更したい(Business date)
• 申請は5月3日にあった(Processing date)
ユーザーID 名前 住所 from_z thru_z in_z out_z
1 小鳩ミク 東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3
1 小鳩ミク 東京都 2019/4/1 2019/5/1 2019/5/3 9999/12/1
1 小鳩ミク 埼玉県 2019/5/1 9999/12/1 2019/5/3 9999/12/1
5/3までの情報として初期データのシステム終了日を「2019/5/3」に更新して締める
5/3からの情報として、東京都と埼玉県のレコードを作成する
東京都の利用開始日と終了日をそれぞれ「2019/4/1」と「2019/5/1」にする
埼玉県の利用開始日と終了日とそれぞれ「2019/5/1」とINFINITYにする
なぜこんな複雑な更新を? → 後ほど説明
#ccc_m7
履歴管理いろいろ(Chaining)
• 履歴管理なし(Snapshot)
• 住所変更の訂正をする
• 誤りを5月4日に訂正したい (Processing date) ← 表現できない!
ユーザーID 名前 住所
1 小鳩ミク 神奈川県
変更した時点でシステムに反映
#ccc_m7
履歴管理いろいろ(Chaining)
• 営業時間のみ (Business-Only)
• 住所変更の訂正をする
• 誤りを5月4日に訂正したい (Processing date) ← 表現できない!
ユーザーID 名前 住所 from_z thru_z
1 小鳩ミク 東京都 2019/4/1 2019/5/1
1 小鳩ミク 神奈川県 2019/5/1 9999/12/1
利用開始日・終了日に変更がないので、「埼玉県」を「神奈川県」に更新して終了
誤りがあったことはなかったことにする
#ccc_m7
履歴管理いろいろ(Chaining)
• 処理時間のみ (Audit-Only)
• 住所変更の訂正をする
• 誤りを5月4日に訂正したい (Processing date)
監査(Audit)が目的なので、
変更前の「埼玉県」のシステム有効終了日を「2019/5/4」に更新
神奈川県のレコードを追加し、システム有効開始日を「2019/5/4」、
システム有効終了日をINFINITY「9999/12/1」とする
ユーザーID 名前 住所 in_z out_z
1 小鳩ミク 東京都 2019/3/25 2019/5/3
1 小鳩ミク 埼玉県 2019/5/3 2019/5/4
1 小鳩ミク 神奈川県 2019/5/4 9999/12/1
#ccc_m7
履歴管理いろいろ(Chaining)
• 営業時間・処理時間両方 (Bi-temporal)
• 住所変更の訂正をする
• 誤りを5月4日に訂正したい (Processing date)
ユーザーID 名前 住所 from_z thru_z in_z out_z
1 小鳩ミク 東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3
1 小鳩ミク 東京都 2019/4/1 2019/5/1 2019/5/3 9999/12/1
1 小鳩ミク 埼玉県 2019/5/1 9999/12/1 2019/5/3 2019/5/4
1 小鳩ミク 神奈川県 2019/5/1 9999/12/1 2019/5/4 9999/12/1
5/4までの情報として、埼玉県のシステム終了日を「2019/5/4」に更新して締める
5/4からの情報として、神奈川県のレコードを作成する
神奈川県の利用開始日と終了日とそれぞれ「2019/5/1」とINFINITYにする
#ccc_m7
履歴管理いろいろ(Chaining)
• 履歴管理なし(Snapshot)
• 利用停止する
• 申請が5月31日にあった(Business / Processing date)← 表現できない!
• 即日停止としたい
ユーザーID 名前 住所
変更した時点でシステムに反映
利用停止を、どう表現する?
物理削除?ステータス管理?論理削除?
#ccc_m7
履歴管理いろいろ(Chaining)
• 営業時間のみ (Business-Only)
• 利用停止する
• 申請が5月31日にあった(Business / Processing date)
• 即日停止としたい
ユーザーID 名前 住所 from_z thru_z
1 小鳩ミク 東京都 2019/4/1 2019/5/1
1 小鳩ミク 神奈川県 2019/5/1 2019/6/1
神奈川県の利用終了日を「2019/6/1」とする
#ccc_m7
履歴管理いろいろ(Chaining)
• 処理時間のみ (Audit-Only)
• 利用停止する
• 申請が5月31日にあった(Business / Processing date)
• 即日停止としたい
神奈川県のシステム有効終了日を「2019/6/1」とする
ユーザーID 名前 住所 in_z out_z
1 小鳩ミク 東京都 2019/3/25 2019/5/3
1 小鳩ミク 埼玉県 2019/5/3 2019/5/4
1 小鳩ミク 神奈川県 2019/5/4 2019/6/1
#ccc_m7
履歴管理いろいろ(Chaining)
• 営業時間・処理時間両方 (Bi-temporal)
• 利用停止する
• 申請が5月31日にあった(Business / Processing date)
• 即日停止としたい
ユーザーID 名前 住所 from_z thru_z in_z out_z
1 小鳩ミク 東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3
1 小鳩ミク 東京都 2019/4/1 2019/5/1 2019/5/3 9999/12/1
1 小鳩ミク 埼玉県 2019/5/1 9999/12/1 2019/5/3 2019/5/4
1 小鳩ミク 神奈川県 2019/5/1 9999/12/1 2019/5/4 2019/6/1
1 小鳩ミク 神奈川県 2019/5/1 2019/6/1 2019/6/1 9999/12/1
元々の神奈川県のシステム終了日を「2019/6/1」に更新して締める
6/1からの情報として、神奈川県のレコードを作成する
新しい神奈川県の利用開始日と終了日とそれぞれ「2019/5/1」と「2019/6/1」にする
#ccc_m7
Bi-temporalを深掘り
住所 from_z thru_z in_z out_z
Inf
6/1
5/3
5/1
4/1
3/25
BusinessTime(from_z/thru_z) 3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
#ccc_m7
Bi-temporalを深掘り
• 「小鳩ミク」さんを登録する
住所 from_z thru_z in_z out_z
東京都 2019/4/1 9999/12/1 2019/3/25 9999/12/1 A
Inf
6/1
5/3
5/1
4/1
3/25
BusinessTime(from_z/thru_z) 3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
A
#ccc_m7
Bi-temporalを深掘り
• 住所変更する
住所 from_z thru_z in_z out_z
東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3 A
Inf
6/1
5/3
5/1
4/1
3/25
3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
BusinessTime(from_z/thru_z)
A
システム終了日を「2019/5/3」に更新して締める
#ccc_m7
Bi-temporalを深掘り
• 住所変更する
住所 from_z thru_z in_z out_z
東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3 A
東京都 2019/4/1 2019/5/1 2019/5/3 9999/12/1 B
埼玉県 2019/5/1 9999/12/1 2019/5/3 9999/12/1 C
Inf
6/1
5/3
5/1
4/1
3/25
BusinessTime(from_z/thru_z)
システム開始日「2019/5/3」の新たなレコードを追加
B
C
3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
A
#ccc_m7
Bi-temporalを深掘り
• 住所変更の訂正をする
住所 from_z thru_z in_z out_z
東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3 A
東京都 2019/4/1 2019/5/1 2019/5/3 9999/12/1 B
埼玉県 2019/5/1 9999/12/1 2019/5/3 2019/5/4 C
Inf
6/1
5/3
5/1
4/1
3/25
BusinessTime(from_z/thru_z)
訂正対象のシステム終了日を
「2019/5/4」に更新して締める
3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
B
C
A
#ccc_m7
Bi-temporalを深掘り
• 住所変更の訂正をする
住所 from_z thru_z in_z out_z
東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3 A
東京都 2019/4/1 2019/5/1 2019/5/3 9999/12/1 B
埼玉県 2019/5/1 9999/12/1 2019/5/3 2019/5/4 C
神奈川県 2019/5/1 9999/12/1 2019/5/4 9999/12/1 D
Inf
6/1
5/3
5/1
4/1
3/25
BusinessTime(from_z/thru_z)
訂正後のレコードを追加する
D
3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
B
C
A
#ccc_m7
Bi-temporalを深掘り
• 利用停止する
住所 from_z thru_z in_z out_z
東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3 A
東京都 2019/4/1 2019/5/1 2019/5/3 9999/12/1 B
埼玉県 2019/5/1 9999/12/1 2019/5/3 2019/5/4 C
神奈川県 2019/5/1 9999/12/1 2019/5/4 2019/6/1 D
Inf
6/1
5/3
5/1
4/1
3/25
BusinessTime(from_z/thru_z)
最新行のシステム終了日を
「2019/6/1」に更新して締める
3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
D
B
C
A
#ccc_m7
Bi-temporalを深掘り
• 利用停止する
住所 from_z thru_z in_z out_z
東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3 A
東京都 2019/4/1 2019/5/1 2019/5/3 9999/12/1 B
埼玉県 2019/5/1 9999/12/1 2019/5/3 2019/5/4 C
神奈川県 2019/5/1 9999/12/1 2019/5/4 2019/6/1 D
神奈川県 2019/5/1 2019/6/1 2019/6/1 9999/12/1 E
Inf
6/1
5/3
5/1
4/1
3/25
BusinessTime(from_z/thru_z)
利用停止のレコードを追加
E
3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
D
B
C
A
#ccc_m7
Bi-temporalを深掘り
• 4月中旬の状態
住所 from_z thru_z in_z out_z
東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3 A
東京都 2019/4/1 2019/5/1 2019/5/3 9999/12/1 B
埼玉県 2019/5/1 9999/12/1 2019/5/3 2019/5/4 C
神奈川県 2019/5/1 9999/12/1 2019/5/4 2019/6/1 D
神奈川県 2019/5/1 2019/6/1 2019/6/1 9999/12/1 E
Inf
6/1
5/3
5/1
4/1
3/25
BusinessTime(from_z/thru_z)
SELECT * FROM USER
WHERE in_z <= ‘2019-04-15’ AND
out_z > ‘2019-04-15’
E
3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
D
B
C
A
#ccc_m7
Bi-temporalを深掘り
• 5月中旬の状態
住所 from_z thru_z in_z out_z
東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3 A
東京都 2019/4/1 2019/5/1 2019/5/3 9999/12/1 B
埼玉県 2019/5/1 9999/12/1 2019/5/3 2019/5/4 C
神奈川県 2019/5/1 9999/12/1 2019/5/4 2019/6/1 D
神奈川県 2019/5/1 2019/6/1 2019/6/1 9999/12/1 E
Inf
6/1
5/3
5/1
4/1
3/25
BusinessTime(from_z/thru_z)
E
3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
D
B
C
A
SELECT * FROM USER
WHERE in_z <= ‘2019-05-15’ AND
out_z > ‘2019-05-15’
#ccc_m7
Bi-temporalを深掘り
• 最新の状態
住所 from_z thru_z in_z out_z
東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3 A
東京都 2019/4/1 2019/5/1 2019/5/3 9999/12/1 B
埼玉県 2019/5/1 9999/12/1 2019/5/3 2019/5/4 C
神奈川県 2019/5/1 9999/12/1 2019/5/4 2019/6/1 D
神奈川県 2019/5/1 2019/6/1 2019/6/1 9999/12/1 E
Inf
6/1
5/3
5/1
4/1
3/25
BusinessTime(from_z/thru_z)
E
3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
D
B
C
A
SELECT * FROM USER
WHERE out_z = ‘9999-12-01’
#ccc_m7
Bi-temporalを深掘り
こんな複雑な仕組みを
SQLで実装するのは面倒・・・
→ Reladomoで解決!
#ccc_m7
Reladomoのプロダクト適用例
• Duolingo
• Duolingo社の語学学習サービス
• 英語以外も充実
• ハイ・ヴァリリア語も学べる
• リスニング、リーディング、ライティング
• ソーシャル機能
• ノルマ&報酬制度
• 1レッスン10問で全問正解まで終わらない → 終わりま10
• 終わりま10を語学以外の学習に使いたい
#ccc_m7
Reladomoのプロダクト適用例
• Study up!
• 個人プロダクト
• AWS ソリューションアーキテクト
アソシエイトの次、
プロフェッショナルを勉強するには?
• 書籍がない・・・
• じゃぁ、自分で学習用のサイトを作ろう!
• https://studyup.info/
• (今のところ)無料
#ccc_m7
Reladomoのプロダクト適用例
• Demo
#ccc_m7
Reladomoのプロダクト適用例
• Reladomoの適用箇所
• 回答結果の履歴を保持 →
• 最新の正解率 →
• 過去5回の平均正解率 →
• 過去10回の平均正解率 →
※ 正解率 ・・・ 10問の初回回答結果から算出 → 10問中8問正解=80%
#ccc_m7
Reladomoのプロダクション適用例
• Study up! on AWS
#ccc_m7
Reladomoのプロダクション適用例
• Study up! on AWS
ちと高い(お値段)
#ccc_m7
Reladomoのプロダクション適用例
• Study up! on AWS
#ccc_m7
Reladomoの実装例
• XMLでテーブル定義
• ビルドプロセスでDDL生成
• ビルドプロセスでコード生成
• 開発のフロー
• ConnectionManagerの作成
• CRUD操作の例
• リレーションの定義
• ユニットテスト
• プライマリキー生成戦略
• キャッシュ戦略
• Auto Scale(クラスタリング)対策
#ccc_m7
Reladomoの実装例
• XMLでテーブル定義 – テーブル名・クラス名定義
user.xml
<MithraObject objectType=“transactional” xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="mithraobject.xsd">
<PackageName>some.package</PackageName>
<ClassName>User</ClassName>
<DefaultTable>USER</DefaultTable>
</MithraObject>
パッケージ名、
エンティティクラス名、
テーブル名
#ccc_m7
Reladomoの実装例
• XMLでテーブル定義 – カラム定義
user.xml
<MithraObject objectType=“transactional” xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="mithraobject.xsd">
<PackageName>some.package</PackageName>
<ClassName>User</ClassName>
<DefaultTable>USER</DefaultTable>
<Attribute name="userId" javaType="long" columnName="user_id" nullable="false“ primaryKey="true"/>
<Attribute name=“name” javaType="String" columnName="name" nullable="false" maxLength="100"/>
<Attribute name="address" javaType="String" columnName="address" nullable="false" maxLength="100"/>
</MithraObject>
カラムリスト
#ccc_m7
Reladomoの実装例
• XMLでテーブル定義 – カラム定義
user.xml
<MithraObject objectType=“transactional” xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="mithraobject.xsd">
<PackageName>some.package</PackageName>
<ClassName>User</ClassName>
<DefaultTable>USER</DefaultTable>
<Attribute name="userId" javaType="long" columnName="user_id" nullable="false“ primaryKey="true"/>
<Attribute name=“name” javaType="String" columnName="name" nullable="false" maxLength="100"/>
<Attribute name="address" javaType="String" columnName="address" nullable="false" maxLength="100"/>
</MithraObject>
カラムコメント(日本語カラム名)
入れたいな・・・
カラムリスト
#ccc_m7
Reladomoの実装例
• XMLでテーブル定義 – Bi-temporal
user.xml
<MithraObject objectType="transactional" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="mithraobject.xsd">
<PackageName>some.package</PackageName>
<ClassName>User</ClassName>
<DefaultTable>USER</DefaultTable>
<AsOfAttribute name="businessDate" fromColumnName="from_z" toColumnName="thru_z"
toIsInclusive="false" isProcessingDate="false"
infinityDate=“[(中略)DefaultInfinityTimestamp.getDefaultInfinity()]"
futureExpiringRowsExist="true"
/>
<AsOfAttribute name="processingDate" fromColumnName="in_z" toColumnName="out_z"
toIsInclusive=“false” isProcessingDate="true"
infinityDate="[(中略)DefaultInfinityTimestamp.getDefaultInfinity()]"
defaultIfNotSpecified="[(中略)DefaultInfinityTimestamp.getDefaultInfinity()]"
/>
<Attribute name="userId" javaType="long" columnName="user_id" nullable="false“ primaryKey="true"/>
<Attribute name=“name” javaType="String" columnName="name" nullable="false" maxLength="100"/>
<Attribute name="address" javaType="String" columnName="address" nullable="false" maxLength="100"/>
</MithraObject>
Bi-temporal
(営業時間、処理時間)
#ccc_m7
Reladomoの実装例
• ビルドプロセスでDDL生成
pom.xmlの抜粋
<configuration>
<tasks>
<property name="plugin_classpath" refid="maven.plugin.classpath"/>
<taskdef name="gen-reladomo-db" classpath="plugin_classpath"
classname=“(中略)MithraDbDefinitionGenerator"/>
<gen-reladomo-db
xml="${project.basedir}/src/main/reladomoxml/MithraClassList.xml"
generatedDir="${project.build.directory}/generated-resources/db"
databaseType="postgres"/>
</tasks>
</configuration>
#ccc_m7
Reladomoの実装例
• ビルドプロセスでDDL生成
MithraClassList.xml
<Mithra xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="mithraobject.xsd">
<MithraObjectResource name="User"/>
・・・・
</Mithra>
生成対象の
エンティティを指定
#ccc_m7
Reladomoの実装例
• ビルドプロセスでDDL生成
pom.xmlの抜粋
<configuration>
<tasks>
<property name="plugin_classpath" refid="maven.plugin.classpath"/>
<taskdef name="gen-reladomo-db" classpath="plugin_classpath"
classname=“(中略)MithraDbDefinitionGenerator"/>
<gen-reladomo-db
xml="${project.basedir}/src/main/reladomoxml/MithraClassList.xml"
generatedDir="${project.build.directory}/generated-resources/db"
databaseType="postgres"/>
</tasks>
</configuration>
sybase
udb82
mssql
postgres
oracle
#ccc_m7
Reladomoの実装例
• ビルドプロセスでDDL生成
pom.xmlの抜粋
<configuration>
<tasks>
<property name="plugin_classpath" refid="maven.plugin.classpath"/>
<taskdef name="gen-reladomo-db" classpath="plugin_classpath"
classname=“(中略)MithraDbDefinitionGenerator"/>
<gen-reladomo-db
xml="${project.basedir}/src/main/reladomoxml/MithraClassList.xml"
generatedDir="${project.build.directory}/generated-resources/db"
databaseType="postgres"/>
</tasks>
</configuration>
sybase
udb82
mssql
postgres
oracle
MySQL ない!
MariaDB ない!
Amazon Aurora ない!
#ccc_m7
Reladomoの実装例
• ビルドプロセスでDDL生成
• AWS RDSの t2.micro(1CPU 1GiBmem) の料金比較
• AWS RDSの t2.2xlarge(8CPU 32GiBmem) の料金比較
RDS hour (USD) month (USD) month (JPY)
Oracle 0.044 31.68 3,516.48
PostgreSQL 0.028 20.16 2,237.76
MySQL 0.026 18.72 2,077.92
RDS hour (USD) month (USD) month (JPY)
Oracle 1.6448 1,184.256 131,452.416
PostgreSQL 0.8960 645.12 71,608.32
MySQL 0.8360 601.92 66,813.12
※ストレージ料金除く
#ccc_m7
Reladomoの実装例
• ビルドプロセスでDDL生成
• AWS RDSの t2.micro(1CPU 1GiBmem) の料金比較
• AWS RDSの t2.2xlarge(8CPU 32GiBmem) の料金比較
MySQL ないのは
つらい
RDS hour (USD) month (USD) month (JPY)
Oracle 0.044 31.68 3,516.48
PostgreSQL 0.028 20.16 2,237.76
MySQL 0.026 18.72 2,077.92
RDS hour (USD) month (USD) month (JPY)
Oracle 1.6448 1,184.256 131,452.416
PostgreSQL 0.8960 645.12 71,608.32
MySQL 0.8360 601.92 66,813.12
※ストレージ料金除く
#ccc_m7
Reladomoの実装例
• ビルドプロセスでDDL生成
• create table、PK、外部キーが生成される
create table user (
user_id bigint not null, ← PK
name varchar(100) not null,
address varchar(100) not null,
from_z timestamp not null,
thru_z timestamp not null, ← PK
in_z timestamp not null,
out_z timestamp not null ← PK
);
alter table user add constraint user_pk primary key (user_id, thru_z, out_z);
#ccc_m7
Reladomoの実装例
• ビルドプロセスでコード生成
pom.xmlの抜粋
<configuration>
<tasks>
<property name="plugin_classpath" refid="maven.plugin.classpath"/>
<taskdef name="gen-reladomo" classpath="plugin_classpath"
classname="com.gs.fw.common.mithra.generator.MithraGenerator"/>
<gen-reladomo xml="${project.basedir}/src/main/reladomoxml/MithraClassList.xml"
generateGscListMethod="true"
generatedDir="${project.build.directory}/generated-sources/reladomo"
nonGeneratedDir="${project.basedir}/src/main/java"
/>
</tasks>
</configuration>
#ccc_m7
Reladomoの実装例
• ビルドプロセスでコード生成
user.xml
UserAbstract UserDatabaseObjectAbstract
UserFinder
UserListAbstract
User UserDatabaseObjectUserList
#ccc_m7
Reladomoの実装例
• ビルドプロセスでコード生成
user.xml
UserAbstract UserDatabaseObjectAbstract
UserFinder
UserListAbstract
User UserDatabaseObjectUserList
検索に用いる
#ccc_m7
Reladomoの実装例
• ビルドプロセスでコード生成
user.xml
UserAbstract UserDatabaseObjectAbstract
UserFinder
UserListAbstract
User UserDatabaseObjectUserList
1レコードを表現
#ccc_m7
Reladomoの実装例
• ビルドプロセスでコード生成
user.xml
UserAbstract UserDatabaseObjectAbstract
UserFinder
UserListAbstract
User UserDatabaseObjectUserList
複数行検索に用いる
#ccc_m7
Reladomoの実装例
• ビルドプロセスでコード生成
user.xml
UserAbstract UserDatabaseObjectAbstract
UserFinder
UserListAbstract
User UserDatabaseObjectUserList
テーブル情報取得用
#ccc_m7
Reladomoの実装例
• ビルドプロセスでコード生成
user.xml
UserAbstract UserDatabaseObjectAbstract
UserFinder
UserListAbstract
User UserDatabaseObjectUserList
抽象クラス・Finderはビルド時に毎回生成
#ccc_m7
Reladomoの実装例
• ビルドプロセスでコード生成
user.xml
UserAbstract UserDatabaseObjectAbstract
UserFinder
UserListAbstract
User UserDatabaseObjectUserList
具象クラスは一度だけ生成
#ccc_m7
Reladomoの実装例
• ビルドプロセスでコード生成
user.xml
UserAbstract UserDatabaseObjectAbstract
UserFinder
UserListAbstract
User UserDatabaseObjectUserList
具象クラスは一度だけ生成
たとえば
firstName + lastNameから
getFullName()メソッドを定義
#ccc_m7
Reladomoの実装例
• 開発のフロー
user.xml
user.ddl
…etc
User.java
…etc
DB
View
Procedure
…etc
可視化
#ccc_m7
Reladomoの実装例
• 開発のフロー
user.xml
user.ddl
…etc
User.java
…etc
DB
View
Procedure
…etc
設計者がXMLを
編集するの?
DBからリバースして
生成してくれないの?
可視化
#ccc_m7
Reladomoの実装例
• ConnectionManagerの作成 – クラス作成
public class ConnectionManager implements SourcelessConnectionManager {
private XAConnectionManager createConnectionManager() {
xaConnectionManager = new XAConnectionManager();
xaConnectionManager.setDriverClassName(“org.postgresql.Driver”);
xaConnectionManager.setJdbcConnectionString(“jdbc:postgresql://xxx.rds.amazonaws.com:5432/xxx”);
xaConnectionManager.setJdbcUser(“xxxxx”);
xaConnectionManager.setJdbcPassword(“xxxxx”);
(中略)
return xaConnectionManager;
}
@Override
public DatabaseType getDatabaseType() {
return PostgresDatabaseType.getInstance();
}
#ccc_m7
Reladomoの実装例
• ConnectionManagerの作成 – クラス作成
public class ConnectionManager implements SourcelessConnectionManager {
private XAConnectionManager createConnectionManager() {
xaConnectionManager = new XAConnectionManager();
xaConnectionManager.setDriverClassName(“org.postgresql.Driver”);
xaConnectionManager.setJdbcConnectionString(“jdbc:postgresql://xxx.rds.amazonaws.com:5432/xxx”);
xaConnectionManager.setJdbcUser(“xxxxx”);
xaConnectionManager.setJdbcPassword(“xxxxx”);
(中略)
return xaConnectionManager;
}
@Override
public DatabaseType getDatabaseType() {
return PostgresDatabaseType.getInstance();
}
お約束のドライバークラス、
接続文字列、ユーザー名、
パスワード
#ccc_m7
Reladomoの実装例
• ConnectionManagerの作成 – クラス作成
public class ConnectionManager implements SourcelessConnectionManager {
private XAConnectionManager createConnectionManager() {
xaConnectionManager = new XAConnectionManager();
xaConnectionManager.setDriverClassName(“org.postgresql.Driver”);
xaConnectionManager.setJdbcConnectionString(“jdbc:postgresql://xxx.rds.amazonaws.com:5432/xxx”);
xaConnectionManager.setJdbcUser(“xxxxx”);
xaConnectionManager.setJdbcPassword(“xxxxx”);
(中略)
return xaConnectionManager;
}
@Override
public DatabaseType getDatabaseType() {
return PostgresDatabaseType.getInstance();
}
使用するRDBMSの指定
#ccc_m7
Reladomoの実装例
• ConnectionManagerの作成 – クラス作成
public class ConnectionManager implements SourcelessConnectionManager {
private XAConnectionManager createConnectionManager() {
xaConnectionManager = new XAConnectionManager();
xaConnectionManager.setDriverClassName(“org.postgresql.Driver”);
xaConnectionManager.setJdbcConnectionString(“jdbc:postgresql://xxx.rds.amazonaws.com:5432/xxx”);
xaConnectionManager.setJdbcUser(“xxxxx”);
xaConnectionManager.setJdbcPassword(“xxxxx”);
(中略)
return xaConnectionManager;
}
@Override
public DatabaseType getDatabaseType() {
return PostgresDatabaseType.getInstance();
}
使用するRDBMSの指定
MySQL ないのは
つらい
#ccc_m7
Reladomoの実装例
• ConnectionManagerの作成 – XML作成
MithraRuntimeConfig.xml
<MithraRuntime>
<ConnectionManager className="some.package.ConnectionManager">
<MithraObjectConfiguration cacheType="partial" className="some.package.User"/>
・・・
</ConnectionManager>
</MithraRuntime>
ConnectionManagerクラスと
使用するエンティティを列挙
#ccc_m7
Reladomoの実装例
• ConnectionManagerの作成 – XML作成
MithraRuntimeConfig.xml
<MithraRuntime>
<ConnectionManager className="some.package.ConnectionManager">
<MithraObjectConfiguration cacheType="partial" className="some.package.User"/>
・・・
</ConnectionManager>
</MithraRuntime>
キャッシュ戦略
・・・後述
#ccc_m7
Reladomoの実装例
• ConnectionManagerの作成 – アプリ起動時にXML読込
try (InputStream is = ReladomoInitializer.class.getClassLoader()
.getResourceAsStream(“MithraRuntimeConfig.xml”)) {
MithraManagerProvider.getMithraManager().readConfiguration(is);
(中略)
}
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – C(insert)
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – C(insert)
user.xml
UserAbstract UserDatabaseObjectAbstract
UserFinder
UserListAbstract
User UserDatabaseObjectUserList
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – C(insert)
MithraManagerProvider.getMithraManager().executeTransactionalCommand(tx -> {
});
トランザクション宣言
ラムダ式内に実装
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – C(insert)
MithraManagerProvider.getMithraManager().executeTransactionalCommand(tx -> {
User user = new User(System.currentTimeMillis());
});
エンティティインスタンスを作成
同時に営業開始日時をセット
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – C(insert)
MithraManagerProvider.getMithraManager().executeTransactionalCommand(tx -> {
User user = new User(System.currentTimeMillis());
user.setUserId(1);
user.setName("小鳩ミク");
user.setAddress("東京都");
});
他の情報を設定
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – C(insert)
MithraManagerProvider.getMithraManager().executeTransactionalCommand(tx -> {
User user = new User(System.currentTimeMillis());
user.setUserId(1);
user.setName("小鳩ミク");
user.setAddress("東京都");
user.insert();
return user;
});
insertメソッドで挿入
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – C(insert)
User user =
MithraManagerProvider.getMithraManager().executeTransactionalCommand(tx -> {
User user = new User(System.currentTimeMillis());
user.setUserId(1);
user.setName("小鳩ミク");
user.setAddress("東京都");
user.insert();
return user;
});
insert結果を返すことも可能
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – R(select)
user.xml
UserAbstract UserDatabaseObjectAbstract
UserFinder
UserListAbstract
User UserDatabaseObjectUserList
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – R(select)
Operation id = UserFinder.userId().eq(1);
Operation bz = UserFinder.businessDate().equalsEdgePoint();
Operation pr = UserFinder.processingDate().equalsInfinity();
Finderを使って検索条件を作成
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – R(select)
Operation id = UserFinder.userId().eq(1);
Operation bz = UserFinder.businessDate().equalsEdgePoint();
Operation pr = UserFinder.processingDate().equalsInfinity();
User user = UserFinder.findOne(id.and(bz).and(pr));
findOneメソッドで1件検索
select * from user
where user_id = 1 and
out_z = '9999-12-01 23:59:00.000'
Inf
6/1
5/3
5/1
4/1
3/25
BusinessTime(from_z/thru_z)
E
3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
D
B
C
A
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – R(select)
Operation id = UserFinder.userId().eq(1);
Operation bz = UserFinder.businessDate().equalsEdgePoint();
Operation pr = UserFinder.processingDate().equalsInfinity();
UserList userList = UserFinder.findMany(id.and(bz).and(pr));
findManyメソッドで複数件検索
Inf
6/1
5/3
5/1
4/1
3/25
BusinessTime(from_z/thru_z)
E
3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
D
B
C
A
select * from user
where user_id = 1 and
out_z = '9999-12-01 23:59:00.000'
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – R(select)
Operation id = UserFinder.userId().eq(1);
Operation bz = UserFinder.businessDate().equalsEdgePoint();
Operation pr = UserFinder.processingDate().eq(Timestamp.valueOf("2019-05-15"));
UserList userList = UserFinder.findMany(id.and(bz).and(pr));
過去を切り取る
select * from user
where user_id = 1 and
in_z <= '2019-05-15 00:00:00.000' and
out_z > '2019-05-15 00:00:00.000'
Inf
6/1
5/3
5/1
4/1
3/25
BusinessTime(from_z/thru_z)
E
3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
D
B
C
A
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – R(select)
Operation id = UserFinder.userId().eq(1);
Operation bz = UserFinder.businessDate().eq(Timestamp.valueOf("2019-05-20"));
Operation pr = UserFinder.processingDate().equalsInfinity();
User user = UserFinder.findOne(id.and(bz).and(pr));
businessDateの指定も可能
Inf
6/1
5/3
5/1
4/1
3/25
BusinessTime(from_z/thru_z)
E
3/25 4/1 5/1 3 4 6/1 Inf
Processing Time (in_z/out_z)
D
B
C
A
select * from user
where user_id = 1 and
from_z <= '2019-05-20 00:00:00.000' and
thru_z > '2019-05-20 00:00:00.000‘ and
out_z = '9999-12-01 23:59:00.000'
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – U(update)
user.xml
UserAbstract UserDatabaseObjectAbstract
UserFinder
UserListAbstract
User UserDatabaseObjectUserList
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – U(update)
MithraManagerProvider.getMithraManager().executeTransactionalCommand(tx -> {
Operation id = UserFinder.userId().eq(1);
Operation bz = UserFinder.businessDate().equalsEdgePoint();
Operation pr = UserFinder.processingDate().equalsInfinity();
User user = UserFinder.findOne(id.and(bz).and(pr));
user.setAddress(“神奈川県");
return user;
});
findOne/Manyで検索した後
セッターメソッドで値を更新
トランザクション終了時に
updateを実行
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – U(update)
ユーザーID 名前 住所 from_z thru_z in_z out_z
1 小鳩ミク 東京都 2019/4/1 9999/12/1 2019/3/25 9999/12/1
ユーザーID 名前 住所 from_z thru_z in_z out_z
1 小鳩ミク 東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3
1 小鳩ミク 東京都 2019/4/1 2019/5/3 2019/5/3 9999/12/1
1 小鳩ミク 神奈川県 2019/5/3 9999/12/1 2019/5/3 9999/12/1
↓
update user set out_z = '2019-05-03‘
where user_id = 1 AND thru_z = '9999-12-01' AND out_z = '9999-12-01’;
insert into user (user_id,name,address,from_z,thru_z,in_z,out_z)
values (1,'小鳩ミク','東京都','2019-04-01','2019-05-03','2019-05-03','9999-12-01’);
insert into user (user_id,name,address,from_z,thru_z,in_z,out_z)
values (1,‘小鳩ミク’,‘神奈川県','2019-05-03','9999-12-01','2019-05-03','9999-12-01’);
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – D(delete)
user.xml
UserAbstract UserDatabaseObjectAbstract
UserFinder
UserListAbstract
User UserDatabaseObjectUserList
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – D(delete)
MithraManagerProvider.getMithraManager().executeTransactionalCommand(tx -> {
Operation id = UserFinder.userId().eq(1);
Operation bz = UserFinder.businessDate().equalsEdgePoint();
Operation pr = UserFinder.processingDate().equalsInfinity();
User user = UserFinder.findOne(id.and(bz).and(pr));
user.terminate();
return user;
});
findOne/Manyで検索した後
terminate()で締める
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – D(delete)
ユーザーID 名前 住所 from_z thru_z in_z out_z
1 小鳩ミク 東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3
1 小鳩ミク 東京都 2019/4/1 2019/5/3 2019/5/3 9999/12/1
1 小鳩ミク 神奈川県 2019/5/3 9999/12/1 2019/5/3 9999/12/1
↓
ユーザーID 名前 住所 from_z thru_z in_z out_z
1 小鳩ミク 東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3
1 小鳩ミク 東京都 2019/4/1 2019/5/3 2019/5/3 9999/12/1
1 小鳩ミク 神奈川県 2019/5/3 9999/12/1 2019/5/3 2019/6/1
1 小鳩ミク 神奈川県 2019/5/3 2019/6/1 2019/6/1 9999/12/1
#ccc_m7
Reladomoの実装例
• CRUD操作の例 – D(delete)
↓
update user_Bi-temporal set out_z = '2019-06-01'
where user_id = 1 AND thru_z = '9999-12-01' AND out_z = '9999-12-01';
insert into user_Bi-temporal(user_id,name,address,from_z,thru_z,in_z,out_z)
values (1,'小鳩ミク','神奈川','2019-05-03','2019-06-01','2019-06-01','9999-12-01');
ユーザーID 名前 住所 from_z thru_z in_z out_z
1 小鳩ミク 東京都 2019/4/1 9999/12/1 2019/3/25 2019/5/3
1 小鳩ミク 東京都 2019/4/1 2019/5/3 2019/5/3 9999/12/1
1 小鳩ミク 神奈川県 2019/5/3 9999/12/1 2019/5/3 2019/6/1
1 小鳩ミク 神奈川県 2019/5/3 2019/6/1 2019/6/1 9999/12/1
#ccc_m7
Reladomoの実装例
• リレーションの定義
• Study up!の例
問題マスター
(QuestionMaster)
問題
(Question)
1 多
・EC2の基本 ・EC2は何の略?
・AMIで選択できるOSイメージは?
・大幅な割引を適用できる仕組みは?
・固定の外部IPアドレスを割り当てる
仕組みは?
※問題マスターのIDで関連する
#ccc_m7
Reladomoの実装例
• リレーションの定義
QuestionMaster.xml
<Attribute name=“questionMasterId” javaType="int“
columnName="question_master_id"nullable="false" primaryKey="true"/>
<Relationship cardinality="one-to-many" relatedObject="Question" name="questions">
this.questionMasterId = Question.questionMasterId
</Relationship>
Question.xml
<Attribute name="questionId" javaType="int“
columnName=“question_id” nullable="false" primaryKey="true"/>
<Attribute name="questionMasterId" javaType="int“
columnName="question_master_id" nullable="false"/>
#ccc_m7
Reladomoの実装例
• リレーションの定義
QuestionMaster Question
+ getQuestions() : QuestionList
Operation operation = QuestionMasterFinder.questionMasterId().eq(1);
QuestionMaster questionMaster = QuestionMasterFinder.findOne(operation);
QuestionList list = questionMaster.getQuestions();
Question question = list.get(0);
String contents = question.getContents();
+ getContents() : String
#ccc_m7
Reladomoの実装例
• リレーションの定義
問題マスターを全件読み、問題文を出力
Operation operation = QuestionMasterFinder.all();
QuestionMasterList list = QuestionMasterFinder.findMany(operation); ①
for (QuestionMaster master : list) {
for (Question question : master.getQuestions()) { ②
System.out.println("問題:" + question.getContents());
・・・
① select * from question_master
② select * from question where question_master_id = 1
select * from question where question_master_id = 2
select * from question where question_master_id = 3
・・・
#ccc_m7
Reladomoの実装例
• リレーションの定義
問題マスターを全件読み、問題文を出力
Operation operation = QuestionMasterFinder.all();
QuestionMasterList list = QuestionMasterFinder.findMany(operation); ①
for (QuestionMaster master : list) {
for (Question question : master.getQuestions()) { ②
System.out.println("問題:" + question.getContents());
・・・
① select * from question_master
② select * from question where question_master_id = 1
select * from question where question_master_id = 2
select * from question where question_master_id = 3
・・・
N+1クエリ問題
#ccc_m7
Reladomoの実装例
• リレーションの定義
問題マスターを全件読み、問題文を出力
Operation operation = QuestionMasterFinder.all();
QuestionMasterList list = QuestionMasterFinder.findMany(operation); ①
for (QuestionMaster master : list) {
for (Question question : master.getQuestions()) { ②
System.out.println("問題:" + question.getContents());
・・・
① select * from question_master
② select * from question where question_master_id = 1
select * from question where question_master_id = 2
select * from question where question_master_id = 3
N+1クエリ問題 DeepFetchがあるよ
#ccc_m7
Reladomoの実装例
• リレーションの定義
問題マスターを全件読み、問題文を出力
Operation operation = QuestionMasterFinder.all();
QuestionMasterList list = QuestionMasterFinder.findMany(operation); ①
list.deepFetch(QuestionMasterFinder.questions());
for (QuestionMaster master : list) {
for (Question question : master.getQuestions()) { ②
System.out.println("問題:" + question.getContents());
・・・
① select * from question_master
② select * from question where question_master_id in ( 1 , 2 , 3 )
#ccc_m7
Reladomoの実装例
• リレーションの定義
問題マスターを全件読み、問題文を出力
Operation operation = QuestionMasterFinder.all();
QuestionMasterList list = QuestionMasterFinder.findMany(operation); ①
list.deepFetch(QuestionMasterFinder.questions());
for (QuestionMaster master : list) {
for (Question question : master.getQuestions()) { ②
System.out.println("問題:" + question.getContents());
・・・
① select * from question_master
② select * from question where question_master_id in ( 1 , 2 , 3 )
一度findManyやfindOneで
検索しないといけない
JOINしてSQL 1発で取れないのか?
#ccc_m7
Reladomoの実装例
• ユニットテスト
• H2データベース(on memory)でテスト
• テスト用ConnectionManagerを作成
• テストデータファイルでデータ投入
#ccc_m7
Reladomoの実装例
• ユニットテスト
• H2データベース(on memory)でテスト
• テスト用ConnectionManagerを作成
• テストデータファイルでデータ投入
プロダクションと
同じデータベースを使いたい
性能を計るテストには
向かない
#ccc_m7
Reladomoの実装例
• ユニットテスト
• テスト用ConnectionManagerを作成
private MithraTestResource testResource;
@Before
public void setup() throws Exception {
testResource = new MithraTestResource("MithraRuntimeConfig_test.xml");
ConnectionManagerForTests connectionManager =
ConnectionManagerForTests.getInstance("test_db");
testResource.createSingleDatabase(connectionManager, "test_data.txt");
testResource.setUp();
}
#ccc_m7
Reladomoの実装例
• ユニットテスト
• テスト用ConnectionManagerを作成
MithraRuntimeConfig_test.xml
<MithraRuntime>
<ConnectionManager className="com.gs.fw.common.mithra.test.ConnectionManagerForTests">
<Property name="resourceName" value="test_db"/>
<MithraObjectConfiguration cacheType="partial" className="some.package.User"/>
・・・
</ConnectionManager>
</MithraRuntime>
#ccc_m7
Reladomoの実装例
• ユニットテスト
• テスト用ConnectionManagerを作成
MithraRuntimeConfig_test.xml
<MithraRuntime>
<ConnectionManager className="com.gs.fw.common.mithra.test.ConnectionManagerForTests">
<Property name="resourceName" value="test_db"/>
<MithraObjectConfiguration cacheType="partial" className="some.package.User"/>
・・・
</ConnectionManager>
</MithraRuntime> プロダクション用のXMLとほぼ同じ。
テスト用のConnectionManagerを指定
#ccc_m7
Reladomoの実装例
• ユニットテスト
• テストデータファイルでデータ投入
private MithraTestResource testResource;
@Before
public void setup() throws Exception {
testResource = new MithraTestResource("MithraRuntimeConfig_test.xml");
ConnectionManagerForTests connectionManager =
ConnectionManagerForTests.getInstance("test_db");
testResource.createSingleDatabase(connectionManager, "test_data.txt");
testResource.setUp();
}
#ccc_m7
Reladomoの実装例
• ユニットテスト
• テストデータファイルでデータ投入
test_data.txt
class some.package.User
userId, name, address, businessDateFrom, businessDateTo, processingDateFrom, processingDateTo
1, “小鳩ミク”, “東京都”, "2019-01-01", "9999-12-01", "2019-01-01", "9999-12-01“
2, ”彩姫” , “東京都”, "2019-01-01", "9999-12-01", "2019-01-01", "9999-12-01“
3, ”遠乃 歌波” , “東京都”, "2019-01-01", "9999-12-01", "2019-01-01", "9999-12-01“
4, ”廣瀬 茜” , “東京都”, "2019-01-01", "9999-12-01", "2019-01-01", "9999-12-01“
5, ”ミサ” , “東京都”, "2019-01-01", "9999-12-01", "2019-01-01", "9999-12-01“
class some.package.XXX
・・・
class some.package.XXX
・・・
#ccc_m7
Reladomoの実装例
• ユニットテスト
• テストデータファイルでデータ投入
test_data.txt
class some.package.User
userId, name, address, businessDateFrom, businessDateTo, processingDateFrom, processingDateTo
1, “小鳩ミク”, “東京都”, "2019-01-01", "9999-12-01", "2019-01-01", "9999-12-01“
2, ”彩姫” , “東京都”, "2019-01-01", "9999-12-01", "2019-01-01", "9999-12-01“
3, ”遠乃 歌波” , “東京都”, "2019-01-01", "9999-12-01", "2019-01-01", "9999-12-01“
4, ”廣瀬 茜” , “東京都”, "2019-01-01", "9999-12-01", "2019-01-01", "9999-12-01“
5, ”ミサ” , “東京都”, "2019-01-01", "9999-12-01", "2019-01-01", "9999-12-01“
class some.package.XXX
・・・
class some.package.XXX
・・・
エンティティクラス名
フィールドリスト
データ
複数エンティティ対応
#ccc_m7
Reladomoの実装例
• ユニットテスト
• テストデータファイルでデータ投入
private MithraTestResource testResource;
@After
public void tearDown() throws Exception {
testResource.tearDown();
}
テストリソースの後始末
#ccc_m7
Reladomoの実装例
• プライマリキー生成戦略
• Max
• Sequence
#ccc_m7
Reladomoの実装例
• プライマリキー生成戦略
user.xml
<MithraObject objectType="transactional" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="mithraobject.xsd">
<Attribute name="userId" javaType="long" columnName="user_id" nullable="false“ primaryKey="true“
primaryKeyGeneratorStrategy="Max"/>
</MithraObject>
対象テーブルの最大値で
PKを作成
#ccc_m7
Reladomoの実装例
• プライマリキー生成戦略
user.xml
<MithraObject objectType="transactional" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="mithraobject.xsd">
<Attribute name="userId" javaType="long" columnName="user_id" nullable="false“ primaryKey="true“
primaryKeyGeneratorStrategy="SimulatedSequence">
<SimulatedSequence sequenceName="sequenceName"
sequenceObjectFactoryName="sequenceObjectFactory"
hasSourceAttribute="false"
batchSize="10"
initialValue="1"
incrementSize="1"/>
</Attribute>
</MithraObject>
Reladomoが管理する
シーケンス
#ccc_m7
Reladomoの実装例
• キャッシュ戦略
• データをキャッシュしてデータベースアクセスを最小に
• エンティティ単位にキャッシュ方法を指定可能
MithraRuntimeConfig.xml
<MithraRuntime>
<ConnectionManager className="some.package.ConnectionManager">
<MithraObjectConfiguration cacheType="partial" className="some.package.User"/>
・・・
</ConnectionManager>
</MithraRuntime>
キャッシュの方法を
エンティティ単位で指定可能
#ccc_m7
Reladomoの実装例
• キャッシュ戦略
• partial
• 一度検索したものはメモリにキャッシュする
• full
• 起動時にメモリにキャッシュする
#ccc_m7
Reladomoの実装例
• キャッシュ戦略
• partial
• 一度検索したものはメモリにキャッシュする
• full
• 起動時にメモリにキャッシュする
システム稼働中に
SQLでデータベースを直接更新したら
キャッシュには反映されない・・・
#ccc_m7
Reladomoの実装例
• キャッシュ戦略
• partial
• 一度検索したものはメモリにキャッシュする
• full
• 起動時にメモリにキャッシュする
システム稼働中に
SQLでデータベースを直接更新したら
キャッシュには反映されない・・・
後述のReladomo Notificationが
解決してくれるかも
#ccc_m7
Reladomoの実装例
• Auto Scale(クラスタリング)対策
• Reladomo Notification
Reladomoが動作するJVM間で通知し、キャッシュなど情報を共有
#ccc_m7
Reladomoの実装例
• Auto Scale(クラスタリング)対策
• Reladomo Notification
Reladomoが動作するJVM間で通知し、キャッシュなど情報を共有
ひとつのEC2でしか動かしていないので
わかりません・・・。
#ccc_m7
メリット / デメリット / 課題
• メリット
• Bi-temporalなデータを扱うなら唯一の選択
• SQLを書かなくてOK
• デメリット
• MySQL非対応
• SQLを書けない
• Reladomoを前提としたテーブル設計が必要
• 課題
• キャッシュ更新どうする?
• Springのトランザクション(@Transactional)と連携させる
には?
• 任意のテーブル同士をJOINしたい場合は?
#ccc_m7
まとめ
• データの履歴管理をするならReladomo一択
• 自分でSQLを書きたいならDomaかMyBatis
• 既存のシステムに導入するには難あり
• (あたりまえだが)公式ドキュメントは熟読しよう
• 非公式ドキュメントは少(マイナーライブラリ)
• Reladomo Kataで試そう

Contenu connexe

Tendances

AWS Black Belt Online Seminar AWS Direct Connect
AWS Black Belt Online Seminar AWS Direct ConnectAWS Black Belt Online Seminar AWS Direct Connect
AWS Black Belt Online Seminar AWS Direct ConnectAmazon Web Services Japan
 
マイクロサービス 4つの分割アプローチ
マイクロサービス 4つの分割アプローチマイクロサービス 4つの分割アプローチ
マイクロサービス 4つの分割アプローチ増田 亨
 
ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方増田 亨
 
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみようドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう増田 亨
 
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design PatternAWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design PatternAmazon Web Services Japan
 
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)NTT DATA Technology & Innovation
 
ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)
ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)
ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)Amazon Web Services Japan
 
Springを何となく使ってる人が抑えるべきポイント
Springを何となく使ってる人が抑えるべきポイントSpringを何となく使ってる人が抑えるべきポイント
Springを何となく使ってる人が抑えるべきポイント土岐 孝平
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪Takuto Wada
 
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...Google Cloud Platform - Japan
 
開発速度が速い #とは(LayerX社内資料)
開発速度が速い #とは(LayerX社内資料)開発速度が速い #とは(LayerX社内資料)
開発速度が速い #とは(LayerX社内資料)mosa siru
 
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
DDDのモデリングとは何なのか、 そしてどうコードに落とすのかDDDのモデリングとは何なのか、 そしてどうコードに落とすのか
DDDのモデリングとは何なのか、 そしてどうコードに落とすのかKoichiro Matsuoka
 
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3 データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3 Hiroshi Ito
 
Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)
Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)
Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)NTT DATA Technology & Innovation
 
マルチテナントのアプリケーション実装〜実践編〜
マルチテナントのアプリケーション実装〜実践編〜マルチテナントのアプリケーション実装〜実践編〜
マルチテナントのアプリケーション実装〜実践編〜Yoshiki Nakagawa
 
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなテスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなKentaro Matsui
 
【15-B-7】無意味なアラートからの脱却 ~ Datadogを使ってモダンなモニタリングを始めよう ~
【15-B-7】無意味なアラートからの脱却 ~ Datadogを使ってモダンなモニタリングを始めよう ~【15-B-7】無意味なアラートからの脱却 ~ Datadogを使ってモダンなモニタリングを始めよう ~
【15-B-7】無意味なアラートからの脱却 ~ Datadogを使ってモダンなモニタリングを始めよう ~Developers Summit
 
ウォーターフォールとアジャイルを考える #ita_ws
ウォーターフォールとアジャイルを考える #ita_wsウォーターフォールとアジャイルを考える #ita_ws
ウォーターフォールとアジャイルを考える #ita_wsYusuke Suzuki
 
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...NTT DATA Technology & Innovation
 
40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていること40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていることonozaty
 

Tendances (20)

AWS Black Belt Online Seminar AWS Direct Connect
AWS Black Belt Online Seminar AWS Direct ConnectAWS Black Belt Online Seminar AWS Direct Connect
AWS Black Belt Online Seminar AWS Direct Connect
 
マイクロサービス 4つの分割アプローチ
マイクロサービス 4つの分割アプローチマイクロサービス 4つの分割アプローチ
マイクロサービス 4つの分割アプローチ
 
ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方
 
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみようドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう
 
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design PatternAWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
 
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
 
ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)
ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)
ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)
 
Springを何となく使ってる人が抑えるべきポイント
Springを何となく使ってる人が抑えるべきポイントSpringを何となく使ってる人が抑えるべきポイント
Springを何となく使ってる人が抑えるべきポイント
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...
 
開発速度が速い #とは(LayerX社内資料)
開発速度が速い #とは(LayerX社内資料)開発速度が速い #とは(LayerX社内資料)
開発速度が速い #とは(LayerX社内資料)
 
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
DDDのモデリングとは何なのか、 そしてどうコードに落とすのかDDDのモデリングとは何なのか、 そしてどうコードに落とすのか
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
 
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3 データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
 
Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)
Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)
Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)
 
マルチテナントのアプリケーション実装〜実践編〜
マルチテナントのアプリケーション実装〜実践編〜マルチテナントのアプリケーション実装〜実践編〜
マルチテナントのアプリケーション実装〜実践編〜
 
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなテスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるな
 
【15-B-7】無意味なアラートからの脱却 ~ Datadogを使ってモダンなモニタリングを始めよう ~
【15-B-7】無意味なアラートからの脱却 ~ Datadogを使ってモダンなモニタリングを始めよう ~【15-B-7】無意味なアラートからの脱却 ~ Datadogを使ってモダンなモニタリングを始めよう ~
【15-B-7】無意味なアラートからの脱却 ~ Datadogを使ってモダンなモニタリングを始めよう ~
 
ウォーターフォールとアジャイルを考える #ita_ws
ウォーターフォールとアジャイルを考える #ita_wsウォーターフォールとアジャイルを考える #ita_ws
ウォーターフォールとアジャイルを考える #ita_ws
 
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
 
40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていること40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていること
 

Similaire à Reladomoを使ったトランザクション履歴管理をプロダクトに適用した際のメリット/デメリット/課題など

「ものづくり」の現場に必要な機能を備えたスケールアウト型データベース GridDBとそのオープンソース活動 ~膨大なIoTデータの管理を実現 ~
「ものづくり」の現場に必要な機能を備えたスケールアウト型データベース GridDBとそのオープンソース活動 ~膨大なIoTデータの管理を実現 ~「ものづくり」の現場に必要な機能を備えたスケールアウト型データベース GridDBとそのオープンソース活動 ~膨大なIoTデータの管理を実現 ~
「ものづくり」の現場に必要な機能を備えたスケールアウト型データベース GridDBとそのオープンソース活動 ~膨大なIoTデータの管理を実現 ~griddb
 
電通、リクルート、サントリーショッピングクラブ、有名企業がいち早く選んだ kintone を徹底解説
電通、リクルート、サントリーショッピングクラブ、有名企業がいち早く選んだ kintone を徹底解説電通、リクルート、サントリーショッピングクラブ、有名企業がいち早く選んだ kintone を徹底解説
電通、リクルート、サントリーショッピングクラブ、有名企業がいち早く選んだ kintone を徹底解説Cybozucommunity
 
kintoneハンズオン♪
kintoneハンズオン♪kintoneハンズオン♪
kintoneハンズオン♪Sakae Saito
 
Crystal Ball - 10.Output and Analytics of Results
Crystal Ball - 10.Output and Analytics of ResultsCrystal Ball - 10.Output and Analytics of Results
Crystal Ball - 10.Output and Analytics of ResultsKaitoKojima
 
<マネーフォワード×税理士法人ビジネスナビゲーション> 中小企業経営を強くする、経理・財務業務のクラウド化とは?
<マネーフォワード×税理士法人ビジネスナビゲーション> 中小企業経営を強くする、経理・財務業務のクラウド化とは?<マネーフォワード×税理士法人ビジネスナビゲーション> 中小企業経営を強くする、経理・財務業務のクラウド化とは?
<マネーフォワード×税理士法人ビジネスナビゲーション> 中小企業経営を強くする、経理・財務業務のクラウド化とは?Money Forward, Inc.
 
【株式会社メンバーズ】テレワーク実証実験報告書
【株式会社メンバーズ】テレワーク実証実験報告書【株式会社メンバーズ】テレワーク実証実験報告書
【株式会社メンバーズ】テレワーク実証実験報告書Members_corp
 
マルチエージェント強化学習 (MARL) と M^3RL
マルチエージェント強化学習 (MARL) と M^3RLマルチエージェント強化学習 (MARL) と M^3RL
マルチエージェント強化学習 (MARL) と M^3RLHarukaKiyohara
 
チケットの棚卸し ウチではこうしてます
チケットの棚卸し ウチではこうしてますチケットの棚卸し ウチではこうしてます
チケットの棚卸し ウチではこうしてます靖宏 田中
 
リクルーティングパートナーシップのご提案
リクルーティングパートナーシップのご提案リクルーティングパートナーシップのご提案
リクルーティングパートナーシップのご提案DIVE INTO CODE Corp.
 
Tableauエンジニア育成の取り組み
Tableauエンジニア育成の取り組みTableauエンジニア育成の取り組み
Tableauエンジニア育成の取り組みHiroshi Masuda
 
Power BI のいろいろな活用パターン
Power BI のいろいろな活用パターンPower BI のいろいろな活用パターン
Power BI のいろいろな活用パターンYugo Shimizu
 
~バランススコアカードでの評価事例~ CMS導入で日々進化するウェブサイトへ
~バランススコアカードでの評価事例~ CMS導入で日々進化するウェブサイトへ~バランススコアカードでの評価事例~ CMS導入で日々進化するウェブサイトへ
~バランススコアカードでの評価事例~ CMS導入で日々進化するウェブサイトへloftwork
 
応用情報・午後・ストラテジ系を解く(H21秋)
応用情報・午後・ストラテジ系を解く(H21秋)応用情報・午後・ストラテジ系を解く(H21秋)
応用情報・午後・ストラテジ系を解く(H21秋)higher_tomorrow
 
120124 jgc information systems conference be st_pro to salesforce
120124 jgc information systems conference be st_pro to salesforce120124 jgc information systems conference be st_pro to salesforce
120124 jgc information systems conference be st_pro to salesforceMasato Fujioka
 
スケコン_サービス資料_220506no-animepitch.pptx
スケコン_サービス資料_220506no-animepitch.pptxスケコン_サービス資料_220506no-animepitch.pptx
スケコン_サービス資料_220506no-animepitch.pptxssuser06a5211
 
HCCソフト(株)2024新卒 会社説明会
HCCソフト(株)2024新卒 会社説明会HCCソフト(株)2024新卒 会社説明会
HCCソフト(株)2024新卒 会社説明会JiiMoya
 
【SFO2020】業務SEを7か月でWebエンジニアに変える方法 ~アジャイルマインドを得るために~
【SFO2020】業務SEを7か月でWebエンジニアに変える方法 ~アジャイルマインドを得るために~【SFO2020】業務SEを7か月でWebエンジニアに変える方法 ~アジャイルマインドを得るために~
【SFO2020】業務SEを7か月でWebエンジニアに変える方法 ~アジャイルマインドを得るために~Yukio Okajima
 
開発者からサポートエンジニアにジョブチェンジした話
開発者からサポートエンジニアにジョブチェンジした話開発者からサポートエンジニアにジョブチェンジした話
開発者からサポートエンジニアにジョブチェンジした話Ito Takayuki
 

Similaire à Reladomoを使ったトランザクション履歴管理をプロダクトに適用した際のメリット/デメリット/課題など (20)

「ものづくり」の現場に必要な機能を備えたスケールアウト型データベース GridDBとそのオープンソース活動 ~膨大なIoTデータの管理を実現 ~
「ものづくり」の現場に必要な機能を備えたスケールアウト型データベース GridDBとそのオープンソース活動 ~膨大なIoTデータの管理を実現 ~「ものづくり」の現場に必要な機能を備えたスケールアウト型データベース GridDBとそのオープンソース活動 ~膨大なIoTデータの管理を実現 ~
「ものづくり」の現場に必要な機能を備えたスケールアウト型データベース GridDBとそのオープンソース活動 ~膨大なIoTデータの管理を実現 ~
 
OP2024
OP2024OP2024
OP2024
 
電通、リクルート、サントリーショッピングクラブ、有名企業がいち早く選んだ kintone を徹底解説
電通、リクルート、サントリーショッピングクラブ、有名企業がいち早く選んだ kintone を徹底解説電通、リクルート、サントリーショッピングクラブ、有名企業がいち早く選んだ kintone を徹底解説
電通、リクルート、サントリーショッピングクラブ、有名企業がいち早く選んだ kintone を徹底解説
 
kintoneハンズオン♪
kintoneハンズオン♪kintoneハンズオン♪
kintoneハンズオン♪
 
Crystal Ball - 10.Output and Analytics of Results
Crystal Ball - 10.Output and Analytics of ResultsCrystal Ball - 10.Output and Analytics of Results
Crystal Ball - 10.Output and Analytics of Results
 
<マネーフォワード×税理士法人ビジネスナビゲーション> 中小企業経営を強くする、経理・財務業務のクラウド化とは?
<マネーフォワード×税理士法人ビジネスナビゲーション> 中小企業経営を強くする、経理・財務業務のクラウド化とは?<マネーフォワード×税理士法人ビジネスナビゲーション> 中小企業経営を強くする、経理・財務業務のクラウド化とは?
<マネーフォワード×税理士法人ビジネスナビゲーション> 中小企業経営を強くする、経理・財務業務のクラウド化とは?
 
【株式会社メンバーズ】テレワーク実証実験報告書
【株式会社メンバーズ】テレワーク実証実験報告書【株式会社メンバーズ】テレワーク実証実験報告書
【株式会社メンバーズ】テレワーク実証実験報告書
 
マルチエージェント強化学習 (MARL) と M^3RL
マルチエージェント強化学習 (MARL) と M^3RLマルチエージェント強化学習 (MARL) と M^3RL
マルチエージェント強化学習 (MARL) と M^3RL
 
チケットの棚卸し ウチではこうしてます
チケットの棚卸し ウチではこうしてますチケットの棚卸し ウチではこうしてます
チケットの棚卸し ウチではこうしてます
 
リクルーティングパートナーシップのご提案
リクルーティングパートナーシップのご提案リクルーティングパートナーシップのご提案
リクルーティングパートナーシップのご提案
 
Tableauエンジニア育成の取り組み
Tableauエンジニア育成の取り組みTableauエンジニア育成の取り組み
Tableauエンジニア育成の取り組み
 
Power BI のいろいろな活用パターン
Power BI のいろいろな活用パターンPower BI のいろいろな活用パターン
Power BI のいろいろな活用パターン
 
Minitabへようこそ
MinitabへようこそMinitabへようこそ
Minitabへようこそ
 
~バランススコアカードでの評価事例~ CMS導入で日々進化するウェブサイトへ
~バランススコアカードでの評価事例~ CMS導入で日々進化するウェブサイトへ~バランススコアカードでの評価事例~ CMS導入で日々進化するウェブサイトへ
~バランススコアカードでの評価事例~ CMS導入で日々進化するウェブサイトへ
 
応用情報・午後・ストラテジ系を解く(H21秋)
応用情報・午後・ストラテジ系を解く(H21秋)応用情報・午後・ストラテジ系を解く(H21秋)
応用情報・午後・ストラテジ系を解く(H21秋)
 
120124 jgc information systems conference be st_pro to salesforce
120124 jgc information systems conference be st_pro to salesforce120124 jgc information systems conference be st_pro to salesforce
120124 jgc information systems conference be st_pro to salesforce
 
スケコン_サービス資料_220506no-animepitch.pptx
スケコン_サービス資料_220506no-animepitch.pptxスケコン_サービス資料_220506no-animepitch.pptx
スケコン_サービス資料_220506no-animepitch.pptx
 
HCCソフト(株)2024新卒 会社説明会
HCCソフト(株)2024新卒 会社説明会HCCソフト(株)2024新卒 会社説明会
HCCソフト(株)2024新卒 会社説明会
 
【SFO2020】業務SEを7か月でWebエンジニアに変える方法 ~アジャイルマインドを得るために~
【SFO2020】業務SEを7か月でWebエンジニアに変える方法 ~アジャイルマインドを得るために~【SFO2020】業務SEを7か月でWebエンジニアに変える方法 ~アジャイルマインドを得るために~
【SFO2020】業務SEを7か月でWebエンジニアに変える方法 ~アジャイルマインドを得るために~
 
開発者からサポートエンジニアにジョブチェンジした話
開発者からサポートエンジニアにジョブチェンジした話開発者からサポートエンジニアにジョブチェンジした話
開発者からサポートエンジニアにジョブチェンジした話
 

Plus de なべ

Javaで学ぶネットワークプログラミングの基礎
Javaで学ぶネットワークプログラミングの基礎Javaで学ぶネットワークプログラミングの基礎
Javaで学ぶネットワークプログラミングの基礎なべ
 
普通のJavaエンジニアが、なぜ技術書を出版するに至ったか?
普通のJavaエンジニアが、なぜ技術書を出版するに至ったか?普通のJavaエンジニアが、なぜ技術書を出版するに至ったか?
普通のJavaエンジニアが、なぜ技術書を出版するに至ったか?なべ
 
Spring bootでweb セキュリティ(ログイン認証)編
Spring bootでweb セキュリティ(ログイン認証)編Spring bootでweb セキュリティ(ログイン認証)編
Spring bootでweb セキュリティ(ログイン認証)編なべ
 
Spring bootでweb バリデート編
Spring bootでweb バリデート編Spring bootでweb バリデート編
Spring bootでweb バリデート編なべ
 
Spring bootでweb ユニットテスト編
Spring bootでweb ユニットテスト編Spring bootでweb ユニットテスト編
Spring bootでweb ユニットテスト編なべ
 
Spring bootでweb 基本編
Spring bootでweb 基本編Spring bootでweb 基本編
Spring bootでweb 基本編なべ
 
Lombokのススメ
LombokのススメLombokのススメ
Lombokのススメなべ
 
はじめてのSpring Boot
はじめてのSpring BootはじめてのSpring Boot
はじめてのSpring Bootなべ
 

Plus de なべ (8)

Javaで学ぶネットワークプログラミングの基礎
Javaで学ぶネットワークプログラミングの基礎Javaで学ぶネットワークプログラミングの基礎
Javaで学ぶネットワークプログラミングの基礎
 
普通のJavaエンジニアが、なぜ技術書を出版するに至ったか?
普通のJavaエンジニアが、なぜ技術書を出版するに至ったか?普通のJavaエンジニアが、なぜ技術書を出版するに至ったか?
普通のJavaエンジニアが、なぜ技術書を出版するに至ったか?
 
Spring bootでweb セキュリティ(ログイン認証)編
Spring bootでweb セキュリティ(ログイン認証)編Spring bootでweb セキュリティ(ログイン認証)編
Spring bootでweb セキュリティ(ログイン認証)編
 
Spring bootでweb バリデート編
Spring bootでweb バリデート編Spring bootでweb バリデート編
Spring bootでweb バリデート編
 
Spring bootでweb ユニットテスト編
Spring bootでweb ユニットテスト編Spring bootでweb ユニットテスト編
Spring bootでweb ユニットテスト編
 
Spring bootでweb 基本編
Spring bootでweb 基本編Spring bootでweb 基本編
Spring bootでweb 基本編
 
Lombokのススメ
LombokのススメLombokのススメ
Lombokのススメ
 
はじめてのSpring Boot
はじめてのSpring BootはじめてのSpring Boot
はじめてのSpring Boot
 

Reladomoを使ったトランザクション履歴管理をプロダクトに適用した際のメリット/デメリット/課題など