Java JPA/MySql是一个具有增量主id和辅助id的Enity

Java JPA/MySql是一个具有增量主id和辅助id的Enity,java,mysql,hibernate,jpa,Java,Mysql,Hibernate,Jpa,我有一个资源,比如说一本书。 我希望这本书有一个图书id和版本id 在创建操作时,我希望有增量id book id version id status 1 0 ACTIVE 2 0 ACTIVE 3 0 ACTIVE 更新时,我希望有一个相同id的新版本 book id version id status 1 0

我有一个资源,比如说一本书。 我希望这本书有一个图书id和版本id

在创建操作时,我希望有增量id

book id     version id   status
1             0          ACTIVE
2             0          ACTIVE
3             0          ACTIVE
更新时,我希望有一个相同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
我有两张桌子来做这个

用于生成id的表

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

 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;
实体类是

class Book{
private long id;
private int version;
//other fields
要做到这一点,正确的表格结构和JPA注释是什么

如果没有任何单独的表,我可以在Id和version处使用@Id,但这不允许在持久化对象时检索分配给它的Id

更新:我可以有一个emedtable BookId类(带有book id和version),也可以在book中使用@EmbeddedId,但我必须编写一个id生成器来生成id。
我可以做些什么,这样我就不必在持久化create方法之前编写生成器来分配id了?

JPA@Version

您对version列的预期用途与JPA中的预期不同

版本字段用于支持单个DB记录的乐观锁定。每次事务尝试更新记录时,都会将版本字段与数据库中的值进行比较。如果它们相同,则没有其他事务更新记录。将更新记录并更改版本列。如果它们不相同,则其他一些事务已更新记录,并将抛出OptimisticLockException

更新实体时(使用JPA的merge()),JPA会更新现有记录

在您的问题中,当您“更新”图书记录时,实际上您正在创建(持久化)一个新记录

此外,版本字段由JPA管理,应用程序不应触及它–只读。在您的示例中,您正在创建具有指定版本号的新记录,这是不允许的

主键

您已经为Book定义了PrimaryKey,但是,您需要多个记录来保存同一PrimaryKey。这将失败,因为PrimaryKey必须是唯一的

在这种情况下,您的id和版本形成一个复合主键,您需要将这些字段分离到一个单独的类中;主键类

如果您真的想将记录的每个更改记录为一个单独的记录,则需要特定于应用程序的版本控制,因为您不能将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 
我在中留下了一个JPA版本列,尽管如果您不修改记录,这不是必需的

所以你的书看起来像这样

@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;

创建新记录时,由应用程序根据记录的现有值决定id和bookUpdateId值。JPA不可能知道这一点。因此,不需要单独的表来支持ID生成


请参阅迈克·基思(Mike Keith)和梅里克·辛卡里奥(Merrick Schincariol)的《专业JPA 2》,了解所有这些主题,这是一个很好的介绍。这也将更详细地解释@IdClass。

JPA@Version

您对version列的预期用途与JPA中的预期不同

版本字段用于支持单个DB记录的乐观锁定。每次事务尝试更新记录时,都会将版本字段与数据库中的值进行比较。如果它们相同,则没有其他事务更新记录。将更新记录并更改版本列。如果它们不相同,则其他一些事务已更新记录,并将抛出OptimisticLockException

更新实体时(使用JPA的merge()),JPA会更新现有记录

在您的问题中,当您“更新”图书记录时,实际上您正在创建(持久化)一个新记录

此外,版本字段由JPA管理,应用程序不应触及它–只读。在您的示例中,您正在创建具有指定版本号的新记录,这是不允许的

主键

您已经为Book定义了PrimaryKey,但是,您需要多个记录来保存同一PrimaryKey。这将失败,因为PrimaryKey必须是唯一的

在这种情况下,您的id和版本形成一个复合主键,您需要将这些字段分离到一个单独的类中;主键类

如果您真的想将记录的每个更改记录为一个单独的记录,则需要特定于应用程序的版本控制,因为您不能将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 
我在中留下了一个JPA版本列,尽管如果您不修改记录,这不是必需的

所以你的书看起来像这样

@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;

创建新记录时,由应用程序根据记录的现有值决定id和bookUpdateId值。JPA不可能知道这一点。因此,不需要单独的表来支持ID生成


请参阅迈克·基思(Mike Keith)和梅里克·辛卡里奥(Merrick Schincariol)的《专业JPA 2》,了解所有这些主题,这是一个很好的介绍。这也将更详细地解释@IdClass。

关于版本的
@Version
注释如何?关于版本的
@Version
注释如何?“创建新记录时,将由应用程序决定id是什么…”您的意思是我将有一个生成器类在创建过程中分配id。我使用它让一个随机id生成器将id分配给一个嵌入式id BookId。我可以不使用内置的生成策略,而使用一个生成器或一个策略来使用数据库分配的自动增量id吗?@bl3e问题是知道增加什么-Book_id?这本书的id是什么?如果您创建的记录最初是Book_id=2和Book_Update_id=1,那么您只需等待Book_Update_id增加到2即可。如果您创建了一本新书,那么您希望book_id=4(给定上述数据)