如何通过JPA保留数据而无需主键

时间:2019-06-20 23:18:30

标签: java spring hibernate jpa spring-data-jpa

我有流经我的应用程序的数据,通常不需要打扰,但要实现一项新功能,我需要临时存储它(例如1个小时)。输入的数据可以与其中已经存在的数据完全相同,因此不需要主键。但是,使用JPA实体需要一个ID,但我不需要/想要一个。这使我无法正常工作。

这是通过Spring使用JPA实现的。由于数据经常移入和移出数据库,因此不建议使用自动生成的ID,因为它会在几年后通过ID。我试图使它可嵌入,并说它需要进行组件扫描以找到它的使用位置,但是如果我将其制成一个实体,则它会提示我它需要主键。

这是我的实体,用于存储我需要保留的数据。

@Entity
@Table(name = "quoteOrderHistory")
public class QuoteOrderHistory {

    @Column(name = "storeNumber")
    private int storeNumber;

    @Column(name = "invoiceNumber")
    private String invoiceNumber;

    @Column(name = "quoteSaleDate")
    private Date quoteSaleDate;

    @Column(name="orderTotal")
    private BigDecimal orderTotal;

    @Column(name="orderHistoryDate")
    private Timestamp orderHistoryDate;

    // Constructors, Getters and Setters

}

这是我访问数据的存储库。

@Repository
public interface QuoteOrderHistoryRepository extends JpaRepository<QuoteOrderHistory, Long> {

    @Query("DELETE FROM QuoteOrderHistory q WHERE q.orderHistoryDate > date")
    void deleteAllExpired(Date date);

    @Query("SELECT q FROM QuoteOrderHistory q WHERE q.storeNumber = ?1 AND q.invoiceNumber = ?2 ORDER BY q.orderHistoryDate DESC")
    List<QuoteOrderHistory> findAllByStoreAndInvoiceDesc(int storeNumber, String invoiceNumber);
}

我不知道该怎么做。同样,不需要主键,因为它假定支持重复项。如果没有使用JPA的另一种解决方法,那么我全力以赴,但是目前看来,持久保存数据是最容易的。如果您需要更多信息,请告诉我。我也可能缺少可以避免这些事情的方法,但是我对JPA并不熟悉。因此,感谢所有帮助。

2 个答案:

答案 0 :(得分:2)

如果使用正确的大小,则列的ID不会用完。停止尝试使用您的框架,只需添加一个自动递增的列即可。

https://hashrocket.com/blog/posts/running-out-of-ids

  

比方说,生意如此好,我们每个月插入10,000条记录   分钟到我们的桌子。因此,要花多长时间才能最大限度地利用我们   顺序? 1750380517年

来自How large can an id get in postgresql

Name        Storage Size    Description                       Range
smallint    2 bytes         small-range integer               -32768 to +32767
integer     4 bytes         usual choice for integer          -2147483648 to +2147483647
bigint      8 bytes         large-range integer               -9223372036854775808 to 9223372036854775807
serial      4 bytes         autoincrementing integer          1 to 2147483647
bigserial   8 bytes         large autoincrementing integer    1 to 9223372036854775807

如果出于某种我可能无法理解的原因而急于不使用id列,则看起来可以在JPA中通过将每个列作为主键描述的一部分来实现,但是随后您的删除和更新操作将删除/更新任意数量的记录。我没有尝试过。我不会在生产服务器上实现此功能。

https://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#No_Primary_Key

  

有时您的对象或表没有主键。最好的解决方案   在这种情况下,通常是将生成的ID添加到对象中,   表。如果您没有此选项,则有时会有一列或   表中构成唯一值的一组列。您可以使用   这组唯一的列作为您在JPA中的ID。 JPA ID不   总是必须匹配数据库表的主键约束,也不是   主键或所需的唯一约束。

     

如果您的表确实没有唯一列,请使用所有列   作为ID。通常,发生这种情况时数据是只读的,因此即使   如果表允许具有相同值的重复行,则对象   无论如何都是相同的,所以JPA认为他们没关系   是同一个对象。允许更新和删除的问题是   无法唯一标识对象的行,因此所有   匹配的行将被更新或删除。

     

如果您的对象没有ID,但是其表具有ID,则可以。   使对象成为可嵌入对象,可嵌入对象没有   ID。您将需要一个包含此可嵌入对象的实体才能持久   并查询它。

答案 1 :(得分:0)

Jazzepi说的是正确的,但严格要求我不要使用自动生成的数字作为ID。因此,人们使用UUID链接了此here描绘。这是解决此问题的最佳选择,因为数据库中的对象被安排在其中的时间不超过几个小时。既然是这种情况,那么UUID将永远不会溢出,并且在任何给定时间在表内重复UUID的可能性几乎为零,因为大多数人不会留在那里。

新实体类:

@Entity
@Table(name = "quoteOrderHistory")
public class QuoteOrderHistory {

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
    @Column(name = "uuid", unique = true)
    private String uuid;

    @Column(name = "storeNumber")
    private int storeNumber;

    @Column(name = "invoiceNumber")
    private String invoiceNumber;

    @Column(name = "quoteSaleDate")
    private Date quoteSaleDate;

    @Column(name="orderTotal")
    private BigDecimal orderTotal;

    @Column(name="orderHistoryDate")
    private Timestamp orderHistoryDate;

    // Constructor, getters, setters

}