データ履歴管理のためのテンポラルデータモデルとreladomoの紹介 #jjug_ccc...

76
データ履歴管理のための テンポラルデータモデルと Reladomoの紹介 株式会社FOLIO 伊藤博志 JJUG CCC 2017 Spring 2017.5.20 #ccc_g3 Reladomo is an open source software Licensed under Apache 2.0 License, Copyright 2016 Goldman Sachs, Its name may be a trademark of its owner.

Upload: hiroshi-ito

Post on 21-Jan-2018

37.910 views

Category:

Engineering


5 download

TRANSCRIPT

Page 1: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

データ履歴管理のための

テンポラルデータモデルと

Reladomoの紹介

株式会社FOLIO 伊藤博志

JJUG CCC 2017 Spring 2017.5.20

#ccc_g3

Reladomo is an open source software Licensed under Apache 2.0 License,Copyright 2016 Goldman Sachs, Its name may be a trademark of its owner.

Page 2: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

1

株式会社FOLIOの紹介 hashtag: #ccc_g3

https://www.wantedly.com/companies/folio/projectsエンジニア募集中!

Page 3: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

2

Agenda

1. 自己紹介

2. RDBMSで履歴データを扱う

スナップショットデータモデル

トランザクション時間データモデル

有効時間データモデル

バイテンポラルデータモデル

3. Javaからバイテンポラルモデルを容易に扱うReladomoの紹介

hashtag: #ccc_g3

Page 4: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

3

自己紹介

趣味:ドラム演奏

JavaOneコミュニティバンド

Null Pointersで演奏経験あり(日本人初)

Tech Lead @ FOLIO

伊藤 博志

Eclipse Collections:共同プロジェクトリード兼コミッターReladomo:コントリビューターOpenJDK:コントリビューターJJUG CCC、Java Day Tokyo、JavaOne San Francisco登壇

2017年5月17日に株式会社FOLIO入社。

hashtag: #ccc_g3

Page 5: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

4

RDBMSで変更履歴をどう扱うか

hashtag: #ccc_g3

Page 6: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

5

RDBMSで履歴データを扱う

単純なシナリオを考えてみましょう

シンプルな人事システム。扱う情報は姓名のみ。

4月1日に「鈴木花子」さん入社。3月1日にシステムに登録

6月6日に結婚し、姓が「斎藤」に変更。同日システム上に間違えて「斉藤」と登録

6月8日にシステム上で修正(斉藤=>斎藤) 。事実としては6月6日づけで直したい

12月1日、退職にともない同日にシステム上で情報を無効化

hashtag: #ccc_g3

Page 7: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

6

RDBMSで履歴データを扱う

シナリオをよく観察すると、2種類の履歴が存在

hashtag: #ccc_g3

3/1 4/1 6/6 6/8 12/1

鈴木花子

事実情報の履歴

システムに反映された

履歴

入社🎉

「鈴木花子」をシステムに登録

結婚して斎藤になる👰

名字を「斉藤」に変更

名字を「斎藤」に変更

退職†

データを無効化

Page 8: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

7

RDBMSで履歴データを扱う

最新の情報さえ分かれば良い

いつシステムに反映されたか履歴が知りたい

2種類の履歴から考えうる4種類の要件

事実情報の履歴が知りたい

事実情報と、いつシステムに反映されたか両方の履歴が知りたい

hashtag: #ccc_g3

Page 9: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

8

RDBMSで履歴データを扱う

スナップショットデータモデル

トランザクション時間データモデル

有効時間データモデル

バイテンポラルデータモデル

各要件を満たすために、4つのデータモデルが考えられる

hashtag: #ccc_g3

Page 10: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

9

スナップショットデータモデル

hashtag: #ccc_g3

最新の情報さえ分かれば良い

Page 11: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

10

スナップショットデータモデル

スナップショットデータモデルで表現できるのは、最新の情報のみ(履歴は表現できない)

hashtag: #ccc_g3

3/1 4/1 6/6 6/8 12/1

鈴木花子

事実情報の履歴

システムに反映された

履歴

入社🎉

「鈴木花子」をシステムに登録

結婚して斎藤になる👰

名字を「斉藤」に変更

名字を「斎藤」に変更

退職†

データを無効化

Page 12: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

11

スナップショットデータモデル

姓 名 inserted_at updated_at

鈴木 花子 2017/3/1 2017/3/1

