[Java] Simplifiez la mise en œuvre de la gestion de l'historique des données avec Reladomo

Qu'est-ce que Reladomo?

reladomo-200.png Reladomo est un framework Java ORM publié par Goldman Sachs en tant que OSS. Je l'aime car il a une caractéristique qui facilite la gestion de l'historique des modifications dans le SGBDR.

Dans Reladomo, Java et DDL peuvent être générés en définissant l'entité en XML. En exploitant l'API générée, vous pouvez effectuer des opérations CRUD sur les tables correspondantes.

Que faire dans cet article

Cette fois, je vais aborder brièvement les opérations de base de Reladomo, les types de modèles de données, etc.

À ce moment-là, en ce qui concerne le modèle de données bitemporelles (décrit plus loin), il est plus facile à comprendre en regardant le comportement réel. Je voudrais jeter un oeil à l'aide d'un exemple d'API REST combiné avec Spring Boot. https://github.com/amtkxa/spring-boot-reladomo

À propos de la gestion de l'historique des données par Reladomo

Afin de pouvoir suivre l'historique des modifications des données, il est nécessaire de sauvegarder les données historiques, Le temps qui a un sens doit être économisé ensemble.

Transaction Time, Vaild Time

Reladomo permet de gérer facilement deux fois l'historique des modifications des données.

Modèle de données

Les quatre modèles de données suivants peuvent être pris en compte selon que l'heure de transaction et l'heure de validité sont utilisées ou non. Reladomo vous donne également la flexibilité de choisir un modèle de données par entité.

Modèle de données La description
Modèle de données instantané Aucune dimension temporelle n'est prise en charge (pas de gestion de l'historique)
Modèle de données de temps de transaction Seul le temps de transaction pris en charge
Modèle de données de temps valide Seul le temps valide pris en charge
Modèle de données bitemporel Prend en charge à la fois Vaild Time et Transaction Time

En fait, utilisez-le (modèle de données de temps de transaction)

Tout d'abord, traitons du modèle de données de temps de transaction tout en abordant l'utilisation de base de Reladomo.

Préparer un modèle de domaine simple

Puisque le but est de confirmer la fonction de Reladomo, nous avons préparé un modèle de domaine simple qui semble possible. 50054750-b2e45800-0188-11e9-8aeb-fad5262e78d8.png

Créer un fichier XML pour l'objet Reladomo

Commencez par créer un fichier XML qui définit les objets qui correspondent aux tables de votre base de données.

Account.xml


<MithraObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              objectType="transactional"
              xsi:noNamespaceSchemaLocation="../config/mithraobject.xsd">
    <PackageName>com.amtkxa.springbootreladomosimple.domain.entity</PackageName>
    <ClassName>Account</ClassName>
    <DefaultTable>ACCOUNT</DefaultTable>

    <AsOfAttribute name="processingDate" fromColumnName="PROCESSING_DATE_FROM" toColumnName="PROCESSING_DATE_TO"
                   toIsInclusive="false"
                   isProcessingDate="true"
                   infinityDate="[com.gs.fw.common.mithra.util.DefaultInfinityTimestamp.getDefaultInfinity()]"
                   defaultIfNotSpecified="[com.gs.fw.common.mithra.util.DefaultInfinityTimestamp.getDefaultInfinity()]"
    />
    <Attribute name="accountId" javaType="int" columnName="ACCOUNT_ID" primaryKey="true"
               primaryKeyGeneratorStrategy="SimulatedSequence">
        <SimulatedSequence sequenceName="Account"
                           sequenceObjectFactoryName="com.amtkxa.springbootreladomosimple.infrastructure.util.ObjectSequenceObjectFactory"
                           hasSourceAttribute="false"
                           batchSize="1"
                           initialValue="1"
                           incrementSize="1"/>
    </Attribute>
    <Attribute name="customerId" javaType="int" columnName="CUSTOMER_ID" nullable="false"/>
    <Attribute name="balance" javaType="double" columnName="BALANCE"/>
</MithraObject>

Une brève description de chaque attribut est la suivante.

Element La description
PackageName Le package auquel appartient l'objet généré.
ClassName Le nom de classe de l'objet.
DefaultTable La table à laquelle correspond l'objet.
Attribute Attributs d'objets. Correspond aux colonnes de la table définies dans DefaultTable.
AsOfAttribute Elle correspond à la colonne de gestion de l'historique, et la période est représentée par deux colonnes de à à.
SimulatedSequence Valeur de séquence numérotée automatiquement au moment de INSERT.

Vous pouvez également en savoir plus sur ce que vous avez défini ici en regardant mithraobject.xsd.

Génération de fichiers Java

À partir du fichier XML que vous venez de définir, vous pouvez générer un fichier Java pour l'objet correspondant.

Créer une MithraClassList

MithraClassList.xml


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Mithra xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="../config/mithraobject.xsd">
    <MithraObjectResource name="ObjectSequence"/>
    <MithraObjectResource name="Customer"/>
    <MithraObjectResource name="Account"/>
    <MithraObjectResource name="Transaction"/>
</Mithra>

définition de tâche gen-reladomo

Définissez la tâche gen-reladomo dans pom.xml. Cette tâche Ant utilise le MithraGenerator pour générer un fichier Java basé sur le fichierMithraClassList.xml.

pom.xml


<tasks>
    <property name="plugin_classpath" refid="maven.plugin.classpath"/>
    <taskdef name="gen-reladomo" classpath="plugin_classpath"
                classname="com.gs.fw.common.mithra.generator.MithraGenerator"/>
    <gen-reladomo
            xml="${project.basedir}/src/main/resources/reladomo/model/MithraClassList.xml"
            generateGscListMethod="true"
            generatedDir="${project.build.directory}/generated-sources/reladomo"
            nonGeneratedDir="${project.basedir}/src/main/java"
    />
</tasks>

Ici, deux destinations de sortie sont définies par «generatedDir» et «nonGeneratedDir».

exécution de la tâche gen-reladomo

La tâche gen-reladomo générera un fichier Java, par exemple en exécutant mvn clean install. generatedDir génère une classe abstraite qui est recréée à chaque fois pour suivre les modifications XML, et nonGeneratedDir crée une classe concrète dans laquelle l'utilisateur ajoute sa propre logique métier. Les classes et dépendances générées sont les suivantes.

FireShot Capture 21 - spring-boot-relado_ - https___app.genmymodel.com_edit__alkjIAXvEemAl9N48If50Q#.png

La classe abstraite générée ici contient la plupart du code nécessaire pour effectuer des opérations CRUD sur une entité.

Génération DDL

Vous pouvez générer du DDL pour les bases de données prises en charge par Reladomo. DDL semble prendre en charge les tables, les index et les clés externes.

définition de la tâche gen-reladomo-db

Définissez la tâche gen-reladomo-db dans pom.xml. Cette tâche Ant s'appuie sur le fichier MithraClassList.xml et utilise MithraDbDefinitionGenerator pour générer un DDL.

pom.xml


<tasks>
    <property name="plugin_classpath" refid="maven.plugin.classpath"/>
    <taskdef name="gen-reladomo-db" classpath="plugin_classpath"
                classname="com.gs.fw.common.mithra.generator.dbgenerator.MithraDbDefinitionGenerator"/>
    <gen-reladomo-db
            xml="${project.basedir}/src/main/resources/reladomo/model/MithraClassList.xml"
            generatedDir="${project.build.directory}/generated-resources/db"
            databaseType="postgres"/>
</tasks>

exécution de la tâche gen-reladomo-db

La tâche gen-reladomo-db générera un DDL, par exemple en exécutant mvn clean install. Le DDL généré lorsque postgres était défini sur databaseType avait le contenu suivant.

target/generated-resources/db/ACCOUNT.ddl


drop table if exists ACCOUNT;

create table ACCOUNT
(
    ACCOUNT_ID int not null,
    CUSTOMER_ID int not null,
    BALANCE float8,
    PROCESSING_DATE_FROM timestamp not null,
    PROCESSING_DATE_TO timestamp not null
);

target/generated-resources/db/ACCOUNT.idx


alter table ACCOUNT add constraint ACCOUNT_PK primary key (ACCOUNT_ID, PROCESSING_DATE_TO);

drop index if exists ACCOUNT_IDX0;
create index ACCOUNT_IDX0 on ACCOUNT(CUSTOMER_ID, PROCESSING_DATE_TO);

Lors de la gestion de l'historique à l'aide de Reladomo, il semble que le DDL de clé étrangère ne soit pas généré à partir du XML correspondant. À propos, il semble que le DDL généré ici ne soit pas utilisé tel quel, mais qu'il soit censé être personnalisé en fonction de cela.

The DDLs generated by Reladomo are not meant to be used as is. They are merely meant to be a starting point for further customization. There are two common reasons to customize the generated DDLs. One is to add database specific clauses for specifying table spaces, schemas etc. Another is to add additional indices based on usage patterns seen in the application. Guided Tour Of Reladomo - 2.3. Database DDL Generation

Je suis reconnaissant pour la fonction de génération DDL.

Fonctionnement du Reladomo CRUD

CRUD (Create)

Enregistrement d'un seul enregistrement

Ajoutez le constructeur suivant à la classe concrète générée par Reladomo.

Account.java


public Account(int customerId, double balance) {
    this(com.gs.fw.common.mithra.util.DefaultInfinityTimestamp.getDefaultInfinity());
    this.setCustomerId(customerId);
    this.setBalance(balance);
}

Ensuite, essayez d'exécuter le code ci-dessous.

MithraManagerProvider.getMithraManager().executeTransactionalCommand((tx) -> {
    Account account = new Account(1, 100);
    account.insert();
    return null;
});

Ensuite, l'enregistrement a été enregistré dans la table ACCOUNT du DB de destination de connexion.

testdb=> select * from account;
 account_id | customer_id | balance |  processing_date_from  | processing_date_to
------------+-------------+---------+------------------------+---------------------
          1 |           1 |     100 | 2018-12-23 14:42:14.61 | 9999-12-01 23:59:00

Numérotation des valeurs de séquence

Puisque la valeur de séquence numérotée est définie sur ʻaccount_id` pour laquelle aucune valeur n'est définie, elle y est complétée. Si vous entrez ce qui suit dans la colonne correspondante de Account.xml définie précédemment, vous pourrez numéroter la valeur de séquence.

Account.xml


    <Attribute name="accountId" javaType="int" columnName="ACCOUNT_ID" primaryKey="true"
               primaryKeyGeneratorStrategy="SimulatedSequence">
        <SimulatedSequence sequenceName="Account"
                           sequenceObjectFactoryName="com.amtkxa.springbootreladomosimple.infrastructure.util.ObjectSequenceObjectFactory"
                           hasSourceAttribute="false"
                           batchSize="1"
                           initialValue="1"
                           incrementSize="1"/>
    </Attribute>

Le ʻObjectSequenceObjectFactory spécifié dans ʻAccount.xml est créé séparément.

ObjectSequenceObjectFactory.java


public class ObjectSequenceObjectFactory implements MithraSequenceObjectFactory {
  public MithraSequence getMithraSequenceObject(String sequenceName, Object sourceAttribute, int initialValue) {
    ObjectSequence objectSequence = ObjectSequenceFinder.findByPrimaryKey(sequenceName);
    if (objectSequence == null) {
      objectSequence = new ObjectSequence();
      objectSequence.setSimulatedSequenceName(sequenceName);
      objectSequence.setNextValue(initialValue);
      objectSequence.insert();
    }
    return objectSequence;
  }
}

Les valeurs à numéroter sont gérées dans la table OBJECT_SEQUENCE, qui définit également les métadonnées en XML.

ObjectSequence.xml


<MithraObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              objectType="transactional"
              xsi:noNamespaceSchemaLocation="../config/mithraobject.xsd">

    <PackageName>com.amtkxa.springbootreladomosimple.domain.entity</PackageName>
    <ClassName>ObjectSequence</ClassName>
    <DefaultTable>OBJECT_SEQUENCE</DefaultTable>

    <Attribute name="simulatedSequenceName" javaType="String" columnName="SEQUENCE_NAME" primaryKey="true" maxLength="64"/>
    <Attribute name="nextValue" javaType="long" columnName="NEXT_VALUE"/>

</MithraObject>
testdb=> select * from object_sequence;
 sequence_name | next_value
---------------+------------
 Account       |          2

Enregistrement de plusieurs enregistrements

Vous pouvez également enregistrer plusieurs enregistrements en utilisant ʻAccountList` généré par Reladomo.

MithraManagerProvider.getMithraManager().executeTransactionalCommand((tx) -> {
    AccountList accountList = new AccountList();
    accountList.add(new Account(2, 200));
    accountList.add(new Account(3, 300));
    accountList.insertAll();
    return null;
});

Lorsque j'ai exécuté ce code, plusieurs enregistrements ont été enregistrés.

testdb=> select * from account where customer_id in (2, 3);
 account_id | customer_id | balance |  processing_date_from  | processing_date_to
------------+-------------+---------+------------------------+---------------------
          2 |           2 |     200 | 2018-12-23 15:10:37.92 | 9999-12-01 23:59:00
          3 |           3 |     300 | 2018-12-23 15:10:37.92 | 9999-12-01 23:59:00

CRUD (Read)

Le processus de recherche utilise la classe Finder générée par Reladomo.

Paramètres des conditions de recherche

Vous pouvez créer une instance de la classe ʻOperation en utilisant la classe Finder. La classe ʻOperation peut être définie sur la clause WHERE de la requête émise.

Laisse moi te donner quelques exemples.

// where NAME = 'tanaka'
Operation op1 = CustomerFinder.name().eq("tanaka");
// where NAME <> 'tanaka'
Operation op2 = CustomerFinder.name().notEq("tanaka");
// where NAME like 'tanaka%'
Operation op3 = CustomerFinder.name().startsWith("tanaka");
// where NAME like '%taro'
Operation op4 = CustomerFinder.name().endsWith("taro");
// where NAME like '%tanaka%'
Operation op5 = CustomerFinder.name().wildCardEq("*tanaka*");
// where CUSTOMER_ID < 3
Operation op6 = CustomerFinder.customerId().lessThan(3);

En plus de ceux listés ici, ʻisNull et contient` sont disponibles. Vous pouvez également enchaîner les «opérations» comme suit:

// where NAME like '%tanaka%' and CUSTOMER_ID < 3
Operation op = op5.and(op6);

1 recherche

Vous pouvez obtenir un seul enregistrement en utilisant findOne de la classe Finder.

// select t0.ACCOUNT_ID,t0.CUSTOMER_ID,t0.BALANCE,t0.PROCESSING_DATE_FROM,t0.PROCESSING_DATE_TO from ACCOUNT t0 
// where  t0.ACCOUNT_ID = 1 and t0.PROCESSING_DATE_TO = '9999-12-01 23:59:00.000'
Account account = AccountFinder.findOne(AccountFinder.accountId().eq(1));

La condition de la requête effectivement émise est t0.PROCESSING_DATE_TO = '9999-12-01 23: 59: 00.000', qui fait référence à l'enregistrement correspondant au dernier historique.

Recherche multiple

Si vous utilisez findMany de la classe Finder, vous pouvez obtenir plusieurs enregistrements dans List.

// select t0.CUSTOMER_ID,t0.NAME,t0.COUNTRY,t0.PROCESSING_DATE_FROM,t0.PROCESSING_DATE_TO from CUSTOMER t0
// where  t0.NAME like 'tanaka%' and t0.PROCESSING_DATE_TO = '9999-12-01 23:59:00.000'
CustomerList customerList = CustomerFinder.findMany(CustomerFinder.name().startsWith("tanaka"));

CRUD (Update)

Si vous apportez des modifications à un objet récupéré à l'aide de la classe Finder, les modifications seront également reflétées dans la table DB. J'ai préparé les données suivantes pour vérifier le comportement.

testdb=> select * from customer where customer_id = 7;
 customer_id |  name   | country |  processing_date_from  | processing_date_to
-------------+---------+---------+------------------------+---------------------
           7 | Pikachu | Japan   | 2018-12-23 19:36:07.06 | 9999-12-01 23:59:00

Pikachu deviendra Raichu, supposons donc que le code suivant soit exécuté pour effectuer les modifications.

MithraManagerProvider.getMithraManager().executeTransactionalCommand((tx) -> {
    Customer customer = CustomerFinder.findOne(CustomerFinder.customerId().eq(7));
    customer.setName("Raichu");
    return null;
});

Le résultat de l'exécution est le suivant.

testdb=> select * from customer where customer_id = 7;
 customer_id |  name   | country |  processing_date_from  |   processing_date_to
-------------+---------+---------+------------------------+------------------------
           7 | Pikachu | Japan   | 2018-12-23 19:36:07.06 | 2018-12-23 19:46:13.91
           7 | Raichu  | Japan   | 2018-12-23 19:46:13.91 | 9999-12-01 23:59:00

La requête effectivement émise est la suivante.

--Obtenez les dernières données d'historique
select t0.CUSTOMER_ID,t0.NAME,t0.COUNTRY,t0.PROCESSING_DATE_FROM,t0.PROCESSING_DATE_TO from CUSTOMER t0 
where  t0.CUSTOMER_ID = 7 and t0.PROCESSING_DATE_TO = '9999-12-01 23:59:00.000' FOR SHARE OF t0;

--Mettre à jour la période de validité des dernières données d'historique
update CUSTOMER set PROCESSING_DATE_TO = '2018-12-23 19:46:13.910'  
where CUSTOMER_ID = 7 AND PROCESSING_DATE_TO = '9999-12-01 23:59:00.000';

--Enregistrez les données modifiées comme dernier historique
insert into CUSTOMER(CUSTOMER_ID,NAME,COUNTRY,PROCESSING_DATE_FROM,PROCESSING_DATE_TO) 
values (7,'Raichu','Japan','2018-12-23 19:46:13.910','9999-12-01 23:59:00.000');

CRUD (Delete)

Vous pouvez également le refléter dans le tableau en supprimant l'objet obtenu à l'aide de la classe Finder. Dans ce cas, le comportement est différent pour delete (), terminate () et purge (), alors déplaçons-le facilement.

delete()

delete () peut être utilisé pour les objets dont Reladomo ne gère pas l'historique (déterminé par si XML a ʻAsOfAttribute`). Cela supprime physiquement l'enregistrement de la table.

MithraManagerProvider.getMithraManager().executeTransactionalCommand((tx) -> {
    Transaction transaction = TransactionFinder.findOne(TransactionFinder.transactionId().eq(4));
    transaction.delete();
    return null;
});

La requête réelle exécutée est la suivante.

select t0.LOG_ID,t0.ACCOUNT_ID,t0.TRANSACTION_TYPE,t0.AMOUNT,t0.TRANSACTION_DATE from TRANSACTION t0 
where  t0.LOG_ID = 4 FOR SHARE OF t0;

delete from TRANSACTION where LOG_ID = 4;

terminate()

terminate () termine l'historique des objets gérés par Reladomo. (Enregistrer comme l'histoire demeure) Les données suivantes ont été préparées pour vérifier le comportement.

