Spring-現在のスレッドで使用可能な実際のトランザクションを持つEntityManagerがない-「持続」呼び出しを確実に処理できない


136

「永続化」メソッドを呼び出してエンティティモデルをSpring MVC Webアプリケーションのデータベースに保存しようとすると、このエラーが発生します。この特定のエラーに関連する可能性のあるインターネットの投稿またはページは実際には見つかりません。EntityManagerFactory Beanに何か問題があるようですが、私はSpringプログラミングにかなり慣れていないので、私にとってはすべてがうまく初期化されており、Webのさまざまなチュートリアル記事に従っているようです。

dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
 http://www.springframework.org/schema/mvc 
 http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
 http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
 http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context-4.0.xsd
  http://www.springframework.org/schema/jdbc
  http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
  http://www.springframework.org/schema/data/jpa
  http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
  http://www.springframework.org/schema/data/repository
  http://www.springframework.org/schema/data/repository/spring-repository-1.5.xsd
  http://www.springframework.org/schema/jee
  http://www.springframework.org/schema/jee/spring-jee-3.2.xsd">

    <context:component-scan base-package="wymysl.Controllers" />
    <jpa:repositories base-package="wymysl.repositories"/> 
    <context:component-scan base-package="wymysl.beans" /> 
    <context:component-scan base-package="wymysl.Validators" /> 
    <bean
     class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
     <bean class="org.springframework.orm.hibernate4.HibernateExceptionTranslator"/>

     <bean id="passwordValidator" class="wymysl.Validators.PasswordValidator"></bean>

     <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">

        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
        <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
        <property name="username" value="system" />
        <property name="password" value="polskabieda1" />
    </bean>

 <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="classpath:./META-INF/persistence.xml" />
    <property name="dataSource" ref="dataSource" />

    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
            <property name="showSql" value="true" />
            <property name="generateDdl" value="false" />
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.max_fetch_depth">3</prop>
            <prop key="hibernate.jdbc.fetch_size">50</prop>
            <prop key="hibernate.jdbc.batch_size">10</prop>
        </props>
    </property>
</bean>

    <mvc:annotation-driven />

    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="classpath:messages" />
</bean>

    <bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
             <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>


    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix">
        <value>/WEB-INF/jsp/</value>
    </property>
    <property name="suffix">
        <value>.jsp</value>
    </property>
</bean>

    <mvc:resources mapping="/resources/**" location="/resources/" />
    <mvc:resources mapping="/resources/*" location="/resources/css/"  
    cache-period="31556926"/>



</beans>

RegisterController.java

@Controller
public class RegisterController {

    @PersistenceContext
    EntityManager entityManager;

    @Autowired
    PasswordValidator passwordValidator;

    @InitBinder
    private void initBinder(WebDataBinder binder) {
        binder.setValidator(passwordValidator);
    }

    @RequestMapping(value = "/addUser", method = RequestMethod.GET)
    public String register(Person person) {


        return "register";

    }