4月1日に「鈴木花子」さん入社。3月1日にシステムに登録

鈴木さん入社!

入社日というカラムがあってもいいような気がする

hashtag: #ccc_g3

Page 13: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

12

スナップショットデータモデル

6月6日に結婚し、姓が「斎藤」に変更。同日システム上に間違えて「斉藤」と登録

間違えて「斉藤」と入力してしまいました

姓 名 inserted_at updated_at

斉藤 花子 2017/3/1 2017/6/6

hashtag: #ccc_g3

Page 14: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

13

スナップショットデータモデル

6月8日にシステム上で修正(斉藤=>斎藤)

正しい姓は「斎藤」さんですね。。。

姓 名 inserted_at updated_at

斎藤 花子 2017/3/1 2017/6/8

hashtag: #ccc_g3

Page 15: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

14

スナップショットデータモデル

12月1日、退職にともない同日に人事情報をシステム上で無効化

_人人人人人人人人人人人_> 物理削除 < ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄

物理削除がイヤなら禁断の論理削除フラグという手もあるよ。フフッ

姓 名 inserted_at updated_at

hashtag: #ccc_g3

Page 16: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

15

スナップショットデータモデル

スナップショットデータモデルで履歴を実装しようとすると、バージョンカラムや履歴テーブルを別に用意するなど、力技が求められる

世に存在する履歴系のデータは、この力技で実装されていることが多い(印象)

さらにスナップショットデータモデルでは、データを無効化するのに「論理削除」か「物理削除」か、と悩むケースも

hashtag: #ccc_g3

Page 17: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

16

トランザクション時間データモデル

hashtag: #ccc_g3

いつシステムに反映されたか履歴が知りたい

Page 18: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

17

トランザクション時間データモデル

トランザクション時間データモデルで表現できるのは、「システムに反映された」履歴

hashtag: #ccc_g3

3/1 4/1 6/6 6/8 12/1

鈴木花子

事実情報の履歴

システムに反映された

履歴

入社🎉

「鈴木花子」をシステムに登録

結婚して斎藤になる👰

名字を「斉藤」に変更

名字を「斎藤」に変更

退職†

データを無効化

Page 19: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

18

トランザクション時間データモデル

姓 名 IN OUT

鈴木 花子 2017/3/1 9999/12/1

鈴木さん入社!

INはデータベースに挿入された日付、OUTはその行が無効になった(なる)日付、OUTはデフォルトでINFINITY(この場合9999年)とするよ

やっぱり入社日カラムが欲しくなる。。

4月1日に「鈴木花子」さん入社。3月1日にシステムに登録

hashtag: #ccc_g3

Page 20: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

19

トランザクション時間データモデル

姓 名 IN OUT

鈴木 花子 2017/3/1 2017/6/6

斉藤 花子 2017/6/6 9999/12/1

鈴木さん姓が2017/6/6に無効(OUT)になり、斉藤さん姓が同日入力(IN)されたということだね

6月6日に結婚し、姓が「斎藤」に変更。同日システム上に間違えて「斉藤」と登録

hashtag: #ccc_g3

Page 21: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

20

トランザクション時間データモデル

姓 名 IN OUT

鈴木 花子 2017/3/1 2017/6/6

斉藤 花子 2017/6/6 2017/6/8

斎藤 花子 2017/6/8 9999/12/1

斉藤さん姓が2017/6/8に無効(OUT)になり、斎藤さん姓が同日入力(IN)されたということだね

6月8日にシステム上で修正(斉藤=>斎藤) 。事実としては6月6日づけで直したい

「斎藤」姓がシステム上有効なのは6/8からか。。

hashtag: #ccc_g3

Page 22: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

21

トランザクション時間データモデル

姓 名 IN OUT

鈴木 花子 2017/3/1 2017/6/6

斉藤 花子 2017/6/6 2017/6/8

斎藤 花子 2017/6/8 2017/12/1

2017/12/1日付で無効化(OUT)!

12月1日、退職にともない同日に人事情報をシステム上で無効化

hashtag: #ccc_g3

Page 23: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

22

トランザクション時間データモデル

履歴データをどう検索するのか?

hashtag: #ccc_g3

Page 24: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

23

トランザクション時間データモデル

任意の時間Xにデータベース上で最新だった情報をとってくる

select * from EMPLOYEE

where IN < X

and OUT >= X

hashtag: #ccc_g3

