Spring - 現在のスレッドで使用できる実際のトランザクションを持つ EntityManager がありません - 'persist' 呼び出しを確実に処理できません 質問する

Spring - 現在のスレッドで使用できる実際のトランザクションを持つ EntityManager がありません - 'persist' 呼び出しを確実に処理できません 質問する

Spring MVC Web アプリケーションでエンティティ モデルをデータベースに保存するために "persist" メソッドを呼び出そうとすると、このエラーが発生します。この特定のエラーに関連する投稿やページはインターネット上では見つかりません。EntityManagerFactory Bean に問題があるようですが、私は Spring プログラミングの初心者なので、Web 上のさまざまなチュートリアル記事によると、すべてが正常に初期化されているように見えます。

ディスパッチャサーブレット.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 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>

コントローラを登録する.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

私も同じ問題を抱えていましたが、メソッドに注釈を付けて、@Transactionalうまくいきました。

更新: Springのドキュメントを確認すると、デフォルトではPersistenceContextはTransaction型であるように見えるので、メソッドはトランザクションである必要があります(http://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html):

@PersistenceContext アノテーションにはオプションの属性 type があり、そのデフォルトは PersistenceContextType.TRANSACTION です。このデフォルトは、共有 EntityManager プロキシを受け取るために必要なものです。代替の PersistenceContextType.EXTENDED はまったく別のものです。これは、いわゆる拡張 EntityManager になりますが、これはスレッドセーフではないため、Spring 管理のシングルトン Bean などの同時アクセス コンポーネントでは使用しないでください。拡張 EntityManager は、たとえばセッション内に存在するステートフル コンポーネントでのみ使用することを想定しており、EntityManager のライフサイクルは現在のトランザクションに結び付けられず、完全にアプリケーション次第です。

おすすめ記事