【问题标题】:No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call没有可用于当前线程的具有实际事务的 EntityManager - 无法可靠地处理“持久”调用
【发布时间】:2016-02-20 07:12:07
【问题描述】:

没有可用于当前线程的具有实际事务的 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";
    }

}

【问题讨论】:

  • 您遇到的异常是什么?在不知道异常的情况下,我唯一能想到的就是在您的 EM 上使用 PersistenceContextType.Extended。 @PersistenceContext(type=PersistenceContextType.EXTENDED) EntityManager em;
  • 我得到的错误:org.springframework.web.util.NestedServletException:请求处理失败;嵌套异常是 javax.persistence.TransactionRequiredException: No EntityManager 与当前线程的实际事务可用 - 无法可靠地处理“持久”调用
  • 您尝试过 PersistanceContextType.Extended 吗?简而言之,这从事务范围的 EM 变为有状态的会话 bean...
  • 它有待解决,现在我有这个错误消息:未知实体:com.app.sqli.models.Collaborateur
  • PackagesToScan 说你的实体应该在这个包 com.app.sqli.entities 但你的实体在:com.app.sqli.models... 他们必须匹配所以将你的实体移动到正确的包或更改 packagesToScan 以匹配您的实体的包

标签: spring-mvc jpa entitymanager


【解决方案1】:

感谢@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);
        }


    }

【讨论】:

  • 我遇到了同样的异常,我从一开始就使用注释。我通过添加此示例中的 @EnableTransactionManagement 解决了这个问题。谢谢。
  • 是的,这里也一样(需要@EnableTransactionManagement),但我也从这个答案中收集了一个金块 - 为我的 bean 提供了更好的设置 - 我为 dataSource 和 jpaVendorAdapter 提供了 LocalContainerEntityManagerFactoryBean 的设置器,并调用了定义的 bean 方法!我猜这违背了容器管理的原则并且不确定副作用,但在阅读完这篇文章后我纠正了一切,我的问题就消失了:D
【解决方案2】:

只是为了确认,添加最后一个 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);
    }

}

【讨论】:

    【解决方案3】:

    我不知道(今天)正在阅读这篇文章的人是否和我有同样的情况,但我遇到了同样的问题。幸运的是,我可以通过简单地将以下内容放入我的 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

    【讨论】:

      猜你喜欢
      • 2015-11-23
      • 2017-02-26
      • 2020-09-30
      • 2017-06-01
      • 2021-08-10
      • 1970-01-01
      • 2017-09-10
      相关资源
      最近更新 更多