sql >> データベース >  >> RDS >> PostgreSQL

JPAとHibernateを使用してINSERT/UPDATE/DELETEステートメントを複製する方法

    データベーステーブル

    次の2つのテーブルがあると仮定します。

    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エンティティ

    old_post テーブルは新しい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イベントリスナー

    ここで、PostのINSERT、UPDATE、およびDELETE操作をインターセプトするために3つのイベントリスナーを登録する必要があります。 エンティティ。

    これは、次のイベントリスナーを介して実行できます。

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

    3つのイベントリスナーは、Hibernate Integratorを使用して登録できます。 :

    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) {
    
        }
    }
    

    そして、このカスタムIntegratorを使用するようにHibernateに指示します 、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は次のSQLINSERTステートメントを実行します:

    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)]
    

    1. Python-Oracleがカーソル出力パラメータを渡す

    2. Herokuでは移行できません

    3. mysqlデータベースに接続し、Androidコードを使用してデータを挿入するにはどうすればよいですか?

    4. テーブルのカスタムフィールドを格納するDBデザイン