【发布时间】:2014-08-09 11:29:45
【问题描述】:
在 JPA 中有没有办法将行直接插入到连接表中?我有以下合同和附件实体:
public class Contract implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Version
@Column(name = "version")
private Integer version;
private String number;
private String volume;
@ManyToMany
@JoinTable(joinColumns = @JoinColumn(name = "contract_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "attachment_id", referencedColumnName = "id"))
private List<Attachment> attachments;
}
Attachment实体:
public class Attachment implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Version
@Column(name = "version")
private Integer version;
private String name;
}
由于线程并发问题,我想直接在合约中添加附件,而不需要加载合约,将附件添加到列表中并持久化/保存合约,因为合约对象中没有数据正在更新本身。更详细一点,我有多个线程并行保存附件,如果我要在所有这些线程中保留合同,我需要进行某种并发控制以避免 OptimisticLockExceptions。鉴于 Contract 实体没有被修改(只有连接表),我不想陷入瓶颈,只直接更新连接表。
在 JPA 和/或 JPQL 中有没有办法将行直接插入连接表?工作流程是持久化附件,然后将适当的行插入到连接表中。
有没有办法从实体中检索 JPA 生成的连接表名称?
DDL:
CREATE TABLE `contract` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`number` varchar(255) DEFAULT NULL,
`volume` varchar(255) DEFAULT NULL,
`version` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
CREATE TABLE `attachment` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`version` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=197 DEFAULT CHARSET=utf8;
CREATE TABLE `contract_attachment` (
`contract_id` bigint(20) NOT NULL,
`attachment_id` bigint(20) NOT NULL,
UNIQUE KEY `UK_27094bpt88d7bfngq5v52jrs` (`attachment_id`),
KEY `FK_i1ycj6ewd536bky08t0jjh15d` (`contract_id`),
CONSTRAINT `FK_i1ycj6ewd536bky08t0jjh15d` FOREIGN KEY (`contract_id`) REFERENCES `contract` (`id`),
CONSTRAINT `FK_27094bpt88d7bfngq5v52jrs` FOREIGN KEY (`attachment_id`) REFERENCES `attachment` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
【问题讨论】:
-
你当然可以只保留一个
Attachment,但是由于数据池和缓存,在重新启动它之前,你的程序可能看不到这个信息,就像你直接插入一条记录一样使用另一个客户端进入数据库。 -
@ScaryWombat - 因此需要/理由使用 JPQL(通过实体管理器)来更新连接表。
-
在执行
Attachment插入调用entityManager.getEntityManagerFactory().getCache().evictAll()以刷新缓存之后。 -
@ScaryWombat 但问题是我必须持久化 Contract 对象,否则连接表将不会更新。但是,如果我持久化 Contract 对象,它将更新其版本(即使 Contract 表本身没有任何更改),因此另一个线程将收到 OptimisticLockException,因为版本号不再匹配。这就是为什么我正在寻找一种方法来更新连接表而不修改合同表。
-
因为
Contract表中没有任何实际需要更新的内容,并且如果数据未缓存,那么如果Attachment链接到Attachment,数据的新读取应该返回所有行。假设数据模型是一对多而不是单链接表一
标签: java jpa jpa-2.0 jpql spring-data-jpa