Page 25: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

24

トランザクション時間データモデル

姓 名 IN OUT

鈴木 花子 2017/3/1 2017/6/6

3月15日時点でデータベース上で最新だった情報をとってくる

select * from EMPLOYEE

where IN < “2017/3/15”

and OUT >= “2017/3/15”

姓 名 IN OUT

鈴木 花子 2017/3/1 2017/6/6

斉藤 花子 2017/6/6 2017/6/8

斎藤 花子 2017/6/8 2017/12/1

hashtag: #ccc_g3

Page 26: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

25

トランザクション時間データモデル

姓 名 IN OUT

斉藤 花子 2017/6/6 2017/6/8

select * from EMPLOYEE

where IN < “2017/6/7”

and OUT >= “2017/6/7”

姓 名 IN OUT

鈴木 花子 2017/3/1 2017/6/6

斉藤 花子 2017/6/6 2017/6/8

斎藤 花子 2017/6/8 2017/12/1

6月7日時点でデータベース上で最新だった情報をとってくる

hashtag: #ccc_g3

Page 27: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

26

トランザクション時間データモデル

姓 名 IN OUT

斎藤 花子 2017/6/8 2017/12/1

姓 名 IN OUT

鈴木 花子 2017/3/1 2017/6/6

斉藤 花子 2017/6/6 2017/6/8

斎藤 花子 2017/6/8 2017/12/1

6月9日時点でデータベース上で最新だった情報をとってくる

select * from EMPLOYEE

where IN < “2017/6/9"

and OUT >= “2017/6/9”

hashtag: #ccc_g3

Page 28: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

27

トランザクション時間データモデル

姓 名 IN OUT

select * from EMPLOYEE

where IN < “2017/12/5"

and OUT >= “2017/12/5”

姓 名 IN OUT

鈴木 花子 2017/3/1 2017/6/6

斉藤 花子 2017/6/6 2017/6/8

斎藤 花子 2017/6/8 2017/12/1

2017/12/1以降に有効な行が存在しないので、論理削除フラグを使わなくてもシステム上で無効化されている!

12月5日時点でデータベース上で最新だった情報をとってくる

hashtag: #ccc_g3

Page 29: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

28

トランザクション時間データモデル

ある時点でデータベース上で最新だった情報を一意に取得することができる

過去の履歴を一気に取得することもでき、時間軸でソートも可

最新の行を無効化するにはOUTコラムを更新するだけでOK(物理削除も論理削除フラグも不要)

監査情報を自然な形でモデリングできる

トランザクション時間データモデルの適用例

ドキュメントの履歴管理

状態遷移の履歴管理

etc.

hashtag: #ccc_g3

Page 30: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

29

有効時間データモデル

hashtag: #ccc_g3

事実情報の履歴がほしい

Page 31: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

30

有効時間データモデル

有効時間データモデルで表現できるのは、「事実情報」の履歴

hashtag: #ccc_g3

3/1 4/1 6/6 6/8 12/1

鈴木花子

事実情報の履歴

システムに反映された

履歴

入社🎉

「鈴木花子」をシステムに登録

結婚して斎藤になる👰

名字を「斉藤」に変更

名字を「斎藤」に変更

退職†

データを無効化

Page 32: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

31

有効時間データモデル

姓 名 FROM THRU

鈴木 花子 2017/4/1 9999/12/1

4月1日に「鈴木花子」さん入社。3月1日にシステムに登録

鈴木さん入社!FROMは当該データが事実として有効である最初の日、THRUは当該データが事実として有効である最終日の翌日*、THRUはデフォルトでINFINITY(この場合9999年)とするよ

これで入社日がわかる。。

*ここではTHRUを最終日翌日としていますが、FROMを最初の日の前日とする方法もあります

hashtag: #ccc_g3

*Throughの略

Page 33: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

32

有効時間データモデル

姓 名 FROM THRU

鈴木 花子 2017/4/1 2017/6/6

斉藤 花子 2017/6/6 9999/12/1

6月6日に結婚し、姓が「斎藤」に変更。同日システム上に間違えて「斉藤」と登録

事実として「鈴木」姓の最終日が2017/6/5(THRU-1)になり、2017/6/6(FROM)から間違った「斉藤」姓が有効に

hashtag: #ccc_g3

Page 34: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

33

有効時間データモデル

姓 名 FROM THRU

鈴木 花子 2017/4/1 2017/6/6

