简体   繁体   English

JPA / MySql具有递增的主要和次要ID的特权

[英]JPA/MySql An eniity with incremental primary and secondary id

I have a resource ,say a Book. 我有资源,比如说一本书。 I want the book to have a book id and version id 我希望这本书具有书号和版本号

On Create operations i want to have incremental id 在创建操作上,我想要增量ID

book id     version id   status
1             0          ACTIVE
2             0          ACTIVE
3             0          ACTIVE

On update i want to have a new version for same id 更新时,我想拥有相同ID的新版本

book id     version id   status
    1             0          INACTIVE    //Changed to inactive
    1             1          ACTIVE      //new row with same id
    2             0          ACTIVE
    3             0          ACTIVE

i have two tables to achive this 我有两个桌子可以达到这个目的

A table to generate the id 生成ID的表

  CREATE TABLE `BookIdGenerator` (
`id`int(11) NOT NULL AUTO_INCREMENT ,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

The Book table 书桌

 CREATE TABLE `Book` (
         `id` int(11) NOT NULL ,
         `version` int(11) NOT NULL,
         `title` varchar(255) NOT NULL,
         `isbn` varchar(255) NOT NULL,

     PRIMARY KEY (`id`,`version`),
     foreign key (`id`) references BookIdGenerator(`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

The entity class is 实体类是

class Book{
private long id;
private int version;
//other fields

What would be the correct table structure and JPA annotations to achive this? 要达到此目的,正确的表结构JPA注释是什么?

Without having any separate table I can have @Id at id and version but this does not allow to retrieve the assigned id to an object on persisting it. 没有任何单独的表,我可以在id和version处使用@Id,但这不允许在持久存储时检索分配给对象的ID。

update : I can have an Emeddable BookId class(with book id and version) and can use an @EmbeddedId in Book but I have to write a Id generator to generate the id. 更新:我可以有一个Emeddable BookId类(具有书ID和版本),并且可以在Book中使用@EmbeddedId,但是我必须编写一个ID生成器来生成ID。 What can I do so that i don't have to write a generator to assign id before persisting in create method ? 我该怎么办,这样在坚持使用create方法之前不必写一个生成器来分配id?

JPA @Version JPA @版本

Your intended use of the version column is not as intended in JPA. 版本列的预期用途与JPA中的预期用途不同。

A version field is used to support the Optimistic Locking of individual DB records. 版本字段用于支持单个数据库记录的乐观锁定。 Each time a transaction attempts to update a record, the version field is compared with the value in the DB. 每次事务尝试更新记录时,都会将版本字段与数据库中的值进行比较。 If they are the same then no other transaction has updated the record. 如果它们相同,则没有其他事务更新记录。 The record will be updated and the version column changed. 记录将被更新,版本列将被更改。 If they are not the same then some other transaction has updated the record and an OptimisticLockException will be thrown. 如果它们不相同,则其他事务更新记录,并且将引发OptimisticLockException。

When updating entities (with JPA's merge()), JPA updates the existing record. 在更新实体(使用JPA的merge())时,JPA更新现有记录。

In your question, when you 'update' the book record, you are in fact creating(persisting) a new record. 在您的问题中,当您“更新”记录时,实际上是在创建(持久)新记录。

Further, the version field is managed by JPA and should not be touched by the application – read only. 此外,版本字段由JPA管理,应用程序不应触摸-只读。 In your example you are creating a new record with a specified version number which is not allowed. 在您的示例中,您正在使用指定的版本号创建新记录。

Primary Keys 主键

You have a PrimaryKey defined for Book, however, you require multiple records to hold the same PrimaryKey. 您已经为Book定义了PrimaryKey,但是,您需要多个记录来保存相同的PrimaryKey。 This will fail as the PrimaryKey must be unique. 这将失败,因为PrimaryKey必须是唯一的。

In this case your id and version form a Compound Primary Key, and you'll need to separate these fields out into a separate class; 在这种情况下,您的ID和版本构成一个复合主键,您需要将这些字段分离到一个单独的类中; a Primary Key Class . 主键类

You would require an application specific versioning if you really want to record each change to a record as a separate record, as you can't use the JPA version field for your purposes. 如果您确实想将每个更改记录为一条记录作为单独的记录,则需要特定于应用程序的版本控制,因为您不能出于目的使用JPA版本字段。

Book_id     Book_Update_id   status    JPA_Version
    1             0          INACTIVE       0
    1             1          ACTIVE         0
    2             0          ACTIVE         0
    3             0          ACTIVE         0 

I've left a JPA version column in although this is not required if you are not modifying records. 我保留了“ JPA版本”列,但是如果您不修改记录,则不需要这样做。

so your Book will look something like this. 因此您的书将看起来像这样。

@Entity //Tell JPA this is an entity to be mapped to your DB.
@IdClass(BookId.class) //you need to repeat the PK fields in this class
class Book{
@Id @Column(name=”Book_id”) //Both id and bookUpdateId annotated with @ID
private long id;            //Together they for a compound Primary Key
@Id @Column(name=”Book_Update_id”)
String bookUpdateId
@Version @Column(name=”JPA_Version”) //Tell JPA where to record its version info
private int version;

It will be upto the application, when creating new records, to decide what the id and bookUpdateId values are to be based on the existing values of a record. 在创建新记录时,由应用程序决定是否要根据记录的现有值确定id和bookUpdateId值。 There is no way JPA can know this. JPA无法知道这一点。 There is therefore no separate table required to support ID generation. 因此,不需要单独的表来支持ID生成。

See Pro JPA 2 by Mike Keith and Merrick Schincariol for all these topics, a good introduction and beyond. 有关所有这些主题,请参见Mike Keith和Merrick Schincariol撰写的Pro JPA 2,一个很好的介绍及其他内容。 This will aslo explain the @IdClass in more detail. 这也将详细解释@IdClass。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM