複数のデータソースを使用した Hibernate Envers と Spring Boot

ハイバネート・エンバース このプロジェクトは、永続クラスの監査を容易にすることを目的としています。これにより、エンティティの監査に伴う煩雑な作業が完全に解消されます。
以下のセクションでは、カスタム リビジョン エンティティを使用して Spring Boot で Envers を構成するための高レベルの手順の概要を説明します。 複数のデータ ソースが関係する場合に Envers を構成する方法を示します。
Envers の使用を開始する
Maven を使用している場合は、pom.xml に Envers の以下の設定を追加します。
org.hibernate hibernate-envers
カスタム リビジョン エンティティの作成
多くのシナリオでは、デフォルトのリビジョン エンティティ フィールドでは十分ではないため、カスタム リビジョン エンティティが必要になります。 以下は、カスタム リビジョン エンティティの作成例です。
この例では ID にシーケンスを使用していますが、ID の生成にはさまざまな戦略を使用できます。
@RevisionNumber と @RevisionEntity に注意してください。これらは、Envers がリビジョン エンティティを作成し、データベースに値を保持するために使用します。
package com.example.service.audit.entity @Table(name = "app_user_rev_entity", schema = "application") @Entity @RevisionEntity(UserRevisionListener.class) public class UserRevEntity implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_rev_generator") @SequenceGenerator(name = "user_rev_generator", allocationSize = 10,sequenceName = "app_userrev_seq") @RevisionNumber private int id; @RevisionTimestamp @Temporal(TemporalType.TIMESTAMP) private Date date; @Column(name = "user_name") private String userName; @Column(name = "user_id") private Long userId; // Getters, setters, equals, hashcode ….
UserRevisionListener は、UserRevEntity のすべてのカスタム属性が設定されるクラスです。
以下の例では、Spring Boot プリンシパル ユーザーを使用してユーザー名を取得しています。 同様に、他の属性も設定できます。 このクラスは、Hibernate Envers の RevisionListener インターフェイスを実装する必要があります。
package com.example.service.audit.entity public class UserRevisionListener implements RevisionListener { /** * @see org.hibernate.envers.RevisionListener#newRevision(java.lang.Object) */ @Override public void newRevision(Object userRevision) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); User authenticatedUser = (User) authentication.getPrincipal(); UserRevEntity userRevEntity = (UserRevEntity) userRevision; userRevEntity.setUserName(authenticatedUser.getUsername()); userRevEntity.setDate(Calendar.getInstance(TimeZone.getTimeZone("UTC")).getTime()); }
application.properties を構成する
以下は、Hibernate Envers に固有の構成の一部です。 構成プロパティの詳細については、こちらをご覧ください。 こちら.
spring.jpa.properties.org.hibernate.envers.revision_type_field_name=revision_type spring.jpa.properties.org.hibernate.envers.revision_field_name=revision_id spring.jpa.properties.org.hibernate.envers.modified_flag_suffix=_mod spring.jpa.properties.org.hibernate.envers.audit_strategy=org.hibernate.envers.strategy.ValidityAuditStrategy
Hibernateにカスタムリビジョンエンティティやその他の監査テーブルを自動的に作成させたい場合は、spring.jpa.hibernate.ddl-auto=updateを使用できますが、これは本番環境ではお勧めしません。本番環境では、テーブルを自分で作成するのが最善です。
次のセクションは監査戦略についてです。 デフォルトでも十分ですが、ValidityAuditStrategy はより高度な戦略です。
監査対象のエンティティを構成する
以下は、Entity クラスを監査する方法の例です。 必要なのは、 @Audited アノテーションをクラス レベルで追加するか (すべての属性を監査する必要がある場合)、またはアノテーションを個別の属性レベルとして追加することだけです。
@Entity @Table(name = "app_user", schema = "application") public class UserEntity implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_generator") @SequenceGenerator(name = "user_generator", allocationSize = 1, sequenceName = "application.app_userid_seq") @Column(name = "user_id") private Long userId; @NotNull @Column(name = "first_name") @Audited private String firstName;
複数のデータソースを使用して Envers を構成する
多くのアプリケーションでは、異なるデータを異なるスキーマや場合によっては異なるデータベースに保存する必要があるため、複数のデータ ソースが存在します。 以下のセクションでは、複数のデータ ソースを使用して Envers を構成する手順の概要を説明します。
application.properties ファイルで複数のデータソースを構成します。
application.spring.datasource.url = jdbc:postgresql://xxxx application.spring.datasource.username = xxx application.spring.datasource.password=xxx application.spring.datasource.testWhileIdle = true application.spring.datasource.validationQuery = SELECT 1 application.spring.datasource.schema=application application.spring.datasource.driver-class-name=org.postgresql.Driver example.spring.datasource.url = jdbc:postgresql://xxx example.spring.datasource.username = xxx example.spring.datasource.password=xxx example.spring.datasource.testWhileIdle = true example.spring.datasource.validationQuery = SELECT 1 example.spring.datasource.schema=public example.spring.datasource.driver-class-name=org.postgresql.Driver
Spring Boot が使用するデータ ソースを識別して読み込むために必要な構成は次のとおりです。
上記のどちらの構成においても、覚えておくべき重要な点は、Envers Custom Revision Entity クラスが実装されているパッケージを追加することです。この場合、Envers によるエンティティ スキャン用のデータソース構成ファイルの両方に「com.example.service.audit.entity」を追加します。
構成ファイルの XNUMX つにパッケージを追加しなかった場合、監査対象のエンティティを永続化しようとすると、突然以下のエラーが表示され始める可能性があります。 コードは変更されていない可能性がありますが、障害が発生し始める可能性があります。
これは、起動時に最初にデータ ソースがロードされる ClassLoader によって異なります。 エンティティ スキャン パッケージが欠落しているデータ ソースが最後にロードされた場合、以下のエラーが表示されます。
これにより、問題のデバッグに多くの時間が無駄になり、Hibernate Envers で使用される汎用シーケンスである欠落した hibernate_sequence を作成するという誤解を招く可能性があります。
Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:106) at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:79) at org.hibernate.id.enhanced.SequenceStructure$1.getNextValue(SequenceStructure.java:96) at org.hibernate.id.enhanced.NoopOptimizer.generate(NoopOptimizer.java:40) at org.hibernate.id.enhanced.SequenceStyleGenerator.generate(SequenceStyleGenerator.java:412) at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:101) at org.hibernate.jpa.event.internal.core.JpaSaveEventListener.saveWithGeneratedId(JpaSaveEventListener.java:56) at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192) at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38) at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177) at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32) at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73) at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:679) at org.hibernate.internal.SessionImpl.save(SessionImpl.java:671) at org.hibernate.envers.internal.revisioninfo.DefaultRevisionInfoGenerator.saveRevisionData(DefaultRevisionInfoGenerator.java:75) at org.hibernate.envers.internal.synchronization.AuditProcess.getCurrentRevisionData(AuditProcess.java:119) at org.hibernate.envers.internal.synchronization.AuditProcess.executeInSession(AuditProcess.java:96) ... 141 common frames omitted Caused by: org.postgresql.util.PSQLException: ERROR: relation "hibernate_sequence" does not exist Position: 17
結論
Hibernate Envers は、Hibernate によって提供される成熟した監査モジュールです。 高度に構成可能であり、監査フレームワークを構築する労力を節約します。
ただし、複数のデータ ソースを使用する場合は、両方のデータ ソースでエンティティ スキャン パッケージを構成することを忘れないでください。そうしないと、特に作業中のコードが突然失敗し始めた場合に、誤解を招き、問題のデバッグに多くの時間を費やすことになります。
私たちの投稿をお読みくださいフロントエンドブラウザのデバッグブラウザの問題をトラブルシューティングするためのツールとコツについては、こちらをご覧ください。











