所以我看了各种关于JPA与Spring Data的教程,在很多场合都是不同的,我不太确定正确的方法是什么。
假设存在以下实体:
package stackoverflowTest.dao;
import javax.persistence.*;
@Entity
@Table(name = "customers")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private long id;
@Column(name = "name")
private String name;
public Customer(String name) {
this.name = name;
}
public Customer() {
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
字符串
我们还有一个DTO,它在服务层中检索,然后交给控制器/客户端。
package stackoverflowTest.dto;
public class CustomerDto {
private long id;
private String name;
public CustomerDto(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
型
因此,现在假设客户想要在webui中更改他的名称-然后将有一些控制器动作,其中将有具有旧ID和新名称的更新的DTO。
现在我必须将此更新的DTO保存到数据库。
不幸的是,目前没有办法更新现有的客户(除了删除DB中的条目并使用新的自动生成的ID创建一个新的客户)
然而,由于这是不可行的(特别是考虑到这样的实体可能有数百个潜在的关系)-所以我想到了两个直接的解决方案:
1.在Customer类中为id创建一个setter-从而允许设置id,然后通过相应的存储库保存Customer对象。
或者是
1.将id字段添加到构造函数中,每当你想更新一个客户时,你总是用旧的id创建一个新的对象,但其他字段的新值(在本例中只有名称)
所以我的问题是,是否有一个一般规则如何做到这一点?我所解释的两种方法的缺点是什么?
8条答案
按热度按时间l7mqbcuq1#
T getById(ID id)
自2.7起已弃用。Please useT getReferenceById(ID id)
instead.的思想是一样的,它只返回一个引用。但它更容易自我解释,因为“getById”可能不清楚,而“getReferenceById”则不那么模糊。字符串
更好的是@Tanjim Rahman回答你可以使用Spring Data JPA使用
T getOne(ID id)
方法型
Is更好,因为
getOne(ID id)
只获取一个引用(代理)对象,而不从DB中获取它。在这个引用上,你可以设置你想要的,在save()
上,它只会像你期望的那样执行一个SQL UPDATE语句。相比之下,当你调用find()
时,比如在@Tanjim Rahmans answer spring data中,JPA将执行SQL SELECT来从DB中物理地获取实体,当你只是更新时,你不需要它。r8xiu3jd2#
在SpringData中,如果您有ID,则只需定义一个更新查询
字符串
一些解决方案声称使用Spring Data 并执行JPA老派(即使以丢失更新的方式)。
wz3gfoph3#
简单的JPA更新..
字符串
shstlldc4#
在JpaRepository中有一个方法
字符串
目前已弃用,而改用
型
所以正确的方法应该是
型
iqxoj9l95#
这更像是一个对象初始化问题,而不是一个jpa问题,两个方法都可以工作,你可以同时使用它们,通常如果数据成员值在示例化之前就准备好了,你就使用构造函数参数,如果这个值在示例化之后可以更新,你就应该有一个setter。
aelbi1ox6#
如果您需要直接使用DTO而不是实体,则应检索现有Customer示例,并将DTO中的更新字段Map到该示例。
字符串
hfwmuf9z7#
因此,现在假设客户想要在webui中更改他的名称-然后将有一些控制器动作,其中将有具有旧ID和新名称的更新的DTO。
通常,您有以下工作流:
1.用户向服务器请求数据并在UI中获取数据;
1.用户更正其数据,并将其发送回服务器与已经存在的ID;
1.在服务器上,你通过用户获取更新数据的DTO,通过ID在DB中找到它(否则抛出异常),然后用所有给定的数据,外键等转换DTO -> Entity。
1.然后你只需要merge它,或者如果使用Spring Data调用保存(),它又会merge它(参见thread);
**P.S.**此操作将不可避免地发出2个查询:选择并更新。同样,2个查询,即使你想更新一个字段。然而,如果你在实体类的顶部使用Hibernate专有的@DynamicUpdate注解,它将帮助你不包括所有的字段,而只包括那些实际改变的字段。
**P.S.**如果你不想为第一个select语句付费,而更喜欢使用Spring Data的@Modifying查询,那么做好丢失与可修改实体相关的L2 C缓存区域的准备;甚至更糟糕的情况与本机更新查询(见此thread),当然也准备手动编写这些查询,测试他们,并支持他们在未来。
jtjikinw8#
我遇到了这个问题!
幸运的是,我确定了 2种方法 ,并了解了一些事情,但其余的不清楚。
希望有认识的人讨论或支持。
1.使用RepositoryExtendJPA.保存(entity)。
范例:
第一个月
此块代码更新了id = 0的记录的新名称;
1.使用javax或spring框架中的@Transactional**。
让我们把@Transactional放在你的类或指定的函数上,两者都可以。
我在某个地方读到过,这个注解在函数流的末尾做了一个“提交”动作。因此,您在实体中修改的所有内容都将更新到数据库中。