斎藤 花子 2017/6/6 9999/12/1

2017/6/6(FROM)から正しい「斎藤」さん姓になった。間違えた「斉藤」姓は上書きされたので、システム上の履歴はわからないね。

6月8日にシステム上で修正(斉藤=>斎藤) 。事実としては6月6日づけで直したい

hashtag: #ccc_g3

Page 35: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

34

有効時間データモデル

姓 名 FROM THRU

鈴木 花子 2017/4/1 2017/6/6

斎藤 花子 2017/6/6 2017/12/1

12月1日、退職にともない同日に人事情報をシステム上で無効化

これで鈴木さんが2017/4/1に入社、2017/6/6に斎藤姓に代わり、2017/12/1に退社した、という事実情報がすべて表現されるね!

hashtag: #ccc_g3

Page 36: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

35

有効時間データモデル

検索方法はトランザクション時間

データモデルの場合と同様なので省略

hashtag: #ccc_g3

Page 37: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

36

有効時間データモデル

ある時点での「事実情報」を一意に取得することができる

過去の事実の履歴を一気に取得することもでき、時間軸でソートも可

最新の行を無効化するにはTHRUコラムを更新するだけでOK(物理削除も論理削除フラグも不要)

事実の履歴を自然な形でモデリングできる

有効時間データモデルの適用例

変更履歴を気にしないビジネスデータ

etc.

hashtag: #ccc_g3

Page 38: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

37

バイテンポラルデータモデル

hashtag: #ccc_g3

事実情報と、いつシステムに反映されたか両方の履歴が知りたい

Page 39: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

38

バイテンポラルデータモデル

バイテンポラルデータモデルで表現できるのは、「システムに反映された」履歴と「事実情報」の履歴両方

hashtag: #ccc_g3

3/1 4/1 6/6 6/8 12/1

鈴木花子

事実情報の履歴

システムに反映された

履歴

入社🎉

「鈴木花子」をシステムに登録

結婚して斎藤になる👰

名字を「斉藤」に変更

名字を「斎藤」に変更

退職†

データを無効化

Page 40: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

39

バイテンポラルデータモデル

姓 名 FROM THRU IN OUT

鈴木 花子 2017/4/1 9999/12/1 2017/3/1 9999/12/1

4月1日に「鈴木花子」さん入社。3月1日にシステムに登録

鈴木さん入社!

4月1日に入社したこともわかるし、3月1日にシステムに反映されたこともわかる!

hashtag: #ccc_g3

Page 41: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

40

バイテンポラルデータモデル

姓 名 FROM THRU IN OUT

鈴木 花子 2017/4/1 9999/12/1 2017/3/1 2017/6/6

鈴木 花子 2017/4/1 2017/6/6 2017/6/6 9999/12/1

斉藤 花子 2017/6/6 9999/12/1 2017/6/6 9999/12/1

6月6日に結婚し、姓が「斎藤」に変更。同日システム上に間違えて「斉藤」と登録

最初の行が「システム上」無効になり、新しい「事実」が2つの期間にわたって挿入されているね。

hashtag: #ccc_g3

Page 42: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

41

バイテンポラルデータモデル

姓 名 FROM THRU IN OUT

鈴木 花子 2017/4/1 9999/12/1 2017/3/1 2017/6/6

鈴木 花子 2017/4/1 2017/6/6 2017/6/6 9999/12/1

斉藤 花子 2017/6/6 9999/12/1 2017/6/6 2017/6/8

斎藤 花子 2017/6/6 9999/12/1 2017/6/8 9999/12/1

名字の漢字が間違っており、6月8日にシステム上で修正(斉藤=>斎藤)

間違えた行が「システム上」無効になり、正しい「事実」が挿入されているね。

3つ目の行は「斉藤」という間違った事実が「システム上有効だった」期間が6/6から6/8の間存在するという情報を表しているよ。

hashtag: #ccc_g3

Page 43: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

42

バイテンポラルデータモデル

姓 名 FROM THRU IN OUT

鈴木 花子 2017/4/1 9999/12/1 2017/3/1 2017/6/6

鈴木 花子 2017/4/1 2017/6/6 2017/6/6 9999/12/1

斉藤 花子 2017/6/6 9999/12/1 2017/6/6 2017/6/8

斎藤 花子 2017/6/6 9999/12/1 2017/6/8 2017/12/1

