当前位置: 首页 > 知识库问答 >
问题:

Spring boot JPA不会将实体附加到会话

杨海
2023-03-14

我有一个使用Spring Boot JPA(Spring Boot starter data JPA dependency)的项目,它使用Hibernate作为JPA实现。

我自动配置了我的容器(@EnableAutoConfiguration),并且我使用EntityManager进行CRUD操作。

问题:我在启动时使用EntityManager通过HQL查询加载实体,但当我想要编辑或删除其中任何一个实体时,会出现以下错误

org.springframework.dao.InvalidDataAccessApiUsageException:删除分离的实例com.phistory.data.model.car.Car#2;嵌套异常java.lang.IllegalArgumentException:删除分离的实例com.phistory.data.model.car.Car#2

org.springframework.dao.InvalidDataAccessApiUsageException:未管理实体;嵌套异常java.lang.IllegalArgumentException:未管理实体

图书馆:

  • spring boot starter数据jpa 1.4.4。发布(Hibernate 5.0.11.最终版)

主要内容:

@SpringBootApplication
@EnableAutoConfiguration
@Slf4j
public class Main {    
    public static void main(String[] args) {
        try {
            SpringApplication.run(Main.class, args);
        } catch (Exception e) {
            log.error(e.toString(), e);
        }
    }

数据库配置(没有明确声明bean,EntityManager会自动连接):

@Configuration
@ComponentScan("com.phistory.data.dao")
@EntityScan("com.phistory.data.model")
@EnableTransactionManagement
@PersistenceUnit
public class SqlDatabaseConfig {
}

@Transactional
@Repository
public class SqlCarDAOImpl extends SqlDAOImpl<Car, Long> implements SqlCarDAO {

    @Autowired
    public SqlCarDAOImpl(EntityManager entityManager) {
        super(entityManager);
    }

    @Override
    public List<Car> getAll() {
        return super.getEntityManager()
                    .createQuery("FROM Car AS car")
                    .getResultList();
    }
}

家长DAO

@Transactional
@Repository
@Slf4j
@NoArgsConstructor
public abstract class SqlDAOImpl<TYPE extends GenericEntity, IDENTIFIER> implements SqlDAO<TYPE, IDENTIFIER> {

    @Getter
    @PersistenceContext
    private EntityManager entityManager;

    public SqlDAOImpl(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public void saveOrEdit(TYPE entity) {
        if (entity != null) {
            if (entity.getId() == null) {
                log.info("Saving new entity: " + entity.toString());
                this.entityManager.persist(entity);
            } else {
                log.info("Editing entity: " + entity.toString());
                this.entityManager.refresh(entity);
            }
        }
    }

    public void delete(TYPE entity) {
        if (entity != null) {
            log.info("Deleting entity: " + entity.toString());
            this.entityManager.remove(entity);
        }
    }

    public Session getCurrentSession() {
        return this.entityManager.unwrap(Session.class);
    }
}

为什么我加载的实体没有附加到会话?显然,保存一个新实体效果很好,因为此时不能管理该实体。

多谢问候

共有2个答案

郎宏逸
2023-03-14

在dao之外调用dao的方法时,实体被分离。为了保持会话,应该在调用dao方法的方法上定义@Transactional注释。

例如)

public class CarService {

    @Transactional   <-- {here}
    public void doSomething(){
        Car car = sqlDao.getOne(1);
        sqlDao.update(car);
        sqlDao.delete(car);
    }
}
谯嘉懿
2023-03-14

如果您真的想使用Spring数据JPA,为什么要直接使用EntityManager?

您在上面发布的所有内容都可以“开箱即用”:

应用程序启动程序:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Main {

    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }

}

Spring Data JPA存储库:

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.example.model.CollectionParent;
import java.lang.String;
import java.util.List;

@Repository
public interface CarRepository extends CrudRepository<Car, Long> {
     // nearly everything you need comes for free
}

CarRepository现在为您提供了方法findAll():Iterable

DAO/服务可能如下所示:

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

@Service
public class CarService {

    @Autowired
    private CarRepository carRepository;

    @Transactional
    public Iterable<Car> findCars() {
        return carRepository.findAll();
    }

    @Transactional
    public void updateCar(final Long carId, ...some other params ...) {
        final Car car = carRepository.findOne(carId);
        car.setXXX ...use some other params here ...
        car.setYYY ...use some other params here ...
    }

    @Transactional
    public void updateCar(final Car detachedAndModifiedCar) {
         carRepository.save(detachedAndModifiedCar);
    }

    ...
}

如果您将Car Entity加载到当前持久性上下文中,对其进行修改并让Hibernate在刷新时间存储更改,最好在数据库事务中存储更改,则可以简单地实现更新。这可以通过使用@Transactional注释的Service/DAO方法轻松实现。

分离的实体也可以传递给服务,只需重新连接并使用carRepository保存即可。保存(已分离和已修改的CAR)

即使您的saveOrEdit方法也只是在现有实体的情况下调用entityManager.refresh(实体)。这意味着根本没有更新代码,还是我弄错了?实体将仅使用数据库中的数据进行更新。

 类似资料:
  • 当我试图在模板上生成带有图标的电子邮件时,我遇到了Thymeleaf的问题。我已经按照留档建议的步骤进行了操作,请参见第4.3部分,但在电子邮件中,只显示了3个图标中的2个。 首先我加载图标: 然后我将图标添加到: 在哪里: 然后,在发送电子邮件之前,我在

  • 我正在尝试将BeautifulSoup对象写入文件。请注意,我向soup对象附加了一些内容。这是一个div,它包含来自Plotly的to_HTML()函数的HTML/JavaScript,它给了我一个HTML格式的图表。我将问题缩小到以下代码: 在write函数中,我尝试了各种函数将soup对象转换为字符串,比如str(soup)、soup。prettify(),还有更多我忘记的内容,还有那些确实

  • 我有一个使用Drools 7.12.0的drools实现。最终在WildFly-10.1.0下完美工作。最终。我们现在正在尝试升级到WildFly-19.0.0。FINAL和drools模块将不加载。我在日志中看到这一点,因为Wildfly试图启动Drools模块; 我的kmodule.xml看起来像 我知道从10.0开始。1至19.0。0是一个很大的飞跃,但在这件事上我别无选择。谁能告诉我哪里出

  • 问题内容: 我有一个托管bean,其中包含当前页面的实体对象列表。在我创建一个新对象并在事务中使用persist()将其持久保存到数据库之后;在另一个事务中,当我调用merge时(由于该实体由于先前的事务提交而处于分离状态);实体管理器无法在持久性上下文中找到对象,并向数据库抛出选择查询。我是否缺少某些东西,或者是正常行为? 更新:当我使用mysql数据库和自动生成的ID列时,存在上述问题。当我在

  • 我有两个表,sr_leagures和sr_programs。SR_Programs与sr_leagues有一对多的关系。 我有以下使用实体框架的代码: 那么这就是我要问的部分: 然后关闭DB上下文 这是否会两次将实体添加到数据库中?一旦附加到并添加到表? 或者EF会因为两者的关系而知道自己是同一个实体吗?

  • 我的编码似乎有什么问题?为什么字体不会改变?我已经在资产/字体文件夹下导入了字体。有了这个,我将xml和java文件附加在一起 XML文件 JAVA文件