这个问题几乎说明了一切。使用JPARepository我如何更新一个实体?
JPARepository只有一个save方法,它并没有告诉我它是创建还是更新。例如,我插入一个简单的对象到数据库User,它有三个字段:姓,名和年龄:
@Entity
public class User {
private String firstname;
private String lastname;
//Setters and getters for age omitted, but they are the same as with firstname and lastname.
private int age;
@Column
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
@Column
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
private long userId;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public long getUserId(){
return this.userId;
}
public void setUserId(long userId){
this.userId = userId;
}
}
然后我简单地调用save(),这在这一点上实际上是插入到数据库:
User user1 = new User();
user1.setFirstname("john"); user1.setLastname("dew");
user1.setAge(16);
userService.saveUser(user1);// This call is actually using the JPARepository: userRepository.save(user);
到目前为止一切顺利。现在我要更新这个用户,比如改变他的年龄。为此,我可以使用QueryDSL或NamedQuery之类的查询。但是,考虑到我只想使用spring-data-jpa和JPARepository,我如何告诉它我想做更新而不是插入呢?
具体来说,我如何告诉spring-data-jpa具有相同用户名和名字的用户实际上是EQUAL,并且现有实体应该被更新?重写等号并不能解决这个问题。
你可以看到下面的例子:
private void updateDeliveryStatusOfEvent(Integer eventId, int deliveryStatus) {
try {
LOGGER.info("NOTIFICATION_EVENT updating with event id:{}", eventId);
Optional<Event> eventOptional = eventRepository.findById(eventId);
if (!eventOptional.isPresent()) {
LOGGER.info("Didn't find any updatable notification event with this eventId:{}", eventId);
}
Event event = eventOptional.get();
event.setDeliveryStatus(deliveryStatus);
event = eventRepository.save(event);
if (!Objects.isNull(event)) {
LOGGER.info("NOTIFICATION_EVENT Successfully Updated with this id:{}", eventId);
}
} catch (Exception e) {
LOGGER.error("Error :{} while updating NOTIFICATION_EVENT of event Id:{}", e, eventId);
}
}
或使用本机查询更新:
public interface YourRepositoryName extends JpaRepository<Event,Integer>{
@Transactional
@Modifying
@Query(value="update Event u set u.deliveryStatus = :deliveryStatus where u.eventId = :eventId", nativeQuery = true)
void setUserInfoById(@Param("deliveryStatus")String deliveryStatus, @Param("eventId")Integer eventId);
}
因为@axtavt的回答关注的是JPA而不是spring-data-jpa
通过查询来更新一个实体,然后保存是不高效的,因为它需要两次查询,而且可能查询会非常昂贵,因为它可能会连接其他表并加载任何fetchType= fetchType的集合。急切的
Spring-data-jpa支持更新操作。
您必须在Repository接口中定义该方法。并使用@Query和@Modifying进行注释。
@Modifying
@Query("update User u set u.firstname = ?1, u.lastname = ?2 where u.id = ?3")
void setUserInfoById(String firstname, String lastname, Integer userId);
@Query用于定义自定义查询,@Modifying用于告诉spring-data-jpa这个查询是一个更新操作,它需要executeUpdate()而不是executeQuery()。
您可以将返回类型指定为int,其中包含正在更新的记录的数量。
注意:在事务中运行此代码。
如果你的主键是自动递增的,那么你必须设置主键的值。
对于save();方法作为update()工作。否则它将在db中创建一个新记录。
如果使用JSP表单,则使用隐藏字段设置主键。
Jsp:
<form:input type="hidden" path="id" value="${user.id}"/>
Java:
@PostMapping("/update")
public String updateUser(@ModelAttribute User user) {
repo.save(user);
return "redirect:userlist";
}
再看看这个:
@Override
@Transactional
public Customer save(Customer customer) {
// Is new?
if (customer.getId() == null) {
em.persist(customer);
return customer;
} else {
return em.merge(customer);
}
}