enum
DB格納時はordinalかnameが保存される。どちらにするかは選択できる。
http://www.slideshare.net/ryoasai/jpa-9109517 17ページ
それ以外の値を使いたい場合は、JAPの実装依存。
EclipseLinkの場合はコンバーターを作成すればよい。
http://brissyu.blogspot.jp/2011/05/rcp-eclipselink.html
サーブレットでもEJBでもないクラスのフィールドに@PersistenceContext
可能だが、そのクラスのインスタンスもコンテナによってnewされる必要があるようだ。
プログラムでFoo f = new Foo();し、f.xxx に@PersistenceContextをつけていても、f.xxx には注入されておらずnullになる。
Fooのインスタンス生成をCDIに管理させれば、f.xxxに注入されるようになる。→JavaEE/CDI
サーブレットからEntityManagerを使う
@PersistenceContext による注入は可能だが、
トランザクションは自分で制御する必要がある。
以下のコードで制御する。
UserTransaction utx; try { Context ctx = new InitialContext(); utx = (UserTransaction)ctx.lookup("UserTransaction"); // lookupの引数は /UserTransaction とか java:comp/UserTransaction とかの説もあり。 } catch (NamingException e) { throw new ServletException(e); }
try { utx.begin();
やりたい処理
utx.commit();
} catch (Exception e) { try { utx.rollback(); } catch (Exception e1) { e1.printStackTrace(); }
throw new ServletException(e); }
UserTransactionはコンテナに注入してもらうことも可能。これを利用すれば、上記のようにJNDI lookupをする必要はなくなる。
@Inject private UserTransaction utx;
別の方法として、EntityManager#getTransaction() で EntityTransaction を取得し、そのbegin/commitを呼ぶ方法もあるらしい。
参考
- http://d.hatena.ne.jp/u6k/20100108/1262939091
- http://www.koutou-software.co.jp/junk/servlet-and-transaction.html
GlassFish 3.1.2.2(内蔵のEclipseLink) で使う
参考
デフォルトのデータソース
管理コンソールの以下で確認できる。
Resources > JDBC > JDBC Resources → jdbc/__default が定義されている。 PoolがDerbyPoolとなっている。
Resources > JDBC > JDBC Connection Pools > DerbyPool → Additional Propertiesタブで、接続先(PortNumber, serverNameなどが確認できる。)
persistence.xml
最低限以下の記述が必要。
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="boardPU"> <!-- boardPUはアプリから@PersistenceContextで参照している名前 --> <properties> <!-- テスト用にテーブルを自動的に削除・再作成させたい場合に必要 無ければ作るの場合は value="create-tables" を指定。 --> <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/> </properties> </persistence-unit> </persistence>
providerとjta-data-sourceも書くべき?
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="boardPU"> <!-- providerとjta-data-sourceは省略してもとりあえずは動く --> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <jta-data-source>jdbc/__default</jta-data-source> <!-- GlassFishセットアップ時に自動作成されているデータソース--> <properties> <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/> <property name="eclipselink.logging.level" value="INFO"/> </properties> </persistence-unit> </persistence>
エラー
「connectでエラー」
java.net.ConnectException: ポート 1527 のサーバー localhost への接続中にメッセージ Connection refused: connect でエラーになりました。
Derbyが起動していない。以下のコマンドで起動する。
asadmin start-database
Could not resolve a persistence unit
cannot Deploy MessageBoard Deployment Error for module: MessageBoard: Error occurred during deployment: Exception while preparing the app : Could not resolve a persistence unit corresponding to the persistence-context-ref-name [sample.board.Exp/em] in the scope of the module called [MessageBoard]
@PersistenceContextのunitNameで参照している名前が persistence.xmlのpersistence-unitで定義されていない場合にこのエラーになる。エラーメッセージ中のname [sample.board.Exp/em] が、unitNameとは無関係な名前になっている点に注意。注入先のクラス名/変数名の形になっている。
表またはビュー 'SEQUENCE' は存在しません。
java.sql.SQLSyntaxErrorException: 表またはビュー 'SEQUENCE' は存在しません。
おそらく、DB側に適切にテーブルが作成済みならこのエラーにはならない。
自力で作成するか、persistence.xmlに以下の記述(EclipseLink固有)を追加して、
EclipseLinkに作成させる。
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
javax.persistence.TransactionRequiredException
persistence.xmlのpersistence-unitにtransaction-type="JTA"の指定がある場合(transacition-typeを省略した場合も同じ)、EntityManagerのメソッドを使うには、JTAでトランザクションが開始されていないとならない。
Servletの場合、コンテナが自動的にトランザクションを開始してくれるわけではない?
UserTransactionを使って自分で管理する。