英文:
Hibernate does not allow to save data with similar id
问题
我正在学习Spring,几天前我开始学习Hibernate。我有一个学习项目,我需要创建一个带有产品的商店。以下是实体类:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Entity
@Table(name = "cart")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cart {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "quantity")
private int quantity;
@Column(name = "mask")
private String mask;
@Column(name = "price")
private int price;
然后,我创建了接口:
import org.springframework.data.jpa.repository.JpaRepository;
public interface CartRepository extends JpaRepository<Cart, Integer> {
}
并创建了控制器:
@Autowired
CartRepository cartList;
@RequestMapping("/add-black-mask")
public String addBlackMask() {
cartList.save(new Cart(1, 1, "black", 3));
return "masks/add-black-mask";
}
@RequestMapping("/add-build-mask")
public String addBuildMask() {
cartList.save(new Cart(2, 1, "build", 5));
return "masks/add-build-mask";
}
@RequestMapping(value = "/save_product_to_cart")
public ModelAndView saveProduct(@ModelAttribute(value = "cart")
Cart cart, BindingResult result) {
int index = Integer.parseInt(String.valueOf(cartList.count()));
if (cart.getId() == 0) {
cart.setId(index + 1);
cartList.save(cart);
} else {
Cart cart1 = cartList.getOne(cart.getId());
cart1.setMask(cart.getMask());
cart1.setQuantity(cart.getQuantity());
cart1.setPrice(cart.getPrice());
cartList.save(cart1);
}
return new ModelAndView("redirect:/");
}
还有一些其他用于视图、Thymeleaf等的控制器,但没关系。我的问题是 - 当我保存产品1次时 - 一切正常,但当我保存第二次时 - 它不起作用(我认为是因为我不能保存具有相似ID的2行数据)。因此,似乎在我的表中我有唯一的ID,并且它不能重复。问题是 - 如何删除唯一的ID或以任何方式更改我的代码?提前谢谢!
p.s. 我阅读了这里的一些其他主题,但对我没有帮助。
英文:
I'm learning Spring and few days ago i started learning Hibernate. I have my studying project where i need to create a shop with products. Here is entity class
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Entity
@Table(name = "cart")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cart {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "quantity")
private int quantity;
@Column(name = "mask")
private String mask;
@Column(name = "price")
private int price;
So, i create interface
import org.springframework.data.jpa.repository.JpaRepository;
public interface CartRepository extends JpaRepository<Cart, Integer> {
}
and create controllers
@Autowired
CartRepository cartList;
@RequestMapping("/add-black-mask")
public String addBlackMask() {
cartList.save(new Cart(1, 1, "black", 3));
return "masks/add-black-mask";
}
@RequestMapping("/add-build-mask")
public String addBuildMask() {
cartList.save(new Cart(2, 1, "build", 5));
return "masks/add-build-mask";
}
@RequestMapping(value = "/save_product_to_cart")
public ModelAndView saveProduct(@ModelAttribute(value = "cart")
Cart cart, BindingResult result) {
int index = Integer.parseInt(String.valueOf(cartList.count()));
if (cart.getId() == 0) {
cart.setId(index + 1);
cartList.save(cart);
} else {
Cart cart1 = cartList.getOne(cart.getId());
cart1.setMask(cart.getMask());
cart1.setQuantity(cart.getQuantity());
cart1.setPrice(cart.getPrice());
cartList.save(cart1);
}
return new ModelAndView("redirect:/");
}
Also, there are some other controllers for view, Thymeleaf etc, but its ok. My problem is - when i save my product 1 time - its ok, but when i save second - it didnt work( i think because i can't save 2 rows with similar ID) So it seems i have UNIQUE ID in my table and it can not be repeated. Question is - how can i delete unique id or change my code in any way? Thanks in advance!
p.s. i read some other topics here but it didnt help me.
答案1
得分: 0
当您使用 GENERATIONTYPE.IDENTITY
时,您正在要求 Hibernate 由数据库为您处理 Ids,您不应该自行设置它。您正在更改 id 的值,只需创建一个新产品,设置所有字段,并在事务上下文中保存您的产品。此外,为了序列化目的,始终使用基本类型的包装版本(Long
是一个对象,但 long
是一个基本类型)。您可以搜索“装箱和拆箱”以了解更多信息。
英文:
when you use GENERATIONTYPE.IDENTITY
you are asking hibernate to let the database handle Ids for you, you should not set it yourself. you are changing the value of the id, just create a new product, set all the fields and inside a transactional context, save your product. Also always use wrapped versions of primitives for serialization purposes. (Long
is an object but long
is a primitive.) you can google boxing and unboxing and learn more about this.
答案2
得分: 0
让我来回答这个问题:
首先,将注解用作我们的配置方法只是一种方便的方法,而不是复制无休止的 XML 配置文件。
@Id
注解继承自 javax.persistence.Id
,表示下面的成员字段是当前实体的主键。因此,您的 Hibernate 和 Spring 框架以及您可以基于此注解进行一些反射工作。有关详细信息,请查看 Id 的 javadoc。
@GeneratedValue
注解用于配置指定列(字段)的递增方式。例如,在使用 Mysql
时,您可以在表的定义中指定 auto_increment
,以使其自增,并在 Java 代码中使用以下内容:
@GeneratedValue(strategy = GenerationType.IDENTITY)
来表示您也确认使用这个数据库服务器端的策略。此外,您可以根据不同的需求更改此注解中的值。
1. 在数据库中定义 Sequence
例如,Oracle 必须使用 sequence
作为增量方法,比如我们在 Oracle 中创建一个序列:
create sequence oracle_seq;
2. 引用数据库序列
既然我们在数据库中有了序列,但我们需要建立 Java 和数据库之间的关系,可以使用 @SequenceGenerator
:
@SequenceGenerator(name="seq", sequenceName="oracle_seq")
sequenceName
是 Oracle 中序列的实际名称,name
是您在 Java 中想要称呼它的名称。如果与 name
不同,您需要指定 sequenceName
,否则只需使用 name
。我通常会忽略 sequenceName
,以节省时间。
3. 在 Java 中使用序列
最后,是时候在 Java 中使用这个序列了。只需添加 @GeneratedValue
:
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
generator
字段指的是您要使用的序列生成器。请注意,这不是数据库中实际的序列名称,而是您在 SequenceGenerator
的 name
字段中指定的名称。
4. 完整版本
因此,完整的版本应该是这样的:
public class Cart
{
@Id
@SequenceGenerator(name="seq", sequenceName="oracle_seq")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
private Integer id;
}
现在开始使用这些注解,使您的 JavaWeb 开发变得更加简便。
此外,我希望您理解 Hibernate 中的所有 4 种 ID 生成方式。您可以在空闲时间考虑阅读一下:
- GenerationType.AUTO
- GenerationType.IDENTITY(您的情况)
- GenerationType.SEQUENCE
- GenerationType.TABLE(现在很少使用)
英文:
Let me answer this question:
First of all, using annotations as our configure method is just a convenient method instead of coping the endless XML configuration file.
The @Id
annotation is inherited from javax.persistence.Id
, indicating the member field below is the primary key of current entity. Hence your Hibernate and spring framework as well as you can do some reflect
works based on this annotation. for details please check javadoc for Id
The @GeneratedValue
annotation is to configure the way of increment of the specified column(field). For example when using Mysql
, you may specify auto_increment
in the definition of table to make it self-incremental, and then use
@GeneratedValue(strategy = GenerationType.IDENTITY)
in the Java code to denote that you also acknowledged to use this database server side strategy. Also, you may change the value in this annotation to fit different requirements.
1. Define Sequence in database
For instance, Oracle has to use sequence
as increment method, say we create a sequence in Oracle:
create sequence oracle_seq;
2. Refer the database sequence
Now that we have the sequence in database, but we need to establish the relation between Java and DB, by using @SequenceGenerator
:
@SequenceGenerator(name="seq",sequenceName="oracle_seq")
sequenceName
is the real name of a sequence in Oracle, name
is what you want to call it in Java. You need to specify sequenceName
if it is different from name
, otherwise just use name
. I usually ignore sequenceName
to save my time.
3. Use sequence in Java
Finally, it is time to make use this sequence in Java. Just add @GeneratedValue
:
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
The generator
field refers to which sequence generator you want to use. Notice it is not the real sequence name in DB, but the name you specified in name
field of SequenceGenerator
.
4. Complete
So the complete version should be like this:
public class Cart
{
@Id
@SequenceGenerator(name="seq",sequenceName="oracle_seq")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
private Integer id;
}
Now start using these annotations to make your JavaWeb development easier.
On top of that I would like you to understand all 4 ways of ID generation in hibernate. You can think of reading in your free time
- GenerationType.AUTO
- GenerationType.IDENTITY (your case)
- GenerationType.SEQUENCE
- GenerationType.TABLE {Rarely used nowdays}
专注分享java语言的经验与见解,让所有开发者获益!
评论