1. Reladomo in Scala
株式会社FOLIO 伊藤博志
グッドフロー・テクノロジーズ 瀬良和弘
Scala関西 Summit 2017.9.9
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.
X
38. 37
Finder API:一件検索
Operation findTaroOp =
PersonFinder.firstName().eq(“太郎");
Person taro =
PersonFinder.findOne(findTaroOp);
Finder APIを用いてOperationを作成
Finder.findOne()で一件検索
結果はEntityオブジェクトで取得
39. 38
val taro: Option[Person] =
PersonFinder.findOne(findTaroOp)
val taro: Option[Person] =
PersonFinder.findOneWith(_.firstName.eq(“太郎”))
Finder API:一件検索
val findTaroOp =
PersonFinder.firstName.eq(“太郎")
Finder APIを用いてOperationを作成
Finder.findOne()で一件検索
結果はEntityオブジェクトで取得
40. 39
Finder API:複数検索
Operation findAllOp = PersonFinder.all();
PersonList people =
PersonFinder.findMany(findAllOp);
Finder APIを用いてOperationを作成
Finder.findMany()で複数検索
結果はListオブジェクトで取得
41. 40
Finder API:複数検索
val findAllOp = PersonFinder.all
val people = PersonFinder.findManyWith(_.all)
Finder APIを用いてOperationを作成
Finder.findMany()で複数検索
結果はListオブジェクトで取得
42. 41
Finder API:Operationの例1
Operation op1 = PersonFinder.firstName().eq("大輔");
// SQL: WHERE first_name = '大輔’
Operation op2 = PersonFinder.lastName().endsWith("藤");
// SQL: WHERE last_name LIKE '%藤’
Operation op1OrOp2 = op1.or(op2);
// SQL: WHERE (( first_name = '大輔') OR ( last_name LIKE '%藤'))
Operation op1AndOp2 = op1.and(op2);
// SQL: WHERE (( first_name = '大輔') AND ( last_name LIKE '%藤'))
43. 42
Finder API:Operationの例1
val op1 = PersonFinder.firstName.eq("大輔")
// SQL: WHERE first_name = '大輔’
val op2 = PersonFinder.lastName.endsWith("藤")
// SQL: WHERE last_name LIKE '%藤’
val op1OrOp2 = op1 || op2
// SQL: WHERE (( first_name = '大輔') OR ( last_name LIKE '%藤'))
val op1AndOp2 = op1 && op2
// SQL: WHERE (( first_name = '大輔') AND ( last_name LIKE '%藤'))
// Scalaでは and/or 条件が非常に柔軟に書ける!
Finder.findManyWith { q => (q.firstName.eq(”XXX") ||
q.firstName.eq(”YYY")) && (…)) }
44. 43
Operation op3 =
PersonFinder.age().in(IntHashSet.newSetWith(22, 24, 30));
// SQL: WHERE age in (22, 24, 30)
Operation op4 =
PersonFinder.age().notIn(IntHashSet.newSetWith(22, 25));
// SQL: WHERE age in (22, 25)
Operation op5 =
PersonFinder.age().greaterThan(25);
// SQL: WHERE age > 25
その他複雑なクエリを型安全に記述することが可能
Finder API:Operationの例2
45. 44
val op3 = PersonFinder.age.in(Set(22, 24, 30))
// SQL: WHERE age in (22, 24, 30)
val op4 = PersonFinder.age.notIn(Set(22, 25))
// SQL: WHERE age in (22, 25)
val op5 = PersonFinder.age.greaterThan(25)
// SQL: WHERE age > 25
その他複雑なクエリを型安全に記述することが可能
Finder API:Operationの例2
48. 47
val taro = PersonFinder.findOne(_.firstName.eq("太郎"))
val op1 = PersonFinder.firstName.eq("大輔")
val op2 = PersonFinder.lastName.endsWith("藤")
val people2 = PersonFinder.findMany(op1 || op2))
people2.forceResolve()
val op3 = PersonFinder.age.greaterThan(25)
val people3 = PersonFinder.findMany(op3)
people3.forceResolve()
3種類の条件の違うクエリーは直接DBを叩く
ReIadomoのキャッシュ
49. 48
2017-07-23 18:02:06:881 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person -
connection:2005169944 find with: select t0.person_id,t0.first_name,t0.last_name,t0.age from person t0
where t0.first_name = '太郎’
2017-07-23 18:02:06:891 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - retrieved 1 objects,
83.0 ms per
2017-07-23 18:02:06:992 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person -
connection:2005169944 find with: select t0.person_id,t0.first_name,t0.last_name,t0.age from person t0
where (( t0.first_name = '大輔') or ( t0.last_name like '%藤'))
2017-07-23 18:02:06:994 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - retrieved 3 objects,
1.3333333333333333 ms per
2017-07-23 18:02:06:997 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person -
connection:2005169944 find with: select t0.person_id,t0.first_name,t0.last_name,t0.age from person t0
where t0.age > 25
2017-07-23 18:02:07:005 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - retrieved 1 objects,
8.0 ms per
ReIadomoのキャッシュ
3回のDBアクセス
hashtag: #scala_ks_main
50. 49
val people = PersonFinder.findManyWith(_.all)
val findTaroOp = PersonFinder.firstName.eq(“太郎")
… 前ページと同じ3つのクエリー
前ページと同じ3種類のクエリーの直前に全選択の
クエリーを走らせると…
ReIadomoのキャッシュ
51. 50
2017-07-23 19:34:04:415 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person -
connection:112049309 find with: select t0.person_id,t0.first_name,t0.last_name,t0.age from person
t02017-07-23 19:34:04:458 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - retrieved 4
objects, 25.5 ms per
ReIadomoのキャッシュ
1回のDBアクセスで全選択
●DBへのIOは全選択クエリーの1回のみ
●その後のクエリーはキャッシュから取得
hashtag: #scala_ks_main
59. 58
val tanaka = PersonFinder.findOneWith(_.lastName.eq("田中"))
tanaka.copy(age = 25).update()
Reladomoの更新処理:単一更新
Entityインスタンスを検索
setter で更新しない update/delete 呼ぶまでは DB
に反映はしない
バイテンポラルの場合も有効時間の指定以外はほぼ
同じコードで表現できる(後述)
60. 59
Reladomoの更新処理:複数更新
複数検索でListオブジェクトを取得
val people = PersonFinder.findManyWith(_.all)
people.withAge(20).updateAll()
2017-07-23 21:45:08:489 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - multi update of 6
objects with: update person set age = ? where person_id in (?...)
2017-07-23 21:45:08:489 [main] DEBUG com.gs.fw.common.mithra.batch.sqllogs.Person - multi updating
with: update person set age = 20 where person_id in (0,1,2,3,4,5)
61. 60
Reladomoの更新処理:バッチ更新
Entityインスタンスを検索
トランザクション内での複数更新はバッチ更新される
val tanaka = PersonFinder.findOneWith(_.lastName.eq(“田中”))
val sato = PersonFinder.findOneWith(_.lastName.eq(“佐藤”))
TransactionProvider.withTransaction { implicit tx =>
tanaka.copy(age = 25).update()
sato.copy(age = 23).update()
}
2017-07-23 21:38:39:403 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - batch update of 2
objects with: update person set age = ? where person_id = ?
2017-07-23 21:38:39:404 [main] DEBUG com.gs.fw.common.mithra.batch.sqllogs.Person - batch
updating with: update person set age = 25 where person_id = 0
2017-07-23 21:38:39:405 [main] DEBUG com.gs.fw.common.mithra.batch.sqllogs.Person - batch
updating with: update person set age = 23 where person_id = 1