转载 关于Spring Data JPA 更新
分类:java 2019-12-14T15:15:13 52人阅读
JpaRepository并没有提供专门的update方法,而是将更新操作放在save中完成了,下面是save方法的源码实现:
@Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
我们看到调用save方法传入一个实例,首先会通过entityInformation.isNew(entity)
来判断该实体是否是一个新的对象,具体的是先判断有无id,如果有就通过id在数据库中查找是否存在对应的数据,如果存在就是更新操作,会调用EntityManager
的merge()
方法执行更新,如果不存在就说明是插入操作,会调用EntityManager
的persist()
方法执行插入。
EntityManager管理器
通过源码我们可以看到save方法实质上是调用的EntityManager的方法完成的数据库操作,所以这里有必要介绍下EntityManager接口,在此之前得了解jpa中实体对象拥有的四种状态:
下面的图清晰的表示了各个状态间的转化关系:
下面介绍下EntityManager接口的几个常用方法:
entityManager.persist(modelObject);
entityManager.merge(modelObject);
// 参数一:实体类的class,参数二:实体主键值
entityManager.find(Class<T> ModelObject.class , int key);
entityManager.remove(entityManager.getReference(ModelObject.class, key));
setFlushModel()
方法修改EntityManager的刷新模式。默认为AUTO
,这种模式下,会在执行查询(指使用JPQL语句查询前,不包括find()和getReference()查询)前或事务提交时自动执行flush()。通过entityManager.setFlushMode(FlushModeType.COMMIT)
设置为COMMIT
模式,该模式下只有在事务提交时才会执行flush()。现在我们再回到更新方法,为了方便查看,我们摘取出上面写好的更新方法实现
public Boolean update(User user) {
Optional<User> u = userDao.findById(user.getId());
if (u.isPresent()) {
User oldUser = u.get();
oldUser.setName(user.getName());
oldUser.setRoles(user.getRoles());
oldUser.setBirthday(user.getBirthday());
oldUser.setEmail(user.getEmail());
oldUser.setUpdateTime(new Date());
userDao.save(oldUser);
return Boolean.TRUE;
}
return Boolean.FALSE;
}
如果你已经理解了上文中的JPA的四种状态,那你应该就能看出这段代码存在的问题,oldUser是从数据库中查出来的,是托管状态对象,受EntityManager管理,我们后面对该对象所做的修改会在事务提交时自动调用flush()
将修改写入数据库完成更新,所以并不需要再调用save()方法执行更新,这样显得多此一举。当然还要注意这样实现更新需要在方法上加@Transactional
启动事务。
下面是修改后的代码实现:
@Transactional
public Boolean update(User user) {
Optional<User> u = userDao.findById(user.getId());
if (u.isPresent()) {
User oldUser = u.get();
oldUser.setName(user.getName());
oldUser.setRoles(user.getRoles());
oldUser.setBirthday(user.getBirthday());
oldUser.setEmail(user.getEmail());
oldUser.setUpdateTime(new Date());
return Boolean.TRUE;
}
return Boolean.FALSE;
}