はまる!JPA(初学者向けライト版)

25.7K Views

May 26, 22

スライド概要

JJUG CCC 2015 Springでの資料です。

profile-image

Java、Spring、IntelliJ IDEA

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

はまる!JPA (初学者向けライト版) 株式会社カサレアル 多田真敏 JJUG CCC 2015 Spring 2015/4/11(土) (C) CASAREAL, Inc. All rights reserved. 1

2.

このセッションについて  ハッシュタグ #ccc_cd2  JPAについて基礎、および初学者の方が 間違えやすい「はまりポイント」を 解説します (C) CASAREAL, Inc. All rights reserved. 2

3.

自己紹介  多田真敏(ただまさとし)  (株)カサレアル  大阪出身、香川育ちの31歳  Java EE 7などを中心に研修講師やってます  JJUG CCCは3回連続3回目の出場  SNS  Twitter:@suke_masa  はてなブログ:Java EE 事始め!  GitHub:https://github.com/MasatoshiTada (C) CASAREAL, Inc. All rights reserved. 3

4.

目次 ① JPAの概要 ② CRUD操作とエンティティの状態 ③ 1対Nのリレーション ④ Java Persistence Query Language(JPQL) (C) CASAREAL, Inc. All rights reserved. 4

5.

①JPAの概要 (C) CASAREAL, Inc. All rights reserved. 5

6.

JPA(Java Persistence API)  Java EE標準のORマッパー  .NETにも影響を与えている  ADO.NET Entity Framework (C) CASAREAL, Inc. All rights reserved. 6

7.

JPAの特徴:高生産性・高機能  設定ファイル(XML)が少ない  Hibernateのようなマッピングファイルは不 要  CoC(設定より規約)によるもの  1対Nなどのリレーションをエンティティ で表現できる  DB製品非依存な問合せが可能 (C) CASAREAL, Inc. All rights reserved. 7

8.

JPAのバージョン Java EE JPA JSR Java EE 5 1.0 220 Java EE 6 2.0 317 Java EE 7 2.1 338 Java EE 8 2.2? 338? 説明 EJBの一部 EJBから独立 ★今ここ! Java SE 8対応? (C) CASAREAL, Inc. All rights reserved. 8

9.

仕様と実装  JPAで決まっているのは仕様のみ (≒インターフェイスの集合)  実装  EclipseLink(参照実装)  GlassFish・WebLogicに内包  Hibernate  WildFly・JBossに内包。Springも。  その他の実装はJPA 2.1未対応 (C) CASAREAL, Inc. All rights reserved. 9

10.

今回の開発環境  EclipseLink 2.5.2  Java DB(JDKに内包)  JDK 8u40+Maven(Java SE環境)  NetBeans 8.0.2  JPA実装やDB製品、その他の環境によって、 挙動が若干異なることがあります (C) CASAREAL, Inc. All rights reserved. 10

11.

エンティティクラス  IDEで自動生成可能  NetBeansが一番楽  IntelliJ IDEAは高機能だが少し手順が複雑  Eclipseは不安定  詳しい手順はこちら↓ http://masatoshitada.hatenadiary.jp/entry /2014/05/11/153725 (C) CASAREAL, Inc. All rights reserved. 11

12.

サンプルDBの構造(一部省略) 顧客 注文 製品 顧客ID 注文No. 顧客ID (FK) 製品ID (FK) 数量 発送費用 注文日付 発送日付 ・・・ 製品ID 製造者ID (FK) 種別コード (FK) 購入価格 ・・・ 顧客名 住所 電話番号 ・・・ 製造者 製造者ID 製造者名 住所 電話番号 ・・・ 種別コード 種別コード 説明 ・・・ (C) CASAREAL, Inc. All rights reserved. 12

13.

生成されたエンティティ(一部抜粋) // 製造者エンティティ @Entity public class Manufacturer ・・・ { @Id private Integer manufacturerId; private String name; private String addressline1; private String addressline2; ・・・ @OneToMany(・・・) private List<Product> productList; // setter/getter・・・ (C) CASAREAL, Inc. All rights reserved. 13

