スプリングブート1.2.3.RELEASEバージョンをJPA with hibernateで使用しています。次の例外が発生しています
org.springframework.dao.InvalidDataAccessApiUsageException: No transactional EntityManager available; nested exception is javax.persistence.TransactionRequiredException: No transactional EntityManager available
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.Java:410) ~[EntityManagerFactoryUtils.class:4.1.6.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.Java:223) ~[HibernateJpaDialect.class:4.1.6.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.Java:417) ~[AbstractEntityManagerFactoryBean.class:4.1.6.RELEASE]
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.Java:59) ~[ChainedPersistenceExceptionTranslator.class:4.1.6.RELEASE]
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.Java:213) ~[DataAccessUtils.class:4.1.6.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.Java:147) ~[PersistenceExceptionTranslationInterceptor.class:4.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179) [ReflectiveMethodInvocation.class:4.1.6.RELEASE]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.Java:122) ~[CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.class:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179) [ReflectiveMethodInvocation.class:4.1.6.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.Java:92) [ExposeInvocationInterceptor.class:4.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179) [ReflectiveMethodInvocation.class:4.1.6.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:207) [JdkDynamicAopProxy.class:4.1.6.RELEASE]
at com.Sun.proxy.$Proxy110.deleteByCustomerId(Unknown Source) ~[na:na]
Caused by: javax.persistence.TransactionRequiredException: No transactional EntityManager available
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.Java:275) ~[SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.class:4.1.6.RELEASE]
at com.Sun.proxy.$Proxy102.remove(Unknown Source) ~[na:na]
at org.springframework.data.jpa.repository.query.JpaQueryExecution$DeleteExecution.doExecute(JpaQueryExecution.Java:270) ~[JpaQueryExecution$DeleteExecution.class:na]
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.Java:74) ~[JpaQueryExecution.class:na]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.Java:97) ~[AbstractJpaQuery.class:na]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.Java:88) ~[AbstractJpaQuery.class:na]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.Java:395) ~[RepositoryFactorySupport$QueryExecutorMethodInterceptor.class:na]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.Java:373) ~[RepositoryFactorySupport$QueryExecutorMethodInterceptor.class:na]
以下は私のプログラム構造です
構成クラス
@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableTransactionManagement
public class WSApplication {
public static void main(final String[] args) {
SpringApplication.run(WSApplication.class, args);
}
}
@Entity
@Table(Orders)
public class Order {
@id
@GeneratedValue
private long id;
@Column(name = "customerId")
private Long customerId;
// getter & setter methods
// equals & hashCode methods
}
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByCustomerId(Long customerId);
// 4- @Transactional works fine
void deleteByCustomerId(Long cusotmerId);
}
public class OrderService {
@Autowired
private OrderRepository repo;
// 3- @Transactional works fine
public void deleteOrder(long customerId){
//1- throws exception
repo.deleteByCustomerId(customerId);
//2- following works fine
//repo.delete(repo.findByCustomerId(customerId).get(0));
}
}
上記のサービスクラスコードで、2が機能し、1が例外をスローする理由を誰かに教えてもらえますか?.
ありがとう
最初に、 Spring-Data JPA Documentation を引用して、delete
メソッドがあなたのケースで機能する理由を正当化します(つまり、オプション2 )。
リポジトリインスタンスのCRUDメソッドは、デフォルトでトランザクション対応です。読み取り操作の場合、トランザクション構成
readOnly
フラグがtrueに設定され、他のすべてはプレーン@Transactional
で構成されているため、デフォルトのトランザクション構成が適用されます。詳細については、CrudRepositoryのJavaDocを参照してください
delete
メソッドは、実際にはCrudRepository
のメソッドです。リポジトリはJpaRepository
を拡張します。これはCrudRespository
を拡張するため、CrudRepositoryインターフェースに属し、上記の見積もりによるとトランザクションです。
セクション トランザクションクエリメソッド を読んだ場合、それはオプション4と同じであることがわかります。リポジトリのすべてのメソッドにカスタムトランザクション動作を適用します。また、ドキュメントの例61は、オプション3と同じシナリオを示しています。
ここでは、JDBCロジックを使用していないことに注意してください。この場合、データベースはトランザクションを処理しますが、ORMベースのフレームワーク内で処理します。 ORMフレームワークでは、オブジェクトキャッシュとデータベース間の同期をトリガーするためにトランザクションが必要です。したがって、deleteByCustomerId
のようなORMロジックを実行するメソッドのトランザクションコンテキストを認識して提供する必要があります。
デフォルトでは、@Transactional
(つまり、パラメーターなし)は、伝搬モードをREQUIRED
に設定し、readOnlyフラグをfalseに設定します。アノテーションが付けられたメソッドを呼び出すと、トランザクションが存在しない場合はトランザクションが初期化されます。これが、@ LucasSaldanhaの回避策の理由です(例と同じ)ファサードを使用して複数のリポジトリ呼び出しのトランザクションを定義する )およびオプション4が機能します。そうでなければ、トランザクションがなければ、オプション1のスローされた例外に陥ります。
わかりました、それを機能させる方法を見つけました。
@Transactional
アノテーション(org.springframework.transaction.annotation.Transactional)をdeleteOrderメソッドでOrderService。
@Transactional
public void deleteOrder(long customerId){
repo.deleteByCustomerId(customerId);
}
2番目の方法が機能する理由は本当にわかりません。 CrudRepositoryインターフェースからの直接的な方法であるため、アトミックに実行する方法を知っていると思います。
前者はdeleteByCustomerIdの呼び出しです。この呼び出しは、指定されたIDを持つ顧客を見つけるために処理され、それを削除します。何らかの理由で、明示的なトランザクションを使用します。
繰り返しますが、それは単なる推測です。私はいくつかの春の開発者に連絡してみて、おそらく問題を開いてこの動作を確認しようと思います。
それが役に立てば幸い!
search()
メソッドにNo transactional EntityManager available
でアノテーションを付けた後でも、@Transactional
例外が発生します。
私は このチュートリアル に従い、Spring BootでHibernate検索を設定する方法を説明しました。
私にとっての問題は、hibernate-search-orm
への依存関係が異なることでした。問題なく私のために働いた依存関係は
compile("org.hibernate:hibernate-search-orm:5.7.0.Final")
これをgradleビルドファイルに追加した後、すべてが期待どおりに機能しました。
これが他の誰かにも役立つことを願っています。