Hibernate 弹簧靴JPA不';t将实体附加到会话

Hibernate 弹簧靴JPA不';t将实体附加到会话,hibernate,jpa,spring-boot,hql,Hibernate,Jpa,Spring Boot,Hql,我有一个使用SpringBootJPA(SpringBootStarterDataJPA依赖项)的项目,它使用Hibernate作为JPA实现 我自动配置了容器(@EnableAutoConfiguration),并使用EntityManager进行CRUD操作 问题: 我使用这个EntityManager在启动时通过HQL查询加载实体,但是当我想要编辑或删除其中任何一个实体时,我会遇到以下错误 org.springframework.dao.InvalidDataAccessApiUsageE

我有一个使用SpringBootJPA(SpringBootStarterDataJPA依赖项)的项目,它使用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.RELEASE(Hibernate 5.0.11.Final)
主要内容:

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

@Transactional
@存储库
公共类SqlCarDAOImpl扩展SqlDAOImpl实现SqlCarDAO{
@自动连线
公共SqlCarDAOImpl(EntityManager EntityManager){
超级(实体管理器);
}
@凌驾
公共列表getAll(){
返回super.getEntityManager()
.createQuery(“从汽车到汽车”)
.getResultList();
}
}
父道

@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);
    }
}
@Transactional
@存储库
@Slf4j
@诺尔格构装师
公共抽象类SqlDAOImpl实现SqlDAO{
@吸气剂
@持久上下文
私人实体管理者实体管理者;
公共SqlDAOImpl(EntityManager EntityManager){
this.entityManager=entityManager;
}
公共void saveOrEdit(类型实体){
如果(实体!=null){
if(entity.getId()==null){
log.info(“保存新实体:+entity.toString());
this.entityManager.persist(实体);
}否则{
log.info(“编辑实体:+entity.toString());
this.entityManager.refresh(实体);
}
}
}
公共作废删除(类型实体){
如果(实体!=null){
log.info(“删除实体:+entity.toString());
this.entityManager.remove(实体);
}
}
公共会话getCurrentSession(){
返回此.entityManager.unwrap(Session.class);
}
}
为什么我加载的实体没有附加到会话?显然,保存一个新实体可以很好地工作,因为此时不能管理该实体

非常感谢
问候语

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

(例如)

公共类CarService{

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

(例如)

公共类CarService{

@事务性如果您确实想要使用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数据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
}
如果您将一个Car实体加载到当前持久性上下文中,对其进行修改并让Hibernate在刷新时存储更改(最好是在数据库事务中),则可以简单地实现更新。这可以通过使用
@Transactional
注释的Service/DAO方法轻松实现

分离的实体也可以传递给服务,只需重新连接并使用
carRepository.save(detachedAndModifiedCar)
保存即可


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

如果您确实想要使用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数据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
}
如果您将一个Car实体加载到当前持久性上下文中,对其进行修改并让Hibernate在刷新时存储更改(最好是在数据库事务中),则可以简单地实现更新。这可以通过使用
@Transactional
注释的Service/DAO方法轻松实现

分离的实体也可以传递给服务,只需重新连接并使用
carRepository.save(detachedAndModifiedCar)
保存即可


甚至您的saveOrEdit方法也只是调用
entityManager.refresh(entity)
对于现有实体。这意味着根本没有更新代码,或者我弄错了吗?该实体将只使用数据库中的数据进行更新。

我尝试注释我的控制器和方法,而不是使用@Transactional处理实体的版本以及调用getAll()的服务方法,但问题仍然存在。但我注意到的一个变化是在之前的跟踪之后的第二个跟踪:org.springframework.transaction.TransactionSystemException:无法提交JPA事务;嵌套异常是javax.persistence.RollbackException:标记为rollbackOn的事务ly]使用root-cause我尝试注释我的控制器和方法,而不是处理带有@Transactional的实体版本以及调用getAll()的服务方法,但运气不好,问题仍然存在。不过,我注意到的一个变化是,在org.springframework.transaction.TransactionSystemException:Can之前的跟踪之后的第二个跟踪
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);
    }

}
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
}
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);
    }

    ...
}