14.
[beta]
生成された設定ファイル
(persistence.xml)
<persistence version=“2.1” ・・・>
<persistence-unit name="samplePU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>hoge.entity.Product</class>
<class>hoge.entity.Manufacturer</class>
・・・
<properties>
<property name="javax.persistence.jdbc.url"
value="jdbc:derby://localhost:1527/sample"/>
<property name="javax.persistence.jdbc.user" value="app"/>
<property name="javax.persistence.jdbc.driver"
value="org.apache.derby.jdbc.ClientDriver"/>
<property name="javax.persistence.jdbc.password" value="app"/>
</properties>
</persistence-unit>
</persistence>
(C) CASAREAL, Inc. All rights reserved.

14

15.

ログ出力の設定(EclipseLinkの場合)  開発時は必ずログを出しましょう! <persistence・・・> <persistence-unit ・・・> ・・・ <properties> ・・・ <property name="eclipselink.logging.level” value="FINE"/> </properties> ・・・ (C) CASAREAL, Inc. All rights reserved. 15

16.

②CRUD操作と エンティティの状態 (C) CASAREAL, Inc. All rights reserved. 16

17.

JPAの概念図 DB entity Entity Manager クライアント プログラム 永続化コンテキスト entity entity entity entity (C) CASAREAL, Inc. All rights reserved. 17

18.

EntityManagerインターフェイス  find()・・・主キー検索  persist()・・・新規追加を予約する  remove()・・・削除を予約する  merge()・・・エンティティを永続化コンテキ スト管理下に置く  detach()・・・エンティティを永続化コンテキ ストから切り離す  flush()・・・永続化コンテキストの変更をDBに 反映する (C) CASAREAL, Inc. All rights reserved. 18

19.

永続化コンテキストとは?  EntityManagerが管理するエンティティ を保持する場所  EntityManagerは、永続化コンテキスト 内のエンティティのみを管理する (C) CASAREAL, Inc. All rights reserved. 19

20.

エンティティの状態 ① NEW状態  エンティティのインスタンスがnewされてすぐ ② MANAGED状態  エンティティが永続化コンテキストの管理下にある ③ DETACHED状態  エンティティが永続化コンテキストの管理下から 切り離されている ④ REMOVED状態  DBからの削除が予約されている (C) CASAREAL, Inc. All rights reserved. 20

21.

★重要★ エンティティの状態遷移 NEW 状態 find() persist() merge() DETACHED 状態 MANAGED 状態 detach() clear() remove() REMOVED 状態 flush() refresh() DB (C) CASAREAL, Inc. All rights reserved. 21

22.

基本的な書き方 persistence.xmlの persistence-unitの name属性 EntityManagerFactory emf = Persistence.createEntityManagerFactory("samplePU"); EntityManager em = emf.createEntityManager(); // 処理 em.close(); emf.close(); (C) CASAREAL, Inc. All rights reserved. 22

23.

主キー検索 エンティティクラス名と 主キー値を指定 Manufacturer m = em.find(Manufacturer.class, 19985678); System.out.println(m.getName()); 実行結果 [EL Fine]: sql: Connection(50826412)--SELECT MANUFACTURER_ID, ADDRESSLINE1, ADDRESSLINE2, CITY, EMAIL, FAX, NAME, PHONE, REP, STATE, ZIP FROM MANUFACTURER WHERE (MANUFACTURER_ID = ?) bind => [19985678] Happy End Searching SELECT文が発行される (C) CASAREAL, Inc. All rights reserved. 23

24.

新規追加 EntityTransaction tx = em.getTransaction(); tx.begin(); Manufacturer m = new Manufacturer(); m.setManufacturerId(1); m.setName("HOGE"); em.persist(m); persist()で永続化 →flush()でDBに反映 em.flush(); →commit()で確定 tx.commit(); (C) CASAREAL, Inc. All rights reserved. 24

25.

新規追加 INSERT文が発行される 実行結果 [EL Fine]: sql: Connection(1168076863)--INSERT INTO MANUFACTURER (MANUFACTURER_ID, ADDRESSLINE1, ADDRESSLINE2, CITY, EMAIL, FAX, NAME, PHONE, REP, STATE, ZIP) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) bind => [1, null, null, null, null, null, HOGE, null, null, null, null] レコードが追加される (C) CASAREAL, Inc. All rights reserved. 25

26.

更新 EntityTransaction tx = em.getTransaction(); tx.begin(); Manufacturer m = em.find(Manufacturer.class, 1); m.setName("FUGA"); find()で取ってくる em.flush(); →setterで変更 tx.commit(); →flush()でDBに反映 (C) CASAREAL, Inc. All rights reserved. 26