斎藤 花子 2017/6/6 2017/12/1 2017/12/1 9999/12/1

12月1日、退職にともない同日に人事情報をシステム上で無効化

無事、事実情報(入社、姓変更、退社)と変更履歴がすべて記録されました!

hashtag: #ccc_g3

Page 44: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

43

バイテンポラルデータモデル

バイテンポラルデータモデルは「システム履歴」と「事実情報の履歴」を同時に正しく表現することができる非常に強力なモデル

バイテンポラルデータモデルの適用例

監査履歴が重要な金融システムの基幹データ

その他、時系列に紐づくビジネスデータで変更履歴が重要なユースケース

etc.

hashtag: #ccc_g3

Page 45: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

44

どう実装する?

バイテンポラルデータモデルの雰囲気はわかった

でも、ぱっと見複雑そう。結局、実装するのが大変なのでは。。。?

安心してください

Reladomoを使えば簡単です!

hashtag: #ccc_g3

Page 46: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

45

Javaからバイテンポラルモデルを容易に扱えるReladomoの紹介

hashtag: #ccc_g3

Page 47: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

46

Reladomoとは

https://github.com/goldmansachs/reladomo

ゴールドマン・サックス社が2016年10月にGitHubにOSSとして公開したJava ORMフレームワーク

Apache License 2.0

バイテンポラルデータモデルをネイティブサポート

強力に型付けられたクエリー言語

シャーディングのネイティブサポート

ユニットテストのフルサポート

etc.

hashtag: #ccc_g3

Page 48: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

47

Reladomoとは

Reladomoのコード生成

xmlによるエンティティ定義を用いてコード生成

同xmlからddlの生成も可能

Abstract Classはxmlに変更のある都度生成される

Concrete Classは初回のみ生成しVCSにコミット、ビジネスロジックを記述。コード生成で上書きされない。

hashtag: #ccc_g3

Page 49: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

48

Employeeエンティティ定義ファイル hashtag: #ccc_g3

<MithraObject objectType="transactional"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="reladomoobject.xsd">

<PackageName>sample.domain</PackageName><ClassName>Employee</ClassName><DefaultTable>EMPLOYEE</DefaultTable>

<Attribute name="employeeId" javaType="int" columnName="EMPLOYEE_ID" primaryKey="true"primaryKeyGeneratorStrategy="SimulatedSequence">

<SimulatedSequence sequenceName="Employee"sequenceObjectFactoryName="sample.util.ObjectSequenceObjectFactory"hasSourceAttribute="false"batchSize="1"initialValue="1"incrementSize="1"/>

</Attribute><Attribute name="firstName" javaType="String" columnName="FIRST_NAME" nullable="false" maxLength="64"/><Attribute name="lastName" javaType="String" columnName="LAST_NAME" nullable="false" maxLength="64"/>

</MithraObject>

Page 50: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

49

Employeeエンティティ hashtag: #ccc_g3

トランザクション時間

生成されたAbstract Class

Page 51: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

50

Employeeエンティティ hashtag: #ccc_g3

Concrete Class (初回のみ生成)

さまざまなビジネスロジックを記述できる

Page 52: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

51

DBトランザクション hashtag: #ccc_g3

テンポラルオブジェクトの挿入、更新はトランザクション内でのみ可能

(以降のコード例では省略している場合も)

Employee hanako = MithraManagerProvider.getMithraManager().executeTransactionalCommand(tx -> {

Employee hanakoNew = new Employee(); hanakoNew.setLastName(“鈴木”);hanakoNew.setFirstName(“花子”);hanakoNew.insert(); return hanakoNew; //トランザクション終了後に使用したいオブジェクトを返り値とし

て与えることができる。});

Page 53: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

52

ReladomoのFinder DSL

型付けられた強力なクエリー言語

自動生成されたフィールドを用いてOperationを構築

hashtag: #ccc_g3

Operation op = EmployeeFinder.lastName().eq("鈴木").and(EmployeeFinder.firstName().eq("花子"));

final Employee hanako = EmployeeFinder.findOne(op);

Page 54: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

53

Reladomoでトランザクション時間を扱う例

hashtag: #ccc_g3

Page 55: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

54

Employeeエンティティ定義ファイル hashtag: #ccc_g3

<MithraObject objectType="transactional"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="reladomoobject.xsd">

<PackageName>sample.domain</PackageName><ClassName>Employee</ClassName><DefaultTable>EMPLOYEE</DefaultTable>

