gpt4 book ai didi

java - 如何使用 JPA 和 Hibernate 复制 INSERT/UPDATE/DELETE 语句

转载 作者:行者123 更新时间:2023-11-29 11:39:23 26 4
gpt4 key购买 nike

我想以我的系统可恢复的方式重命名 PostgreSQL (9.6) 表(使用 JPA/Hibernate 的 Java 应用程序)

在我的 java 代码中,JPA 实体将具有以下注释 @Entity @Table(name="old_name") 并且数据库将具有一个等效的表,称为old_name.

我想以一种可以增量更新数据库和 Java 应用程序的方式将表重命名为 new_name,允许失败和回滚。

典型的步骤是

  1. new_name 中创建 old_name 的副本
  2. 确保读/写在这两种方式中都可用(即数据被双向复制)
  3. 更新 java 应用以使用新表 new_name
  4. 当自信的系统更新完成后,删除 old_name

实际上我想要一个具有相同数据的相同架构中的重复表,都能够接受读取和写入,并且可以从 JPA 实体中读取。

我知道触发器的使用,并希望避免这种情况。我希望有一种我不知道也没有发现的技术可以使这比使用触发器更不痛苦。

我试图重命名该表并在其上创建一个“简单 View ”,但是 JPA 实体提示说它找不到具有该 View 名称的表。 (因为它是一个 View ,而不是一个表 :) 并且似乎没有 @View/@Table JPA 注释可以处理这个问题)

我还没有尝试过这里列出的设施:http://wiki.postgresql.org/wiki/Replication,_Clustering,_and_Connection_Pooling因为大多数似乎与池化、分片有关,我需要一个简单的短期表副本,但我也会研究这些。

谢谢 - 我当然想要最简单的选择,更喜欢 postgres/JPA 内置的东西,但也会认真考虑第 3 方选项。

最佳答案

数据库表

假设您有以下两个表:

CREATE TABLE old_post (
id int8 NOT NULL,
title varchar(255),
version int4 NOT NULL,
PRIMARY KEY (id)
)

CREATE TABLE post (
id int8 NOT NULL,
created_on date,
title varchar(255),
version int4 NOT NULL,
PRIMARY KEY (id)
)

JPA实体

必须使用较新的post 复制old_post 表。请注意,post 表现在比旧表有更多的列。

我们只需要映射Post实体:

@Entity(name = "Post")
@Table(name = "post")
public static class Post {

@Id
private Long id;

private String title;

@Column(name = "created_on")
private LocalDate createdOn = LocalDate.now();

@Version
private int version;

//Getters and setters omitted for brevity
}

hibernate 事件监听器

现在,我们必须注册 3 个事件监听器来拦截 Post 实体的 INSERT、UPDATE 和 DELETE 操作。

我们可以通过以下事件监听器来做到这一点:

public class ReplicationInsertEventListener 
implements PostInsertEventListener {

public static final ReplicationInsertEventListener INSTANCE =
new ReplicationInsertEventListener();

@Override
public void onPostInsert(
PostInsertEvent event)
throws HibernateException {
final Object entity = event.getEntity();

if(entity instanceof Post) {
Post post = (Post) entity;

event.getSession().createNativeQuery(
"INSERT INTO old_post (id, title, version) " +
"VALUES (:id, :title, :version)")
.setParameter("id", post.getId())
.setParameter("title", post.getTitle())
.setParameter("version", post.getVersion())
.setFlushMode(FlushMode.MANUAL)
.executeUpdate();
}
}

@Override
public boolean requiresPostCommitHanding(
EntityPersister persister) {
return false;
}
}

public class ReplicationUpdateEventListener
implements PostUpdateEventListener {

public static final ReplicationUpdateEventListener INSTANCE =
new ReplicationUpdateEventListener();

@Override
public void onPostUpdate(
PostUpdateEvent event) {
final Object entity = event.getEntity();

if(entity instanceof Post) {
Post post = (Post) entity;

event.getSession().createNativeQuery(
"UPDATE old_post " +
"SET title = :title, version = :version " +
"WHERE id = :id")
.setParameter("id", post.getId())
.setParameter("title", post.getTitle())
.setParameter("version", post.getVersion())
.setFlushMode(FlushMode.MANUAL)
.executeUpdate();
}
}

@Override
public boolean requiresPostCommitHanding(
EntityPersister persister) {
return false;
}
}