testdb=> select * from customer where customer_id = 7;
 customer_id |  name   | country |  processing_date_from  |   processing_date_to
-------------+---------+---------+------------------------+------------------------
           7 | Pikachu | Japan   | 2018-12-23 19:36:07.06 | 2018-12-23 19:46:13.91
           7 | Raichu  | Japan   | 2018-12-23 19:46:13.91 | 9999-12-01 23:59:00

En réponse, exécutez ce code.

MithraManagerProvider.getMithraManager().executeTransactionalCommand((tx) -> {
    Customer customer = CustomerFinder.findOne(CustomerFinder.customerId().eq(7));
    customer.terminate();
    return null;
});

Ensuite, la pièce enregistrée comme 9999-12-01 23: 59: 00 dans processing_date_to sera mise à jour.

testdb=> select * from customer where customer_id = 7;
 customer_id |  name   | country |  processing_date_from  |   processing_date_to
-------------+---------+---------+------------------------+------------------------
           7 | Pikachu | Japan   | 2018-12-23 19:36:07.06 | 2018-12-23 19:46:13.91
           7 | Raichu  | Japan   | 2018-12-23 19:46:13.91 | 2018-12-23 22:10:36.68

La requête réelle exécutée est la suivante.

select t0.CUSTOMER_ID,t0.NAME,t0.COUNTRY,t0.PROCESSING_DATE_FROM,t0.PROCESSING_DATE_TO from CUSTOMER t0 
where  t0.CUSTOMER_ID = 7 and t0.PROCESSING_DATE_TO = '9999-12-01 23:59:00.000' FOR SHARE OF t0;

update CUSTOMER set PROCESSING_DATE_TO = '2018-12-23 22:10:36.680'  
where CUSTOMER_ID = 7 AND PROCESSING_DATE_TO = '9999-12-01 23:59:00.000';

purge()

purge () supprime l'historique de l'objet géré par Reladomo.

MithraManagerProvider.getMithraManager().executeTransactionalCommand((tx) -> {
    Customer customer = CustomerFinder.findOne(CustomerFinder.customerId().eq(6));
    customer.purge();
    return null;
});

La requête réelle exécutée est la suivante.

select t0.CUSTOMER_ID,t0.NAME,t0.COUNTRY,t0.PROCESSING_DATE_FROM,t0.PROCESSING_DATE_TO from CUSTOMER t0
where  t0.CUSTOMER_ID = 6 and t0.PROCESSING_DATE_TO = '9999-12-01 23:59:00.000' FOR SHARE OF t0;

delete from CUSTOMER where CUSTOMER_ID = 6;

Utiliser réellement (modèle de données bitemporel)

Utilisez un exemple d'API REST qui fonctionne avec un modèle de données bitemporel en combinaison avec Spring Boot. https://github.com/amtkxa/spring-boot-reladomo

Le temps de transaction et le temps Vaild traités dans le modèle de données bitemporel ont souvent le même timing, mais ici nous allons tracer le cas où vous pouvez voir le mérite de gérer les deux en même temps.

J'ai mentionné l'utilisation de base de Reladomo plus tôt, je vais donc présenter les parties qui ne sont pas beaucoup couvertes.

1er janvier - Ouvrez un compte avec un dépôt initial de 10000 yens

Le tout premier record historique a été enregistré.

sampledb=> select * from account where account_id = 10;
 account_id | customer_id | balance | business_date_from  |  business_date_to   |  processing_date_from  | processing_date_to
------------+-------------+---------+---------------------+---------------------+------------------------+---------------------
         12 |           1 |   10000 | 2019-01-01 00:00:00 | 9999-12-01 23:59:00 | 2018-12-22 16:17:17.49 | 9999-12-01 23:59:00

Dépôt de 17 à 5000 yens

Supposons que vous ne puissiez pas effectuer de dépôt en raison de problèmes. Par conséquent, il n'y a aucun changement dans le contenu de la table.

