コンテナ管理のEntity Managerでjavax.persistence.TransactionRequiredExceptionを取得する

StackOverflow https://stackoverflow.com//questions/24001269

  •  20-12-2019
  •  | 
  •  

質問

こんにちは、簡単なものを作成しました JSF + JPA 応用。私の Web アプリは次のもので構成されています Entity, 、 ManagedBean いくつかの JSF ページ。その目的は、オブジェクトを作成して MySQL データベースに保存することです。分かりました javax.persistence.TransactionRequiredException エンティティを永続化したいたびに、 PersistenceContxt. 。ただし、注射するときは、 UserTransaction コントローラークラスに組み込むと問題なく動作しますが、理由がわかりません。追加する必要はないはずなので、 UserTransaction コンテナ管理されているためです。私が間違っているのでしょうか?それともコードに他の問題があるのでしょうか?

私のマネージドBeanコードは次のとおりです。

@ManagedBean
@SessionScoped
public class Controller {
    @PersistenceContext
    private EntityManager em;
    private Book book;
    public Controller() {}

    public Book getBook() {
        return book;
    } 

    public void setBook(Book book) {
        this.book = book;
    }

    public String createBook() {
        book = new Book();
        return "create";
    }

    public String showResponse() {
        em.persist(book);
        return "response";
    }
}

ここにあります create.xhtml ファセット:

...
<h:form>
    <h:panelGrid columns="2">
        <h:outputText>Title</h:outputText>
        <h:inputText value="#{controller.book.title}" />
    </h:panelGrid>
</h:commandButton action="#{controller.showResponse()}" value="Response" />
...

そしてこれが Persistence.xml コンテンツ:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="JPATestPU" transaction-type="JTA">
    <jta-data-source>jdbc/mysql</jta-data-source>
    <properties>
      <property name="javax.persistence.schema-generation.database.action" value="create"/>
    </properties>
  </persistence-unit>
</persistence>
役に立ちましたか?

解決

トランザクションは EJB のメソッドに対してのみ自動的に作成され、マネージ Bean に対しては自動的に作成されません。JEE7 コンテナを使用している場合は、コントローラの管理対象 Bean に @Transactional を追加してみてください。それ以外の場合は、UserTransation を使用してトランザクションを管理する必要があります。

私が使用したコードの一部は次のとおりです。

@Transactional
public class PersonService {
    @PersistenceContext 
    private EntityManager em;

    public void savePerson(Person person) {
    em.persist(person);
}

そして、それをサーブレットから呼び出しています。

 @WebServlet("/MyServlet")
 public class MyServlet extends HttpServlet {
    @Inject
    PersonService service;
  ....
  service.savePerson(p);
  System.out.println("Person saved");

データベースに保存されたことが確認でき、ログには次のメッセージが表示されます。

INFO: Managed bean with Transactional annotation and TxType of REQUIRED called outside a transaction context.  Beginning a transaction...
INFO: Person saved

ご覧のとおり、新しいトランザクションが作成され、オブジェクトが保存されます

他のヒント

コードスニペットを見たところ。これは技術的な問題というよりは設計の問題だと思います。次のようにアプリケーションを構造化することを検討することをお勧めします。1.データベース層 - MySql。2.エンティティ パッケージ - データベース テーブルに直接マップするエンティティ オブジェクトが含まれています。3.データ アクセス オブジェクト パッケージ - EJB (例:@シングルトン、@ステートレス、@ステートフル)。4.コントローラ パッケージ - EL を介してプレゼンテーション層によってアクセスされるサーブレットおよび/またはマネージド Bean が含まれます (例:@named、@conversionscoped、@managedbeanなど)5。プレゼンテーション層 - JSF ページ (例:Index.xhtml など)

永続化を実行する必要がある EJB にはトランザクション、セキュリティ、その他のサービスが自動的に提供されるため、コードをこのように構造化することが重要です。つまり、EntityManager への参照 (@PersistenceContext を介した) は、マネージド Bean オブジェクト内ではなく EJB 内で行われる必要があります。コントローラー内のオブジェクトは @Inject (@EJB) アノテーションを使用して、 注入する 依存関係。

データベースから読み取る操作でない限り、必要なのはメソッドの上の「@Transactional」アノテーションだけです。また、クラスの上に定義することもできます。しかし、それは適切なアーキテクチャではありません。少なくとも、別のクラスを作成して Bean に注入する必要があります。

JavaEE を使用している場合は、EJB を使用する必要があります。簡単で、取引について心配する必要はありません。コンテナは全体を制御できます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top