<AsOfAttribute name="processingDate" fromColumnName="IN_Z" toColumnName="OUT_Z"toIsInclusive="false"isProcessingDate="true"infinityDate="[com.gs.fw.common.mithra.util.DefaultInfinityTimestamp.getDefaultInfinity()]"defaultIfNotSpecified="[com.gs.fw.common.mithra.util.DefaultInfinityTimestamp.getDefaultInfinity()]"

/>

<Attribute name="employeeId" javaType="int" columnName="EMPLOYEE_ID" primaryKey="true"primaryKeyGeneratorStrategy="SimulatedSequence">

<SimulatedSequence sequenceName="Employee"sequenceObjectFactoryName="sample.util.ObjectSequenceObjectFactory"hasSourceAttribute="false"batchSize="1"initialValue="1"incrementSize="1"/>

</Attribute><Attribute name="firstName" javaType="String" columnName="FIRST_NAME" nullable="false" maxLength="64"/><Attribute name="lastName" javaType="String" columnName="LAST_NAME" nullable="false" maxLength="64"/>

</MithraObject>

トランザクション時間

Page 56: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

55

トランザクション時間データモデル

姓 名 IN OUT

鈴木 花子 2017/3/1 9999/12/1

hashtag: #ccc_g3

//3月1日にこのコードが実行されるEmployee hanakoNew = new Employee(); //メモリ上にオブジェクト作成hanakoNew.setLastName("鈴木");hanakoNew.setFirstName("花子");hanakoNew.insert(); // データベースに挿入

4月1日に「鈴木花子」さん入社。3月1日にシステムに登録

Page 57: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

56

トランザクション時間データモデル

姓 名 IN OUT

鈴木 花子 2017/3/1 2017/6/6

斉藤 花子 2017/6/6 9999/12/1

6月6日に結婚し、姓が「斎藤」に変更。同日システム上に間違えて「斉藤」と登録

hashtag: #ccc_g3

//6月6日にこのコードが実行されるhanako.setLastName("斉藤"); // アップデート

Page 58: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

57

トランザクション時間データモデル

姓 名 IN OUT

鈴木 花子 2017/3/1 2017/6/6

斉藤 花子 2017/6/6 2017/6/8

斎藤 花子 2017/6/8 9999/12/1

6月8日にシステム上で修正(斉藤=>斎藤) 。事実としては6月6日づけで直したい

hashtag: #ccc_g3

//6月8日にこのコードが実行されるhanako.setLastName(“斎藤"); // アップデート

Page 59: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

58

トランザクション時間データモデル

姓 名 IN OUT

鈴木 花子 2017/3/1 2017/6/6

斉藤 花子 2017/6/6 2017/6/8

斎藤 花子 2017/6/8 2017/12/1

12月1日、退職にともない同日に人事情報をシステム上で無効化

hashtag: #ccc_g3

//12月1日にこのコードが実行されるhanako.terminate(); // OUT = NOW

Page 60: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

59

トランザクション時間データモデル hashtag: #ccc_g3

Timestamp mar5 = Timestamp.valueOf(LocalDateTime.of(2017, 3, 5, 0, 0));Operation op = EmployeeFinder.firstName().eq("花子")

.and(EmployeeFinder.processingDate().eq(mar5));Employee hanakoMar5 = EmployeeFinder.findOne(op);logger.info("Mar 5: " + hanakoMar5.getFullName());

3月5日時点の花子さんを検索

[main] INFO sample.HelloReladomoApp - Mar 5: 鈴木 花子

select t0.EMPLOYEE_ID,t0.FIRST_NAME,t0.LAST_NAME,t0.IN,t0.OUT from EMPLOYEE t0 where t0.FIRST_NAME = '花子' and t0.IN <= '2017-03-05 00:00:00.000' and t0.OUT > '2017-03-05 00:00:00.000'

Page 61: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

60

トランザクション時間データモデル hashtag: #ccc_g3

Timestamp jun7 = Timestamp.valueOf(LocalDateTime.of(2017, 6, 7, 0, 0));Operation op = EmployeeFinder.firstName().eq("花子")

