刚开始使用JPA 的小伙伴们,可能有些困惑:
如下源码所示,JPA的CrudRepository只有save 方法,没有update和insert方法。我怎样告诉JPA我是要更新(update)而不是插入(insert)?
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> S save(S entity);
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
Optional<T> findById(ID id);
boolean existsById(ID id);
Iterable<T> findAll();
Iterable<T> findAllById(Iterable<ID> ids);
long count();
void deleteById(ID id);
void delete(T entity);
void deleteAll(Iterable<? extends T> entities);
void deleteAll();
}
在解决以上困惑之前,我们了解一下PA(Persistence API)的两种主要设计方法。
-
update、insert方法
当你需要修改数据库时,显式的调用PA(Persistence API)的方法:调用insert来插入对象,调用update将对象的新状态保存到数据库。 -
工作单元方法
当你需要将新记录插入数据库时,您可以托管相应的对象。 托管对象由其主键标识,因此,如果你使用预定义的主键托管对象,则它将与具有相同ID的数据库记录关联。在这种情况下,你有一组由持久性库(persistence library)管理的对象。 您对这些对象所做的所有更改将在工作单元结束时自动刷新到数据库(通常在当前事务结束时)。
JPA遵循后一种方法,它的save使你的实体如上所述进行管理。 这意味着在具有预定义id的对象上调用save将更新相应的数据库记录而不是插入新的记录,这也解释了为什么是save而不能称为insert。
所以,当我们save没有id的对象时,它直接添加一行到数据库,但是如果我们save有id的对象时,它将更新数据库。如下代码所示:
public void updateStudent(Student student) {
Student studentFromDb = studentRepository.findById(student.getId());
studentFromDb.setFirstname("ming");
studentFromDb.setLastname("li");
studentFromDb.setAge(20);
studentRepository.save(studentFromDb);
}
手写update sql
如果觉得JPA的save做更新操作不习惯,我们可以手写update sql,JPA也是支持sql语句的。@Modifying 表明要对数据库进行修改,方法的返回类型是Integer,它等于受影响的行数,但如果不需要,可以将其设置为void。
@Repository
public interface StudentRepository extends CrudRepository<Student, Integer> {
@Modifying
@Query("UPDATE Student c SET c.address = :address WHERE c.id = :studentId")
int updateAddress(@Param("studentId") int studentId, @Param("address") String address);
}