27.

更新 実行結果 [EL Fine]: sql: Connection(1168076863)--SELECT MANUFACTURER_ID, ADDRESSLINE1, ADDRESSLINE2, CITY, EMAIL, FAX, NAME, PHONE, REP, STATE, ZIP FROM MANUFACTURER WHERE (MANUFACTURER_ID = ?) bind => [1] [EL Fine]: sql: Connection(1168076863)-UPDATE MANUFACTURER SET NAME = ? WHERE (MANUFACTURER_ID = ?) bind => [FUGA, 1] 変更した列のみ UPDATEする (C) CASAREAL, Inc. All rights reserved. 27

28.

更新時の注意点  対象のエンティティがMANAGED状態でな いと、更新が反映されない  方法①:find()で検索したものを変更する  方法②:newしたエンティティをmerge()す る (C) CASAREAL, Inc. All rights reserved. 28

29.

これでも更新可能 EntityTransaction tx = em.getTransaction(); tx.begin(); Manufacturer m = new Manufacturer(); m.manufacturerId(1); m.setName("FUGA"); em.merge(m); newしてmerge() em.flush(); tx.commit(); (C) CASAREAL, Inc. All rights reserved. 29

30.

これでも更新可能 実行結果 [EL Fine]: sql: Connection(1168076863)--SELECT MANUFACTURER_ID, ADDRESSLINE1, ADDRESSLINE2, CITY, EMAIL, FAX, NAME, PHONE, REP, STATE, ZIP FROM MANUFACTURER WHERE (MANUFACTURER_ID = ?) bind => [1] [EL Fine]: sql: Connection(1168076863)--UPDATE MANUFACTURER SET NAME = ? WHERE (MANUFACTURER_ID = ?) bind => [FUGA, 1] merge()時にSELECT →flush()時にUPDATE (C) CASAREAL, Inc. All rights reserved. 30

31.

削除 EntityTransaction tx = em.getTransaction(); tx.begin(); Manufacturer m = new Manufacturer(); m.manufacturerId(1); m.setName("FUGA"); em.remove(m); em.flush(); tx.commit(); (C) CASAREAL, Inc. All rights reserved. 31

32.

削除 実行結果 Exception in thread "main" java.lang.IllegalArgumentException: Entity must be managed to call remove: com.example.entity.Manufacturer[ manufacturerId =1 ], try merging the detached and try the remove again. 例外!? (C) CASAREAL, Inc. All rights reserved. 32

33.

はまりポイント①  削除だけできません問題 (C) CASAREAL, Inc. All rights reserved. 33

34.

【再確認】エンティティの状態遷移 NEW 状態 find() MANAGED状態 じゃないと remove()できない persist() merge() DETACHED 状態 MANAGED 状態 detach() clear() コミット remove() REMOVED 状態 flush() コミット refresh() DB (C) CASAREAL, Inc. All rights reserved. 34

35.

merge()して削除 EntityTransaction tx = em.getTransaction(); tx.begin(); Manufacturer m = new Manufacturer(); m.manufacturerId(1); m.setName("FUGA"); em.merge(m); merge()すれば em.remove(m); remove()できるはず!? em.flush(); tx.commit(); (C) CASAREAL, Inc. All rights reserved. 35

36.

merge()して削除 実行結果 Exception in thread "main" java.lang.IllegalArgumentException: Entity must be managed to call remove: com.example.entity.Manufacturer[ manufacturerId =1 ], try merging the detached and try the remove again. 同じ例外!? MANAGEDになってない!? (C) CASAREAL, Inc. All rights reserved. 36

37.

はまりポイント②  merge()できません問題 (C) CASAREAL, Inc. All rights reserved. 37

38.

Javadocを確認 merge()に戻り値がある!? (C) CASAREAL, Inc. All rights reserved. 38

39.

JSR 338(JPA 2.1の仕様)を確認  3.2.7.1 Merging Detached Entity State  エンティティXがDETACHED状態の場合、  Xと同じ識別子を持つMANAGED状態のX’にコピー される  またはMANAGED状態のX’が新規生成される merge()の引数のコピーがMANAGED状態になり、 それが戻り値となる →引数自体はMANAGED状態にならない! (C) CASAREAL, Inc. All rights reserved. 39

40.

