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.
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
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.
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 |
Tout d'abord, traitons du modèle de données de temps de transaction tout en abordant l'utilisation de base de Reladomo.
Puisque le but est de confirmer la fonction de Reladomo, nous avons préparé un modèle de domaine simple qui semble possible.
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
.
À partir du fichier XML que vous venez de définir, vous pouvez générer un fichier Java pour l'objet correspondant.
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é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».
generatedDir
gen-reladomo
est exécutée.nonGeneratedDir
gen-reladomo
est exécutée, elle ne sera pas recréée si la classe à générer existe déjà.generatedDir
. Dans l'état initial, seul le constructeur minimum requis est décrit et la mise en œuvre de la logique métier, etc. est effectuée ici.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.
La classe abstraite générée ici contient la plupart du code nécessaire pour effectuer des opérations CRUD sur une entité.
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é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>
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.
CRUD (Create)
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
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
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.
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);
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.
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;
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.
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
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.
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
de la classe ʻAccount
générée par Reladomo, la table correspondante sera mise à jour afin que le montant du dépôt de 20000 yens soit ajouté au solde.processing_date_to
et processing_date_to ʻis
9999-12-01 23: 59: 00` est le dernier historique.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.
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.
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