スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Spring MVC Spring Data JPAを使って登録する(その2)

さて、前回@Transactionalアノテーションを使ってトランザクション制御したが、今回は、@Transactionalアノテーションを使わずに実現してみる。

■前回の記事
Spring MVC Spring Data JPAを使って登録する

◎動作検証にあたっての各バージョンは以下の通り
  • SpringFramework 3.2.8.RELEASE
  • Java 1.7
  • Tomcat 7.0

1.BookDaoImpl.java(エラーパターン)

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
//import文 省略

@Repository
//@Transactional
public class BookDaoImpl implements BookDao<BookEntity> {

private static Logger logger = LoggerFactory.getLogger(BookDaoImpl.class);

@PersistenceContext
private EntityManager manager;

//省略

@Override
public void addEntity(BookEntity entity) {
logger.info("addEntity start");
EntityTransaction transaction = manager.getTransaction();
transaction.begin();
manager.persist(entity);
manager.flush();
transaction.commit();
}
}

@Transactionalアノテーションをコメントアウト。まず、EntityManagerを使ってトランザクション制御を試みる。ソースだけ見ると上手くいきそうであるが、結果「HTTPステータス 500 - Request processing failed; nested exception is java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead」と例外が発生する。
「Not allowed to create transaction on shared EntityManager」とインスタンス変数を使ってトランザクション制御するのがよくないのかなと思い、以下に書き換えてみる。

2.BookDaoImpl.java(正常パターン①)


@Override
public void addEntity(BookEntity entity) {
EntityManager manager2 = manager.getEntityManagerFactory().createEntityManager();
EntityTransaction transaction = manager2.getTransaction();
transaction.begin();
manager2.persist(entity);
manager2.flush();
transaction.commit();
}

インスタンス変数のEntityManagerからcreateEntityManagerメソッドで、新たにEntityManagerを取得すると、例外が発生することなく登録できた。しかしながら、違和感のあるコードである。manager.getEntityManagerFactory()はファクトリークラスを取得していることに着目して、さらに以下のように書き換えてみる。

3.BookDaoImpl.java(正常パターン②)


import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
//import文 省略

@Repository
//@Transactional
public class BookDaoImpl implements BookDao<BookEntity> {

private static Logger logger = LoggerFactory.getLogger(BookDaoImpl.class);

@Autowired
private EntityManagerFactory factory;

//省略

@Override
public void addEntity(BookEntity entity) {
logger.info("addEntity start");
EntityManager manager2 = factory.createEntityManager();
EntityTransaction transaction = manager2.getTransaction();
transaction.begin();
manager2.persist(entity);
manager2.flush();
transaction.commit();

Bean定義ファイル(下記参照)で「entityManagerFactory」を定義しているため、インジェクションできると思い試してみたところ、こちらの方法でも登録できた。明示的にトランザクション制御を行う場合の実装方法は他にもあると思うが、ファクトリークラスからEntityManagerを生成する流れは変わらないはずである。
処理の流れについては見てもらえば分かると思うが、flush()はキャッシュに残っている処理をすべて実行するメソッドとなる点を補足しておく。

4.Bean定義ファイル(datasource-config.xmlより抜粋)


<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
<property name="packagesToScan" value="jp.co.sample.book.entity"/>
</bean>


今回、明示的トランザクションで実装してみたが、前回のアノテーションを使った宣言的トランザクションの方がやはりスマートである。@Transactionalは重宝するアノテーションだ。


■過去のSpring関連記事
Spring関連記事 Index

スポンサーサイト

コメントの投稿

非公開コメント

プロフィール

bookmount8

Author:bookmount8
システムエンジニア。サーバーサイドでjavaを扱うことが多い。最近は、ミドルやフロント周りも関心あり。

最新記事
カテゴリ
検索フォーム
最新コメント
月別アーカイブ
これまでの訪問者数
ブロとも申請フォーム

この人とブロともになる

RSSリンクの表示
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。