削除プログラムを修正 merge()の戻り値をremove() EntityTransaction tx = em.getTransaction(); tx.begin(); Manufacturer m = new Manufacturer(); m.manufacturerId(1); m.setName("FUGA"); Manufacturer managedManu = em.merge(m); em.remove(managedManu); em.flush(); tx.commit(); (C) CASAREAL, Inc. All rights reserved. 40

41.

削除プログラムを修正 実行結果 [EL Fine]: sql: Connection(1168076863)--SELECT MANUFACTURER_ID, ADDRESSLINE1, ADDRESSLINE2, CITY, EMAIL, FAX, NAME, PHONE, REP, STATE, ZIP FROM MANUFACTURER WHERE (MANUFACTURER_ID = ?) bind => [1] [EL Fine]: sql: Connection(1168076863)--DELETE FROM MANUFACTURER WHERE (MANUFACTURER_ID = ?) bind => [1] ちゃんと削除されてる! (C) CASAREAL, Inc. All rights reserved. 41

42.

別解  別解①:find()で取得したエンティティ をremove()する  find()したものはMANAGED状態  別解②:DELETE文を使う  DBへのアクセスが1回で済む (C) CASAREAL, Inc. All rights reserved. 42

43.

もう少し詳しく  merge()でもINSERTは可能  persist()は主キー重複の際は例外発生、 merge()は主キー重複の際は例外にならず、 SELECT後にUPDATEする  flush()時に、MANAGED状態のエンティティ と、DBとの差分(変更分)を一気に反映す る  SQL発行タイミング等はJPA実装によって異 なる (C) CASAREAL, Inc. All rights reserved. 43

44.

③1対Nの リレーション (C) CASAREAL, Inc. All rights reserved. 44

45.

