JPA / MySql具有增量主要和次要ID的eniity

时间:2015-07-27 20:52:14

标签: 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          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分配给它。

更新:我可以拥有一个Emeddable BookId类(带有书籍ID和版本),可以在Book中使用@EmbeddedId,但我必须编写一个Id生成器来生成id。 我能做什么,以便在坚持创建方法之前我不必编写生成器来分配id?

1 个答案:

答案 0 :(得分:0)

JPA @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的Pro JPA 2所有这些主题,一个很好的介绍和超越。这将更详细地解释@IdClass。