.and(EmployeeFinder.processingDate().eq(jun7));Employee hanakoJum7 = EmployeeFinder.findOne(op);logger.info(”Jun 7: " + hanakoJun7.getFullName());

6月7日時点の花子さんを検索

[main] INFO sample.HelloReladomoApp - June 7: 斉藤 花子

select t0.EMPLOYEE_ID,t0.FIRST_NAME,t0.LAST_NAME,t0.IN,t0.OUT from EMPLOYEE t0 where t0.FIRST_NAME = '花子' and t0.IN <= '2017-06-07 00:00:00.000' and t0.OUT > '2017-06-07 00:00:00.000'

Page 62: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

61

トランザクション時間データモデル hashtag: #ccc_g3

Timestamp jun8 = Timestamp.valueOf(LocalDateTime.of(2017, 6, 8, 0, 0));Operation op = EmployeeFinder.firstName().eq("花子")

.and(EmployeeFinder.processingDate().eq(jun8));Employee hanakoJum8 = EmployeeFinder.findOne(op);logger.info(”Jun 8: " + hanakoJun8.getFullName());

6月8日時点の花子さんを検索

[main] INFO sample.HelloReladomoApp - June 8: 斎藤 花子

select t0.EMPLOYEE_ID,t0.FIRST_NAME,t0.LAST_NAME,t0.IN,t0.OUT from EMPLOYEE t0 where t0.FIRST_NAME = '花子' and t0.IN <= '2017-06-08 00:00:00.000' and t0.OUT > '2017-06-08 00:00:00.000'

Page 63: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

62

トランザクション時間データモデル

Reladomoのトランザクション時間データ操作

IN/OUTカラムにまつわる処理はユーザーが気にすることなくフレームワークが吸収してくれる

デフォルトで最新のデータが検索される(OUT =

INFINITY)

データをある日付(トランザクション時間)から無効化するにはterminate()を使う

過去の履歴の検索の際はprocessingDate()を明示的に指定してやる

hashtag: #ccc_g3

Page 64: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

63

Reladomoでバイテンポラルデータモデルを扱う例

hashtag: #ccc_g3

Page 65: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

64

<MithraObject objectType=“transactional”xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”xsi:noNamespaceSchemaLocation=“reladomoobject.xsd”>

<PackageName>sample.domain</PackageName><ClassName>Employee</ClassName><DefaultTable>EMPLOYEE</DefaultTable>

<AsOfAttribute name=“processingDate” fromColumnName=“IN_Z” toColumnName=“OUT_Z”toIsInclusive=“false”isProcessingDate=“true”timezoneConversion=“none”infinityDate=“[com.gs.fw.common.mithra.util.DefaultInfinityTimestamp.getDefaultInfinity()]”defaultIfNotSpecified=“[com.gs.fw.common.mithra.util.DefaultInfinityTimestamp.getDefaultInfinity()]”

/>

<AsOfAttribute name=“businessDate” fromColumnName=“FROM_Z” toColumnName=“THRU_Z”toIsInclusive=“false”isProcessingDate=“false”timezoneConversion=“none”infinityDate=“[com.gs.fw.common.mithra.util.DefaultInfinityTimestamp.getDefaultInfinity()]”futureExpiringRowsExist=“true”

/>

・・・省略・・・</MithraObject>

Employeeエンティティ定義ファイル hashtag: #ccc_g3

有効時間

Page 66: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

65

バイテンポラルデータモデル

姓 名 FROM THRU IN OUT

鈴木 花子 2017/4/1 9999/12/1 2017/3/1 9999/12/1

4月1日に「鈴木花子」さん入社。3月1日にシステムに登録

hashtag: #ccc_g3

Timestamp apr1 = Timestamp.valueOf(LocalDateTime.of(2017, 4, 1, 0, 0));Employee hanakoNew = new Employee(apr1); //メモリ上にオブジェクト作成hanakoNew.setLastName("鈴木");hanakoNew.setFirstName("花子");hanakoNew.insert(); // データベースに挿入

Page 67: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

66

バイテンポラルデータモデル

6月6日に結婚し、姓が「斎藤」に変更。同日システム上に間違えて「斉藤」と登録

hashtag: #ccc_g3

//まずは6月6日付(有効時間)でフェッチTimestamp jun6 = Timestamp.valueOf(LocalDateTime.of(2017, 6, 6, 0, 0));Operation opJun6 = EmployeeFinder.firstName().eq(“花子”).

and(EmployeeFinder.businessDate().eq(jun6)); //6月6日付でフェッチfinal Employee hanakoJun6 = EmployeeFinder.findOne(opJun6); //遅延ロードされるのでこの時点ではまだフェッチされていない

//6月6日付(有効時間)でフェッチしたオブジェクトをアップデートMithraManagerProvider.getMithraManager().executeTransactionalCommand(tx -> {

//6月6日(トランザクション時間)にこのコードが実行されるhanakoJun6.setLastName("斉藤"); // この時点で遅延フェッチ&アップデートreturn null;

});