リレーション  @OneToMany、@ManyToOneで表現 @Entity public class Manufacturer { // 製造者 @OneToMany(・・・) private List<Product> productList; ・・・ @Entity public class Product { // 製品 @ManyToOne(・・・) private Manufacturer manufacturer; ・・・ (C) CASAREAL, Inc. All rights reserved. 45

46.

カスケード  関連のあるエンティティに対して、 道連れに同じ操作を行う  CascadeTypeはALL、DETACH、FLUSH、 PERSIST、REFRESH、REMOVEの6種類 @Entity public class Manufacturer { @OneToMany(cascade = CascadeType.ALL) private List<Product> productList; ・・・ (C) CASAREAL, Inc. All rights reserved. 46

47.

カスケードの活用例  受注(1側)と受注明細(N側)を一括登録 受注 order = new 受注(・・・); order.addDetail(new 受注明細(・・・)); order.addDetail(new 受注明細(・・・)); order.addDetail(new 受注明細(・・・)); // 3つの受注明細も同時にINSERTされる em.persist(order); (C) CASAREAL, Inc. All rights reserved. 47

48.

フェッチ  関連のあるエンティティを、 どのタイミングで読み込むか  FetchType.EAGER:即時読み込み  FetchType.LAZY:遅延読み込み @Entity public class Manufacturer { @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) private List<Product> productList; ・・・ (C) CASAREAL, Inc. All rights reserved. 48

49.

よくあるサンプル  社員(Employee)と部署(Department)  社員:部署はN:1 emp_id name 101 Y.Aragaki 102 R.Matsui 103 104 dept_id 1 1 dept_id name 1 SALES 2 DEVELOP E.Ikuta 2 R.Sakurai 2 (C) CASAREAL, Inc. All rights reserved. 49

50.

部署を1つ削除 EntityTransaction tx = em.getTransaction(); Department d = em.find(Department.class, 1); em.remove(d); tx.commit(); 部署ID=1の部署を削除 (C) CASAREAL, Inc. All rights reserved. 50

51.

削除した結果 部署だけでなく、 社員も消えてる!? (C) CASAREAL, Inc. All rights reserved. 51

52.

はまりポイント③  データ吹っ飛びました問題 (C) CASAREAL, Inc. All rights reserved. 52

53.
[beta]
何故こうなったのか
CascadeType.ALL
かつ
FetchType.EAGER

@Entity
public class Department {
・・・
@OneToMany(mappedBy = "department",
cascade = CascadeType.ALL,
fetch = FetchType.EAGER)
private List<Employee> employeeList;

(C) CASAREAL, Inc. All rights reserved.

53

54.

何故こうなったのか EntityTransaction tx = em.getTransaction(); Department d = em.find(Department.class, 1); em.remove(d); tx.commit(); このタイミングで、 関連する社員も 同時に読み込まれる 部署と道連れに 社員も削除される (C) CASAREAL, Inc. All rights reserved. 54

55.

ログ SELECT DEPT_ID, NAME FROM DEPARTMENT WHERE (DEPT_ID = ?) bind => [1] SELECT EMP_ID, NAME, DEPT_ID FROM EMPLOYEE WHERE (DEPT_ID = ?) bind => [1] DELETE FROM EMPLOYEE WHERE (EMP_ID = ?) bind => [101] DELETE FROM EMPLOYEE WHERE (EMP_ID = ?) bind => [102] DELETE FROM DEPARTMENT WHERE (DEPT_ID = ?) bind => [1] (C) CASAREAL, Inc. All rights reserved. 55

56.

解決策  カスケードはALL禁止!  IDEで自動生成すると、ALLになっている 場合があるので注意  フェッチは基本的にLAZY! (C) CASAREAL, Inc. All rights reserved. 56

57.

エンティティ自動生成時の注意点  自動生成時に、デフォルトで CascadeType.ALLになることがある  自動生成後は、必ずカスケード設定を 確認しましょう! (C) CASAREAL, Inc. All rights reserved. 57

58.

動的にフェッチ戦略を変える方法  時間の都合上、キーワードのみご紹介  方法①:JPQLでJOIN  方法②:Entity FETCH文を使う Graphを使う (C) CASAREAL, Inc. All rights reserved. 58

59.

動的にカスケード戦略を変える方法  EclipseLinkの独自機能  https://wiki.eclipse.org/EclipseLink/Examp les/JPA/Dynamic#Relationships より  試したかったけど、サンプルコードのリン クが切れてて確認できず(泣)  JPAの標準機能になってほしい! OneToManyMapping mapping = ・・・; mapping.setCascadeMerge(true); (C) CASAREAL, Inc. All rights reserved. 59

60.

④Java Persistence Query Language (JPQL) (C) CASAREAL, Inc. All rights reserved. 60

61.

JPQLとは?  JPA専用の問合せ言語  SQLに似て非なるもの  SELECT文、UPDATE文、DELETE文の3種類  INSERT文は無い (C) CASAREAL, Inc. All rights reserved. 61

62.

JPQLのメリット  DB製品のSQL方言などに依存せず、問合せ を記述できるので、ポータビリティが高い  ただし、検証は自己責任でお願いします  事例(@kikutaro_さん)  GlassFish+SQL Serverのアプリを、 組込GlassFish+Derbyに移殖  https://speakerdeck.com/kikutaro/chumetefalse-java-ee-kai-fa-karaxue-ndakotojjug-ccc-2014-spring (C) CASAREAL, Inc. All rights reserved. 62

63.
[beta]
基本的な使い方
String jpql = “SELECT m FROM Manufacturer m ”
+ “WHERE m.name LIKE :name”;
TypedQuery<Manufacturer> query =
em.createQuery(jpql, Manufacturer.class);
query.setParameter(“name”, “B%”);
List<Manufacturer> list = query.getResultList();
for (Manufacturer m : list) {
System.out.println(m.getManufacturerId()
+ ":" + m.getName());
}
(C) CASAREAL, Inc. All rights reserved.

63

64.

基本的な使い方 SQLに変換して 実行される 実行結果 [EL Fine]: sql: Connection(1168076863)--SELECT MANUFACTURER_ID, ADDRESSLINE1, ADDRESSLINE2, CITY, EMAIL, FAX, NAME, PHONE, REP, STATE, ZIP FROM MANUFACTURER WHERE NAME LIKE ? bind => [B%] 19971233:Bills Bank and Sons 19985590:Birders United 19955564:Birders United 19955565:Birders United 19984681:Birders United 19984682:Birders United 19941212:Birders United 19987296:Birders United (C) CASAREAL, Inc. All rights reserved. 64

65.

よくある間違い これはJPQLではなく、 ほぼSQL! String jpql = “select m from manufacturer m ” + “where name like :name”; 実行結果 Exception in thread "main" java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager: Exception Description: Problem compiling [select m from manufacturer m where m.name like :name]. [14, 26] The abstract schema type 'manufacturer' is unknown. (C) CASAREAL, Inc. All rights reserved. 65

66.

はまりポイント④  JPQLのつもりがSQL書いちゃった問題 (C) CASAREAL, Inc. All rights reserved. 66

67.

SQLとJPQLの違い① FROM句に別名が必須(識別変数) 識別変数が必須 (identification variable) ○ SELECT m FROM Manufacturer m; × SELECT Manufacturer FROM Manufacturer; (C) CASAREAL, Inc. All rights reserved. 67

68.

SQLとJPQLの違い② 列抽出では識別変数が必須 ○ SELECT m.manufacturerId, m.name FROM Manufacturer m; × SELECT manufacturerId, name FROM Manufacturer m; SQLとしては正しいが、 JPQLとしては正しくない (C) CASAREAL, Inc. All rights reserved. 68

69.

SQLとJPQLの違い③ JPQLは一部Case Sensitive JPQLは基本的に Case Sensitiveと 考えた方がいい!  SELECTなどのJPQLの予約語 →大文字・小文字は区別されない  エンティティクラス名・プロパティ名など →大文字・小文字が区別される  識別変数→大文字・小文字は区別されない ○ SELECT m FROM Manufacturer m; ○ select m from Manufacturer m; × select m from manufacturer m; ○ select M from Manufacturer m; (C) CASAREAL, Inc. All rights reserved. 69

70.

SQLとJPQLの違い④ 副問い合わせ  JSR 338 4.6.16 Subqueries  副問い合わせはWHERE句またはHAVING句で 使用できる。 FROM句では副問い合わせが使えない! ※JSRには「今後のバージョンで考えるかも」と書いてある (C) CASAREAL, Inc. All rights reserved. 70

71.

JPQLのスペルミスを防ぐ方法① NetBeansのJPQL実行ツール  persistence.xmlを右クリック →[JPQL問い合わせの実行]  Ctrl+Spaceで補完が可能 (C) CASAREAL, Inc. All rights reserved. 71

72.

JPQLのスペルミスを防ぐ方法② 名前付きクエリ  エンティティクラスに@NamedQueryを付加  Ctrl+Spaceで補完が可能  JPQLをエンティティに集約できるので便利 (C) CASAREAL, Inc. All rights reserved. 72

73.

まとめ (C) CASAREAL, Inc. All rights reserved. 73

74.

まとめ JPAのメリット  Java EEの標準技術であること  設定ファイルがほぼ不要  カスケードによる一括処理  EntityManagerやJPQLによる、 DB製品に依存しない問合せ (C) CASAREAL, Inc. All rights reserved. 74

75.

まとめ JPAのはまりポイント  エンティティの状態が大切! merge()とremove()は特に注意!  CascadeType.ALLは禁止!  JPQLはSQLではありません!  JPA実装やDB製品によって挙動が異なる 場合がありますので、必ずログを出して、 挙動を確かめながら開発しましょう! (C) CASAREAL, Inc. All rights reserved. 75

76.

紹介しきれなかった はまりポイント  EclipseLinkだと勝手にパラメータ化され ちゃう問題  http://masatoshitada.hatenadiary.jp/entry /2014/12/21/100818  JOINしてるのに列が取れてない問題  DISTINCTの意味が違う問題 (C) CASAREAL, Inc. All rights reserved. 76

77.

さらに勉強したい方へ  書籍  マスタリングJava EE 5 第2版  Beginning Java EE 6  Javaパフォーマンス←NEW!!  公式資料  Java  JSR EE 7 Tutorial Chapter 37~44(英語) 338(英語) (C) CASAREAL, Inc. All rights reserved. 77

78.

さらに勉強したい方へ  勉強会情報など  はまる!JPA(@makingさん)  金魚本に載ってないJPQLの話 (@megascusさん)  JPAの同時実行制御とロック(拙著)  今日この後!  大規模な負荷でもドキドキしない為の Java EE(@nagaseyasuhitoさん) (C) CASAREAL, Inc. All rights reserved. 78

79.

今回のソースコード  GitHubにアップしています  https://github.com/MasatoshiTada/hamaru -jpa-light MVC 1.0(Java EE 8)の サンプルもあります! (C) CASAREAL, Inc. All rights reserved. 79

80.

Enjoy JPA!!  ご清聴ありがとうございました! (C) CASAREAL, Inc. All rights reserved. 80