JPAについて
JPAの参照系について
getResultList()の検索件数0件のときはどんな動きになる?
- Size = 0のリストが帰ってくる感じです (nullじゃないので注意)。
entityの静的クエリはじぶんで追加してっていいんだよね?
- なんか、普通に追加したら not foudと言われてしまった……
@NamedQueries({
:
@NamedQuery(name = "Customer.findByIdAndName", query = "SELECT c FROM Customer c WHERE c.customerId = :customerId AND c.name = :name")})
public class Customer implements Serializable {
:
Caused by: java.lang.IllegalArgumentException: NamedQuery of name: Customer.findByIdAndName not found.
結局、なんかデバッガ起動したりしてたら、何も変えずにちゃんと動きました。
意味がわかりませんが、コンテナ?が、追加した@NamedQueryをちゃんと認識するためのトリガーがあるのかな??
JPAの更新系について
- トランザクションは
em.getTransactionでやればOKと思ってたけどこんなんでた。
public void updateCustomers(Customer customer){
EntityTransaction tx = em.getTransaction();
tx.begin();
em.merge(customer);
tx.commit();
}
Caused by: java.lang.IllegalStateException:
Exception Description: Cannot use an EntityTransaction while using JTA.
at org.eclipse.persistence.internal.jpa.transaction.JTATransactionWrapper.getTransaction(JTATransactionWrapper.java:73)
なんか、JavaEEのトランザクションには種類があるっぽい。JTAトランザクションを使うべきところなのに、別のトランザクション使うなよってことかな?
以下のブログによると、persistence.xmlのなかで、RESOURCE_LOCAL/NON-JTA-DATA-SOURCE/JTA-DATA-SOURCEのいずれかが指定されているらしい。
http://nwing.knowd.co.jp/yamazaki/?q=node/118
JTA-DATA-SOURCE
JTAを使って、トランザクションを管理します。
この場合、EntityManager#getTransactionによるトランザクション制御はできなくなります。トランザクションの制御はコンテナが行う(CMT - Contena Manged Transaction)ので、EJBの宣言性トランザクションを使用するか、または、UserTransactionを取得します。EJBと関連が強くなります。
もし、JTA-DATA-SOURCEを使用しているにもかからずEntityManager#getTransactionから取得したEntitTransactionを使用すると、次の例外が発生します。
Exception Description: Cannot use an EntityTransaction while using JTA.
ということみたい。で、JTAを利用する場合のトランザクションはUserTransactionでやってねということらしい。以下のようなかんじで書けばいいっぽい。
@Resource
UserTransaction utx;
:
public void updateCustomers(Customer customer){
// 例外処理省略
utx.begin();
em.merge(customer);
utx.commit();
}
……と思ったらやっぱりダメ。
Caused by: javax.naming.NameNotFoundException: java:comp/UserTransactionのルックアップは、コンテナで管理されるトランザクションBeanでは許可されません
:
... 63 more
ほんとストレスたまるわ!!
:
:
金魚本9章読んだら解決しました!!
EJB内でのトランザクションの管理方法は2種類あるらしい。
CMT(コンテナ管理トランザクション)
トランザクションの開始、コミット、ロールバックをコンテナが自動管理
BMT(Bean管理トランザクション)
トランザクションの開始、コミット、ロールバックをBean内に記述(@TransactionManagementの指定が必要)。
より細かいトランザクション管理が必要(一つのメソッドで複数トランザクションを管理したい場合など)な時は、BMTを採用するといいみたい。
BMTでやる場合はこんな感じでやればOK。
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class CustomerSessionBean {
:
@Resource
UserTransaction utx;
:
public void updateCustomers(Customer customer){
// 例外処理は省略
utx.begin();
em.merge(customer);
utx.commit();
}
すごく簡単に言えば、CMTはトランザクションを自動的に管理してくれる(デフォルトはこっち)。
要するに、CMTでトランザクション管理してるから、BMTは許可できないよってことだったみたい。
EJBについて
@Injectの動きについて
@Inject, @Producer
@EJB
EJBのリモート&ローカル・インターフェース、インターフェースのないビュー参照を注入。
要するに、コンテナで動いてたりするEJB(セッションBean)への参照を注入している感じ。
@Resource
JDBCデータソース、セッション・コンテキスト、ユーザ・トランザクション等の参照を注入
@Remote, @Local
セッションBeanのリモートインターフェース、ローカルインターフェース(別のセッションBean用のインターフェース)を定義する。
@Local
public interface CustomerManegerLocal {
List<Customer> getCustomers();
List<Customer> getCustomersById(int id);
void updateCustomers(Customer customer);
}
@Remote
public interface CustomerManegerRemote {
List<Customer> getCustomers();
List<Customer> getCustomersById(int id);
void updateCustomers(Customer customer);
}
// セッションBeanでの実装
@Stateless
public class CustomerManeger implements CustomerManegerLocal, CustomerManegerRemote {
:
:
}
呼び出しがわ
@Stateless
@Path("/customers")
public class CustomerSessionBean {
// セッションBean間のローカル呼び出しなので、
// CustomerManegerLocalに注入する必要がある。
@Inject CustomerManegerLocal cm;
:
:
その他
変なビルド失敗について
なんかMavenで新しくプロジェクトを作ってみたら、以下のエラーがでてデプロイできなくなった。
Exception Description: Entity name must be unique in a persistence unit. Entity name [MicroMarket] is used for the entity classes [com.mycompany.customermng.MicroMarket] and [com.mycompany.customermng.entities.MicroMarket].
なんかパッケージ名を変えたときのゴミが残ってたみたい。消去してビルドをやったら上手くいった。