public class ReplicationDeleteEventListener
implements PreDeleteEventListener {

public static final ReplicationDeleteEventListener INSTANCE =
new ReplicationDeleteEventListener();

@Override
public boolean onPreDelete(
PreDeleteEvent event) {
final Object entity = event.getEntity();

if(entity instanceof Post) {
Post post = (Post) entity;

event.getSession().createNativeQuery(
"DELETE FROM old_post " +
"WHERE id = :id")
.setParameter("id", post.getId())
.setFlushMode(FlushMode.MANUAL)
.executeUpdate();
}

return false;
}
}

可以使用 Hibernate Integrator 注册 3 个事件监听器:

public class ReplicationEventListenerIntegrator 
implements Integrator {

public static final ReplicationEventListenerIntegrator INSTANCE =
new ReplicationEventListenerIntegrator();

@Override
public void integrate(
Metadata metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {

final EventListenerRegistry eventListenerRegistry =
serviceRegistry.getService(EventListenerRegistry.class);

eventListenerRegistry.appendListeners(
EventType.POST_INSERT,
ReplicationInsertEventListener.INSTANCE
);

eventListenerRegistry.appendListeners(
EventType.POST_UPDATE,
ReplicationUpdateEventListener.INSTANCE
);

eventListenerRegistry.appendListeners(
EventType.PRE_DELETE,
ReplicationDeleteEventListener.INSTANCE
);
}

@Override
public void disintegrate(
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {

}
}

并且,要指示 Hibernate 使用此自定义 Integrator,您需要设置 hibernate.integrator_provider 配置属性:

<property name="hibernate.integrator_provider"
value="com.vladmihalcea.book.hpjp.hibernate.listener.ReplicationEventListenerIntegrator "/>

测试时间

现在,当持久化一个 Post 实体时:

Post post1 = new Post();
post1.setId(1L);
post1.setTitle(
"The High-Performance Java Persistence book is to be released!"
);

entityManager.persist(post1);

Hibernate 将执行以下 SQL INSERT 语句:

Query:["INSERT INTO old_post (id, title, version) VALUES (?, ?, ?)"], Params:[(1, The High-Performance Java Persistence book is to be released!, 0)]

Query:["insert into post (created_on, title, version, id) values (?, ?, ?, ?)"], Params:[(2018-12-12, The High-Performance Java Persistence book is to be released!, 0, 1)]

当执行另一个更新现有 Post 实体并创建新的 Post 实体的事务时:

Post post1 = entityManager.find(Post.class, 1L);
post1.setTitle(post1.getTitle().replace("to be ", ""));

Post post2 = new Post();
post2.setId(2L);
post2.setTitle(
"The High-Performance Java Persistence book is awesome!"
);

entityManager.persist(post2);

Hibernate 也将所有操作复制到 old_post 表:

 Query:["select tablerepli0_.id as id1_1_0_, tablerepli0_.created_on as created_2_1_0_, tablerepli0_.title as title3_1_0_, tablerepli0_.version as version4_1_0_ from post tablerepli0_ where tablerepli0_.id=?"], Params:[(1)]

Query:["INSERT INTO old_post (id, title, version) VALUES (?, ?, ?)"], Params:[(2, The High-Performance Java Persistence book is awesome!, 0)]

Query:["insert into post (created_on, title, version, id) values (?, ?, ?, ?)"], Params:[(2018-12-12, The High-Performance Java Persistence book is awesome!, 0, 2)]

Query:["update post set created_on=?, title=?, version=? where id=? and version=?"], Params:[(2018-12-12, The High-Performance Java Persistence book is released!, 1, 1, 0)]

Query:["UPDATE old_post SET title = ?, version = ? WHERE id = ?"], Params:[(The High-Performance Java Persistence book is released!, 1, 1)]

删除 Post 实体时:

Post post1 = entityManager.getReference(Post.class, 1L);
entityManager.remove(post1);

old_post 记录也被删除:

Query:["DELETE FROM old_post WHERE id = ?"], Params:[(1)]
Query:["delete from post where id=? and version=?"], Params:[(1, 1)]

代码可用 GitHub .

关于java - 如何使用 JPA 和 Hibernate 复制 INSERT/UPDATE/DELETE 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53723204/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com