20 janvier 20000 yens de dépôt

L'histoire a été coupée en raison du dépôt de 20000 yens.

sampledb=> select * from account where account_id = 12 order by 4, 6;
 account_id | customer_id | balance | business_date_from  |  business_date_to   |  processing_date_from  |   processing_date_to
------------+-------------+---------+---------------------+---------------------+------------------------+------------------------
         12 |           1 |   10000 | 2019-01-01 00:00:00 | 9999-12-01 23:59:00 | 2018-12-22 16:33:09.54 | 2018-12-22 16:38:27.48
         12 |           1 |   10000 | 2019-01-01 00:00:00 | 2019-01-20 00:00:00 | 2018-12-22 16:38:27.48 | 9999-12-01 23:59:00
         12 |           1 |   30000 | 2019-01-20 00:00:00 | 9999-12-01 23:59:00 | 2018-12-22 16:38:27.48 | 9999-12-01 23:59:00

25 janvier - Fixe de 5000 yens qui ne pouvaient pas être déposés

Supposons que le montant d'argent déposé le 17 janvier ait été modifié le 25 janvier. Dans ce cas, si vous utilisez ʻincrementBalance () `pour mettre à jour l'objet acquis en spécifiant le 17 janvier pour business_date, la table correspondante sera mise à jour avec le contenu suivant.

sampledb=> select * from account where account_id = 12 order by 6, 4;
 account_id | customer_id | balance | business_date_from  |  business_date_to   |  processing_date_from  |   processing_date_to
------------+-------------+---------+---------------------+---------------------+------------------------+------------------------
         12 |           1 |   10000 | 2019-01-01 00:00:00 | 9999-12-01 23:59:00 | 2018-12-22 16:33:09.54 | 2018-12-22 16:38:27.48
         12 |           1 |   10000 | 2019-01-01 00:00:00 | 2019-01-20 00:00:00 | 2018-12-22 16:38:27.48 | 2018-12-22 16:45:31.94
         12 |           1 |   30000 | 2019-01-20 00:00:00 | 9999-12-01 23:59:00 | 2018-12-22 16:38:27.48 | 2018-12-22 16:45:31.94
         12 |           1 |   10000 | 2019-01-01 00:00:00 | 2019-01-17 00:00:00 | 2018-12-22 16:45:31.94 | 9999-12-01 23:59:00
         12 |           1 |   15000 | 2019-01-17 00:00:00 | 2019-01-20 00:00:00 | 2018-12-22 16:45:31.94 | 9999-12-01 23:59:00
         12 |           1 |   35000 | 2019-01-20 00:00:00 | 9999-12-01 23:59:00 | 2018-12-22 16:45:31.94 | 9999-12-01 23:59:00

Nous avons pu confirmer que le solde des données historiques à modifier pouvait être mis à jour tout en conservant les données historiques avant modification.

finalement

Après avoir utilisé Reladomo, j'ai réalisé que la gestion de l'historique des données pouvait être facilement réalisée. Surtout dans les cas où vous souhaitez suivre l'historique des modifications ultérieurement pour un audit, etc., il semble que vous puissiez vous attendre à une amélioration de l'efficacité du développement. Cela peut être utile dans de nombreuses situations lors du développement avec le langage JVM.

En outre, sélection de la stratégie de cache pour chaque entité, chargeur de matrices multi-threads (MTLoader), etc. Je suis particulièrement intéressé par les fonctionnalités fournies par Reladomo pour des performances élevées, donc J'aimerais enquêter là-dessus également à un autre moment.

Matériaux que j'ai utilisés comme référence

Quand j'ai cherché cette fois, j'ai senti qu'il y avait beaucoup de documents en anglais, mais tous étaient de haute qualité.

De plus, il existe des documents japonais très faciles à comprendre, ce qui était vraiment utile.

Recommended Posts

