Database 春季数据:Crudepository';s保存方法和更新

Database 春季数据:Crudepository';s保存方法和更新,database,hibernate,spring-mvc,spring-data,spring-data-jpa,Database,Hibernate,Spring Mvc,Spring Data,Spring Data Jpa,我想知道crudepository中的{save}方法如果已经在数据库中找到条目,是否会执行更新,如: @Repository public interface ProjectDAO extends CrudRepository<Project, Integer> {} @Service public class ProjectServiceImpl { @Autowired private ProjectDAO pDAO; public void save(Project p

我想知道
crudepository
中的
{save}
方法如果已经在数据库中找到条目,是否会执行更新,如:

@Repository
public interface ProjectDAO extends CrudRepository<Project, Integer> {}

@Service
public class ProjectServiceImpl {

@Autowired private ProjectDAO pDAO;

public void save(Project p) { pDAO.save(p); } }
@存储库
公共接口项目DAO扩展了CRUDEPository{}
@服务
公共类ProjectServiceImpl{
@自连线私人项目DAO pDAO;
公共无效保存(项目p){pDAO.save(p);}
所以,如果我在一个已经注册的条目上调用该方法,它会在发现一个已更改的属性时更新它吗


谢谢。

查看CRUDepository接口的默认实现

 /*
     * (non-Javadoc)
     * @see org.springframework.data.repository.CrudRepository#save(java.lang.Object)
     */
    @Transactional
    public <S extends T> S save(S entity) {

        if (entityInformation.isNew(entity)) {
            em.persist(entity);
            return entity;
        } else {
            return em.merge(entity);
        }
    }
/*
*(非Javadoc)
*@see org.springframework.data.repository.crudepository#save(java.lang.Object)
*/
@交易的
公共存储(S实体){
if(entityInformation.isNew(实体)){
em.persist(实体);
返回实体;
}否则{
返回em.merge(实体);
}
}
保存方法管理两种情况:

-如果人员Id为null(创建了一个新实体),则将执行save调用persist method=>insert查询

-如果人员id不为null,则save将调用merge:从entityManagerFactory获取现有实体(如果不存在,则从2级缓存获取),并将分离的实体与托管实体进行比较,最后通过调用update query将更改传播到数据库


我想知道crudepository中的{save}方法是否进行了更新 如果它已经在数据库中找到该条目

关于它的Spring文档并不精确:

保存给定的实体。将返回的实例用于进一步的操作 因为保存操作可能已更改实体实例 完全是

但是由于
crudepository
接口没有提出另一种具有显式命名的方法来更新实体,我们可以假设是,因为CRUD需要执行所有CRUD操作(创建、读取、更新、删除)

通过实现
SimpleJpaRepository
类,该类是
crudepository
的默认实现,它显示这两种情况都由以下方法处理:

@Transactional
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}
@Transactional
公共存储(S实体){
if(entityInformation.isNew(实体)){
em.persist(实体);
返回实体;
}否则{
返回em.merge(实体);
}
}
因此,如果我对已注册的条目调用该方法,它将更新 如果它发现了一个更改的属性,它会怎么做


在这种情况下,它将执行合并操作。因此,所有字段都会根据合并级联和只读选项的设置进行更新。

我想知道Crudepository中的{save}方法是否会在数据库中找到条目时进行更新:

答案是肯定的,如果找到条目,它将更新:

来自Spring文档:这里

可以通过crudepository.save(…)-方法保存实体。它将使用底层JPA EntityManager持久化或合并给定实体。如果实体尚未被持久化,Spring Data JPA将通过调用entityManager.persist(…)-方法保存实体,否则将调用entityManager.merge(…)-方法。

准确地说,如果id为空,则save(obj)方法将obj视为新的记录(因此将进行插入)如果填写了id,则将obj视为现有的记录(因此将进行合并)

为什么这很重要?

假设项目对象包含一个自动生成的id和一个必须唯一的person_id。创建一个项目对象并填写person_id,但不填写id,然后尝试保存。Hibernate将尝试插入此记录,因为id为空,但如果数据库中已经存在此人,则会出现重复密钥异常

如何处理
执行findByPersonId(id)检查obj是否已经在数据库中,如果找到它,则从中获取id,

或者只是尝试保存并捕获异常,在这种情况下,您知道它已经在数据库中,您需要在保存之前获取并设置id

在我的例子中,我必须将id属性添加到实体中,并像这样放置注释@id

@Id
private String id;

这样,当您获取对象时,该对象在数据库中具有实体的Id,并且执行更新操作而不是创建。

因此,如果该实体具有复杂类型,比如说图像,那么我想我需要徒手更新。图像是什么意思?如果它不是jpa关系字段,则在任何情况下都会进行更新。因此,如果要保存的实体中的字段为null,那么它将在现有行中将其值覆盖为null。另一件事,这里我看到了'@Transactionel',因此我不需要将该注释添加到服务类no?
@Transactional
默认使用Progration:Propagation.REQUIRED,它支持当前事务,如果不存在,则创建一个新事务。因此,是的,在您的服务中不需要使用@Transactional,但是如果您希望从服务方法手动处理回滚,则不需要使用@Transactional。如果我回答了你的问题,不要犹豫,接受它。