web-dev-qa-db-ja.com

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

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

jUnitでテストを行うと、persistメソッドが機能し、オブジェクトが挿入されていることがわかりますが、コントローラーを介してメソッドを呼び出すと機能しません。

これが私のプロジェクトです:

applicationContext.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:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.2.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">



<!--    <bean id="notification" class="com.app.sqli.notification.NotificationTask" /> -->

<!--    <task:scheduled-tasks> -->
<!--        <task:scheduled ref="notification" method="notifier" cron="*/2 * * * * *"/> -->
<!--    </task:scheduled-tasks> -->

<context:component-scan base-package="com.app.sqli" />  

    <mvc:annotation-driven />
    <bean id="entityManagerFactoryBean" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
      <property name="dataSource" ref="dataSource" />
       <property name="packagesToScan" value="com.app.sqli.entities" />
      <property name="jpaVendorAdapter">
         <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
      </property>
      <property name="jpaProperties">
         <props>
            <prop key="hibernate.hbm2ddl.auto">validate</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
         </props>
      </property>
   </bean>


   <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName" value="com.mysql.jdbc.Driver" />
      <property name="url" value="jdbc:mysql://localhost:3306/sqli" />
      <property name="username" value="root" />
      <property name="password" value="" />
   </bean>


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


   <tx:annotation-driven />


</beans>

私のモデルクラス:

package com.app.sqli.models;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Collaborateur {

    @Id
    private int id;
    private String nom;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getNom() {
        return nom;
    }

    public void setNom(String nom) {
        this.nom = nom;
    }

}

私のDAOクラス

package com.app.sqli.dao;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.stereotype.Repository;

import com.app.sqli.models.Collaborateur;

@Repository
public class CollaborateurDao implements IcollaborateurDao{

    @PersistenceContext
    private EntityManager em;

    @Override
    public void addCollaborateur(Collaborateur c) {
    em.persist(c);

    }

}

私のサービスクラス

package com.app.sqli.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.app.sqli.dao.IcollaborateurDao;
import com.app.sqli.models.Collaborateur;

@Service
@Transactional
public class CollaborateurService implements IcollaborateurService{

    @Autowired
    private IcollaborateurDao cdao;

    @Override
    public void addCollaborateur(Collaborateur c) {
        cdao.addCollaborateur(c);

    }


}

そして私のコントローラー

package com.app.sqli.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.app.sqli.models.Collaborateur;
import com.app.sqli.services.IcollaborateurService;

@org.springframework.stereotype.Controller
public class Controller {
    @Autowired
    private IcollaborateurService cserv;

    @RequestMapping(value = "/index")
    public String index(Model m) {
        System.out.println("insertion ...");
        Collaborateur c = new Collaborateur();
        c.setId(11);
        c.setNom("nom");
        cserv.addCollaborateur(c);
        return "index";
    }

}
6
Mohamed Nabli

@mechkovにご協力いただき、ありがとうございます。設定ファイルを変更することで問題が解決したので、アノテーション付きの設定クラスを使用しましたが、問題はうまくいきました。問題がどこにあるのかまだわかりません。

    @Configuration
    @ComponentScan(basePackages = "your package")
    @EnableTransactionManagement
    public class DatabaseConfig {

        protected static final String PROPERTY_NAME_DATABASE_DRIVER = "com.mysql.jdbc.Driver";
        protected static final String PROPERTY_NAME_DATABASE_PASSWORD = "password";
        protected static final String PROPERTY_NAME_DATABASE_URL = "jdbc:mysql://localhost:3306/databasename";
        protected static final String PROPERTY_NAME_DATABASE_USERNAME = "login";

        private static final String PROPERTY_PACKAGES_TO_SCAN = "where your models are";
        @Bean
        public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter){
            LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
            entityManagerFactoryBean.setDataSource(dataSource);
            entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter);
            entityManagerFactoryBean.setPackagesToScan(PROPERTY_PACKAGES_TO_SCAN);
            return entityManagerFactoryBean;
        }

        @Bean
        public BasicDataSource dataSource(){
            BasicDataSource ds = new BasicDataSource();
            ds.setDriverClassName(PROPERTY_NAME_DATABASE_DRIVER);
            ds.setUrl(PROPERTY_NAME_DATABASE_URL);
            ds.setUsername(PROPERTY_NAME_DATABASE_USERNAME);
            ds.setPassword(PROPERTY_NAME_DATABASE_PASSWORD);
            ds.setInitialSize(5);
            return ds;
        }

        @Bean
        public JpaVendorAdapter jpaVendorAdapter(){
            HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
            adapter.setDatabase(Database.MYSQL);
            adapter.setShowSql(true);
            adapter.setGenerateDdl(true);

//I'm using MySQL5InnoDBDialect to make my tables support foreign keys
adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");
            return adapter;
        }

        @Bean
        public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
            return new JpaTransactionManager(entityManagerFactory);
        }


    }
7
Mohamed Nabli

これを読んでいる人(今日)が私のケースと同じかどうかはわかりませんが、同じ問題がありました。幸い、次のコードをspring-conf.xmlに追加するだけで修正できます。

<beans xmlns="http://www.springframework.org/schema/beans"
...
xmlns:tx="http://www.springframework.org/schema/tx"
...
xsi:schemaLocation="
...
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

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

<!-- This does the trick! -->
<tx:annotation-driven transaction-manager="tManager" />

注:アノテーションを介して宣言型トランザクションを使用しています。そのため、そうする場合は、メソッドに @ Transactional アノテーションを付けることで問題を解決することもできます。

参考:

  1. http://blog.jhades.org/how-does-spring-transactional-really-work/
  2. http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/transaction.html
3
Loa

確認のために、最後のBean定義を追加するとこの問題が解決することを確認してください。

私の設定クラスは以下の通りです:

@Configuration
@EnableTransactionManagement
@ComponentScan
public class OFSConfig {

    @Bean
    public IDAO<FuelStation> getFSService() {
        return new FSService();
    }

    @Bean
    public LocalEntityManagerFactoryBean emfBean() {
        LocalEntityManagerFactoryBean e = new LocalEntityManagerFactoryBean();
        e.setPersistenceUnitName("org.superbapps.db_OWSDB_PU");

        return e;
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory em) {
        return new JpaTransactionManager(em);
    }
}

サービス自体は次のとおりです。

@Transactional
@Repository
public class FSService implements IDAO<FuelStation> {

    @PersistenceContext
    private EntityManager EM;

    public EntityManager getEM() {
        return EM;
    }

    public void setEM(EntityManager EM) {
        this.EM = EM;
    }

    @Override
    public List<FuelStation> getAll() {
        return EM.createNamedQuery("FuelStation.findAll")
                .getResultList();
    }

    @Override
    public FuelStation getByID(String ID) {
        FuelStation fs = (FuelStation) EM.createNamedQuery("FuelStation.findById")
                .setParameter("id", ID)
                .getSingleResult();

        return fs;
    }

    @Override
    public void update(FuelStation entity) {
        EM.merge(entity);
    }

}
1
dobrivoje