[Java] Simplifiez la mise en œuvre de la gestion de l'historique des données avec Reladomo
Calculer le score de similarité des chaînes de caractères avec JAVA
Histoire des annotations Java
CI l'architecture des applications Java / Kotlin avec ArchUnit
Surveillez l'état interne des programmes Java avec Kubernetes
Vérifiez le comportement de Java Intrinsic Locks avec bpftrace
L'histoire de la création de DTO, semblable à Dao avec Java, SQLite
Remplacez seulement une partie de l'hôte URL par java
Histoire de créer une application de gestion de tâches avec Swing, Java
[Java] Implémentation du réseau Faistel
Implémentation de XLPagerTabStrip avec TabBarController
Implémentation d'un analyseur de syntaxe mathématique par méthode d'analyse syntaxique descendante récursive (Java)
Le piège que l'implémentation par défaut de l'interface Java 8 apporte
Assurez-vous de comparer le résultat Java compareTo avec 0
Implémentation Java de tri-tree
Lisez les données de la base de données de nuages de points de la préfecture de Shizuoka avec Java et générez une photographie aérienne et une élévation PNG.
Lisez les données de Shizuoka Prefecture Point Cloud DB avec Java et essayez de détecter la hauteur de l'arbre.
Essayez HelloWorld avec la configuration minimale de Heroku Java spring-boot
[Détails] Implémentation d'applications grand public avec Kinesis Client Library for Java
Une histoire sur l'utilisation de l'API League Of Legends avec JAVA
Le point addictif lors de l'authentification de base avec Java URLConnection
Voir le comportement des mises à jour d'entités avec Spring Boot + Spring Data JPA
Écraser le téléchargement du fichier avec le même nom avec BOX SDK (java)
La version d'Elasticsearch que vous utilisez est-elle compatible avec Java 11?
[Java] Supprimer les éléments de la liste
Filtrer les fluctuations des données brutes
Suivez le lien avec Selenium (Java)
[Java] Zones de données d'exécution de JVM
Gestion des données des livres détenus (portefeuille)
L'origine des expressions Java lambda
Implémentation d'une fonction similaire en Java
Déclarez une méthode qui a une valeur de retour Java avec le type de données de valeur de retour
L'histoire de la création d'un lanceur de jeu avec une fonction de chargement automatique [Java]
Ceci et cela de la mise en œuvre du jugement en temps réel des dates en Java
Vérifiez l'enregistrement MX de l'adresse e-mail avec java et vérifiez le domaine
[Java] Récupère MimeType à partir du contenu du fichier avec Apathce Tika [Kotlin]
Implémentation de la méthode de clonage pour Java Record
Implémentation de DBlayer en Java (RDB, MySQL)
Obtenez le résultat de POST en Java
Devinez le cadre de persistance Java 2017 (3) Reladomo
Vérifiez le contenu du magasin de certificats Java
Vérifiez le contenu des paramètres avec le levier
Examiner l'utilisation de la mémoire des éléments Java
[Java] Obtenez le jour d'un jour spécifique
Mémo: [Java] Vérifiez le contenu du répertoire
[Swift 5] Implémentation de l'enregistrement des membres dans Firebase
Application Java CICS-Run - (3) Gestion de build avec Gradle
Comparer les éléments d'un tableau (Java)
[jour: 5] J'ai résumé les bases de Java
Quelles sont les fonctionnalités mises à jour de Java 13
Quelle est la structure des données d'ActionText?
Mesurez facilement la taille des objets Java
Application Java CICS-Run - (2) Gestion de build avec Maven
Retour sur les bases de Java
Sortie du livre "Introduction à Java"
À propos du traitement de BigDecimal (avec réflexion)
Présentation du test Java automatisé avec JUnit 5 + Gradle
L'histoire de l'écriture de Java dans Emacs
Mettre en forme le contenu de LocalDate avec DateTimeFormatter
[Java] Vérifiez le nombre d'occurrences de caractères