    @RequestMapping(value = "/addUser", method = RequestMethod.POST)
    public String register(@ModelAttribute("person") @Valid @Validated Person person, BindingResult result) {
        if(result.hasErrors()) {
            return "register";
        } else {
            entityManager.persist(person);
            return "index";

        }




    }

1
エラーが言うように、トランザクションはありません。registerメソッドにで注釈を付け@Transactionます。
Rohit

回答:


260

私は同じ問題を抱えていて、私は方法に注釈を付けました、@Transactionalそしてそれはうまくいきました。

更新:デフォルトでPersistenceContextが見えているように見えるSpringドキュメントをチェックすることはタイプTransactionであるため、メソッドはトランザクションでなければなりません(http://docs.spring.io/spring/docs/current/spring-framework-reference/ html / orm.html):

@PersistenceContextアノテーションにはオプションの属性タイプがあり、デフォルトはPersistenceContextType.TRANSACTIONです。このデフォルトは、共有EntityManagerプロキシを受信するために必要なものです。代替のPersistenceContextType.EXTENDEDは完全に異なる問題です。これにより、いわゆる拡張EntityManagerが生成されます。これはスレッドセーフではないため、Spring管理のシングルトンBeanなどの同時にアクセスされるコンポーネントでは使用できません。拡張EntityManagerは、たとえばセッションに常駐するステートフルコンポーネントでのみ使用することを想定しており、EntityManagerのライフサイクルは現在のトランザクションに関連付けられておらず、アプリケーションに完全に依存しています。


71
アノテーションのない@Transactionalメソッドが@Transactional同じクラスファイルにあるアノテーションのあるメソッドを呼び出すと、このエラーにも遭遇します(それが私が直面していたものです)。
Jacob van Lingen

5
サービスクラスにで注釈を付けましたが@Transactional、これも機能します。正しい方法かどうかは
わかり

8
言及する価値のあるもう1つのことは、このアノテーションは他の方法では機能しないため、パブリックメソッドに使用する必要があることです。
Yuriy Kravets 2017年

7
@Transactionalはパブリックメソッドでのみ機能することに注意してください。
Andrei_N 2017

7
参考までに、これにはjavax.transaction.Transactionalアノテーションが必要です(Springアノテーションではありません)。
java-addict301

85

SpringデータリポジトリでdeleteByカスタムメソッドを使用しようとしたときに、この例外が発生しました。JUnitテストクラスから操作が試行されました。

例外は@Transactional、JUnitクラスレベルでアノテーションを使用しても発生しません。


8
私は同じ状況にあり、テストクラスに注釈を付ける代わりに、サービスメソッドに注釈を付けたので、テストでなくてもトリックルダウンしました。
Paul Nelson Baker、

@Transactionalクラスレベルでは、サービス内のさまざまなトランザクションを操作する可能性のあるテストの問題を隠すことができます。
ゾーン

1
@Trasactionalは実際にデータベースとやり取りしている場所であり、正常に動作しているため、リポジトリメソッドを使用しました。
Harish Kumar Saini

22

このエラーは3日間私を怒らせましたが、私が直面した状況でも同じエラーが発生しました。私が見つけることができるすべてのアドバイスに従って、私は構成で遊んだが、役に立たなかった。

結局私はそれを見つけました、違い、私が実行していたサービスは共通のjarに含まれていました、問題はAspectJがサービスのインスタンス化を同じように扱わないことが判明しました。実際には、プロキシは、メソッド呼び出しの前に通常のすべてのSpringマジックを実行せずに、基本となるメソッドを呼び出すだけでした。

最後に、例に従ってサービスに配置された@Scopeアノテーションは問題を解決しました:

@Service
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
@Transactional
public class CoreServiceImpl implements CoreService {
    @PersistenceContext
    protected EntityManager entityManager;

    @Override
    public final <T extends AbstractEntity> int deleteAll(Class<T> clazz) {
        CriteriaDelete<T> criteriaDelete = entityManager.getCriteriaBuilder().createCriteriaDelete(clazz);
        criteriaDelete.from(clazz);
        return entityManager.createQuery(criteriaDelete).executeUpdate();
    }

}

私が投稿したメソッドは削除メソッドですが、アノテーションはすべての永続メソッドに同じように影響します。

この投稿が、jarからサービスをロードするときに同じ問題で苦労している他の人の助けになることを願っています


@Scope(proxyMode = ScopedProxyMode.INTERFACES)インターフェイスを実装するDAOクラスに追加することは非常に重要です。私はこのエラーを理解するために一日中費やしました、そしてあなたの解決策が唯一の作品です。どうもありがとうございました!
サックヴァン

1
あなたの回答からの1つの注釈は、おそらく約3日間私を救ってくれました。私はエデネマの真の力を経験しました。Дякс。
Oleksii Kyslytsyn

11

XML-からjava-configurationに切り替えたため、同じエラーが発生しました。

ポイントは、<tx:annotation-driven/>Stone Fengが示唆したように、タグを移行しなかったということです。

だから私@EnableTransactionManagementはここに提案されているように追加し ました@Configuration ClassでのSpringでのアノテーションドリブントランザクションの設定、そしてそれは今動作します


8

boardRepo.deleteByBoardId(id);

同じ問題に直面した。GOT javax.persistence.TransactionRequiredException:現在のスレッドで使用可能な実際のトランザクションを持つEntityManagerがありません

コントローラ/サービスの上に@Transactionalアノテーションを追加することで解決しました。


7

私は同じ問題を抱えていて、私は追加tx:annotation-drivenapplicationContext.xmlてそれがうまくいきました


4

同じコンポーネント内の非トランザクションメソッドから既にトランザクション注釈付きのメソッドにアクセスするときにも、同じエラーが発生しました。

Before:
    @Component
    public class MarketObserver {
        @PersistenceContext(unitName = "maindb")
        private EntityManager em;

        @Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
        public void executeQuery() {
          em.persist(....);
        }


        @Async
        public void startObserving() {
          executeQuery(); //<-- Wrong
        }
    }

    //In another bean:
     marketObserver.startObserving();

自己参照コンポーネントでexecuteQuery()を呼び出してエラーを修正しました。

Fixed version:
    @Component
    public class MarketObserver {
        @PersistenceContext(unitName = "maindb")
        private EntityManager em;

        @Autowired
        private GenericApplicationContext context;

        @Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
        public void executeQuery() {
          em.persist(....);
        }


        @Async
        public void startObserving() {
          context.getBean(MarketObserver.class).executeQuery(); //<-- Works
        }
    }

3

org.springframework.transaction.annotation.Transactionalテストクラスのクラスレベルで注釈を追加すると、問題が解決しました。


3

エラーの回答を検索している他のユーザーへメモです。別の一般的な問題は次のとおりです。

通常@transactional、同じクラス内からメソッドを呼び出すことはできません。

(AspectJを使用する方法と手段はありますが、リファクタリングははるかに簡単になります)

したがって、@transactionalメソッドを保持する呼び出しクラスとクラスが必要になります。


2

私たちにとって、問題は複数の構成ファイルの同じコンテキスト設定に起因しました。複数の設定ファイルで以下を複製していないことを確認してください。

<context:property-placeholder location="classpath*:/module.properties"/>
<context:component-scan base-package="...." />

2

@Transaction間違ったメソッド/アクションレベルで使用した場合も、同じエラーコードが表示されました。

methodWithANumberOfDatabaseActions() { 
   methodA( ...)
   methodA( ...)
}

@Transactional
void methodA( ...) {
  ... ERROR message
}

もちろん@Transactional、メソッドの真上に配置する必要がありましたmethodWithANumberOfDatabaseActions()

それは私の場合のエラーメッセージを解決しました。


0

からモードを削除しました

<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" />

これを機能させる


0

私は何日もこの問題を抱えていましたが、オンラインで見つけたものは何も助けになりませんでした。他の人を助けるためにここに私の答えを投稿しています。

私の場合、リモート処理によって呼び出されるマイクロサービスに取り組んでおり、サービスレベルの@Transactionalアノテーションがリモートプロキシによって取得されていませんでした。

サービスレイヤーとdaoレイヤーの間にデリゲートクラスを追加し、トランザクションとしてデリゲートメソッドをマークすると、これが修正されました。


0

これは私たちを助けました、多分それは将来他の人を助けることができます。@Transaction私たちのために働いていませんでしたが、これはしました:

@ConditionalOnMissingClass("org.springframework.orm.jpa.JpaTransactionManager")


0

あなたが持っている場合

@Transactional // Spring Transactional
class MyDao extends Dao {
}

そしてスーパークラス

class Dao {
    public void save(Entity entity) { getEntityManager().merge(entity); }
}

そしてあなたは電話します

@Autowired MyDao myDao;
myDao.save(entity);

Spring TransactionInterceptor(トランザクションを提供します)を取得しません。

これはあなたがする必要があることです:

@Transactional 
class MyDao extends Dao {
    public void save(Entity entity) { super.save(entity); }
}

信じられないが真実。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.