*スペースの都合上、以降テーブルは省略

Page 68: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

67

バイテンポラルデータモデル

名字の漢字が間違っており、6月8日にシステム上で修正(斉藤=>斎藤)

hashtag: #ccc_g3

//まずは6月6日付(有効時間)でフェッチTimestamp jun6 = Timestamp.valueOf(LocalDateTime.of(2017, 6, 6, 0, 0));Operation opJun6 = EmployeeFinder.firstName().eq(“花子”).

and(EmployeeFinder.businessDate().eq(jun6)); //6月6日付でフェッチfinal Employee hanakoJun6 = EmployeeFinder.findOne(opJun6); //遅延ロードされるのでこの時点ではまだフェッチされていない

//6月6日付(有効時間)でフェッチしたオブジェクトをアップデートMithraManagerProvider.getMithraManager().executeTransactionalCommand(tx -> {

//6月8日(トランザクション時間)にこのコードが実行されるhanakoJun6.setLastName(“斎藤"); // この時点で遅延フェッチ&アップデートreturn null;

});

Page 69: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

68

バイテンポラルデータモデル

12月1日、退職にともない同日に人事情報をシステム上で無効化

hashtag: #ccc_g3

//まずは12月1日付(有効時間)でフェッチTimestamp dec1 = Timestamp.valueOf(LocalDateTime.of(2017, 12, 1, 0, 0));Operation opDec1 = EmployeeFinder.firstName().eq(“花子”).

and(EmployeeFinder.businessDate().eq(dec1)); //12月1日付でフェッチfinal Employee hanakoDec1 = EmployeeFinder.findOne(opDec1); //遅延ロードされるのでこの時点ではフェッチされない

//12月1日付(有効時間)でフェッチしたオブジェクトをアップデートMithraManagerProvider.getMithraManager().executeTransactionalCommand(tx -> {

//12月1日(トランザクション時間)にこのコードが実行されるhanakoDec1.terminate(); // THRU = 12/1return null;

});

Page 70: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

69

バイテンポラルデータモデル

Reladomoのバイテンポラルデータ操作

オブジェクト作成の際は有効時間の開始時を引数に与える

更新の際は、まず更新したい日付(有効時間)でフェッチする。フェッチしたオブジェクトを更新すると自動でIN/OUT/FROM/THRUが更新・挿入される

データをある日付(有効時間)から無効化するにはterminate()を使う

バイテンポラルデータモデルのテーブル構造を意識することなく処理を記述することが可能

hashtag: #ccc_g3

Page 71: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

70

Reladomoを用いたテンポラルデータモデルの操作

ここで挙げた例はReladomoの機能のさわりのみ

つづきはReladomo Kata / Reladomo Tourで

Reladomo Kata GitHub (Reladomo チュートリアル)

Guided Tour of Reladomo

hashtag: #ccc_g3

Page 72: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

71

まとめ

RDBで履歴を扱う際にはテンポラルデータモデルを用いると素直に表現できる

トランザクション時間と有効時間を組み合わせたテンポラルデータモデルが存在

Reladomoを使うとテンポラルデータモデルの扱いが抽象化できる

ぜひ、みなさんも試してみてください!

hashtag: #ccc_g3

Page 73: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

72

株式会社FOLIOの紹介 hashtag: #ccc_g3

https://www.wantedly.com/companies/folio/projectsエンジニア募集中!

Page 74: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

73

APPENDIX

Page 75: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

74

テンポラルデータモデル hashtag: #ccc_g3

Temporal Data Models(ppt)

Temporal Databases - Richard T. Snodgrass 1998

Temporal Databases - Richard T. Snodgrass and Ilsoo

Ahn 1986

Temporal and Real-Time Databases: A Survey(ppt)

Temporal Data and The Relational Model

Page 76: データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3

75

Reladomo hashtag: #ccc_g3

Reladomo GitHub

Reladomo Kata GitHub (Reladomo チュートリアル)

Guided Tour of Reladomo

Reladomo Documentations