例を作成しました-SPRING、JPA(EclipseLink永続化プロバイダー)とJTAトランザクションマネージャー(JBoss 7)。データベース内のすべてのデータが、読み取り操作に対して適切に UI に表示されていることを確認しました。しかし、保存/更新または削除操作に関しては、サービス層は作業をデータベースにコミットしていません。例外はキャッチされません (コンソール/ログもチェックし、entityManager.persist/remove が例外なく呼び出されていることを確認できるコードをデバッグしました)。
--コード一覧-- 1.standalone.xml でのデータソース設定
<datasource jta="true" jndi-name="java:/mysql_customerdb3" pool-name="mysql_customerdb3_pool" enabled="true" use-java-context="true" use-ccm="true">
<connection-url>jdbc:mysql://localhost:3306/customerdb</connection-url>
<driver>mysql</driver>
<security>
<user-name>root</user-name>
<password>root</password>
</security>
<statement>
<prepared-statement-cache-size>10</prepared-statement-cache-size>
<share-prepared-statements>true</share-prepared-statements>
</statement>
</datasource>
<drivers>
<driver name="mysql" module="com.mysql">
<driver-class>com.mysql.jdbc.Driver</driver-class>
<xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
</driver>
<driver name="h2" module="com.h2database.h2">
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
</drivers>
module.xml でのデータベース ドライバーの構成
persistence.xml
org.eclipse.persistence.jpa.PersistenceProvider java:/mysql_customerdb3 com.springforbeginners.model.Customer
customerdispatcher-servlet.xml
<context:annotation-config /> <context:component-scan base-package="com.springforbeginners" /> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" > <property name="loadTimeWeaver" ref="loadTimeWeaver" /> <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" /> </bean> <bean id="loadTimeWeaver" class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver" > </bean> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManagerName" value="java:jboss/TransactionManager"/> <property name="userTransactionName" value="java:jboss/UserTransaction"/> </bean> <tx:annotation-driven transaction-manager="transactionManager" />
CustomerServiceImpl.java
パッケージ com.springforbeginners.service;
com.springforbeginners.dao.CustomerDAO をインポートします。com.springforbeginners.model.Customer をインポートします。java.util.List をインポートします。import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional;
@Service public class CustomerServiceImpl implement CustomerService { @Autowired private CustomerDAO customerDAO;
@Transactional @Override public void addCustomer(Customer customer) { customerDAO.addCustomer(customer); } @Transactional @Override public List<Customer> listCustomer() { return customerDAO.listCustomer(); } @Transactional @Override public void removeCustomer(Integer customerId) { customerDAO.removeCustomer(customerId); }
}
CustomerDAOImpl.java
パッケージcom.springforbeginners.dao;
com.springforbeginners.model.Customer をインポートします。java.util.List をインポートします。import javax.persistence.EntityManager; javax.persistence.PersistenceContext をインポートします。import org.springframework.stereotype.Repository;
@Repository public class CustomerDAOImpl implements CustomerDAO { @PersistenceContext(unitName="CustomerDetailsPU3") private EntityManager entityManager;
@Override public void addCustomer(Customer customer) { entityManager.persist(customer); } @Override public List<Customer> listCustomer() { return entityManager.createQuery("select c from Customer c", Customer.class).getResultList(); } @Override public void removeCustomer(Integer customerId) { Customer customer = (Customer) entityManager.getReference(Customer.class, customerId); if (null != customer) { entityManager.remove(customer); } }
}
何がどこに欠けているのか正確にはわかりません。しかし、上記のコードでは、読み取り操作は期待どおりに機能しています。問題は保存操作にあります。上記の例を、非 JTA データソースを使用するように変換し (jta=false の standalone.xml も変更)、以下のように JpaTransactionManager を使用するようにしました。
非 JTA データソースと 'org.springframework.orm.jpa.JpaTransactionManager' を使用すると、すべての操作 (読み取りと保存/更新/削除) が正常に機能します。
しかし、私の例の JTA バージョンは期待どおりに動作しません (データベースに作業をコミットしない保存操作)。ヘルプ/ポインタをいただければ幸いです。
ありがとうプラカシュ
ジェームズ、
このアプリケーションを JBoss で実行します。ただし、JBoss 上の 1 つのデータソースと Glassfish およびトランザクション上の別のデータソースは、両方のデータソースで同時に保存操作にまたがる必要があります。これが私が達成しようとしていることです。現在JBossで実行されているサービス(データ)レイヤーのスプリングを含むWebアプリケーションがあります。
前に言ったように、JBoss 用と Glassfish 用の 2 つの persistence.xml を用意します。私がこれを初めて行っているので、トランザクション (異なるサーバー上の 2 つのデータソース (この場合は JBoss と Glassfish) にまたがる) が JBoss によって完全に実行できるかどうかは疑問でした (ビジネスロジック全体がJBoss にデプロイされた serviceImpl クラス)? この場合、JBoss トランザクション マネージャー ( property name="transactionManagerName" value="java:jboss/TransactionManager" ) を使用します。これで十分ですか、それとも同様に Glassfish トランザクションマネージャーも必要ですか? これが混乱を引き起こした場合は申し訳ありません。
私からのもう 1 つの質問は、persistence.xml/anywhere で jndi ポートを指定するための規定があるかということでした (間違いなく、2 つの異なる persistence.xml があり、ターゲット サーバーを 1 つでは JBoss として、もう 1 つでは Glassfish として言及します)。
ビジネス ロジックを JBoss/Glassfish などのさまざまなサーバーに分散し、単一のトランザクションの下で分散できる技術は春にあるのでしょうか? これがオプションになるかどうかはわかりませんでした。サーバーごとに 1 つずつ、2 つの異なる展開スクリプトが必要になるこのシナリオについて話していましたか?
ありがとうプラカシュ