Remarques sur les transactions dans la bibliothèque client Java dans la banque de données

Contexte:

Utilisation de la bibliothèque cliente Java (Google Cloud Client Library for Java) pour utiliser le magasin de données Il y a. J'ai étudié le fonctionnement de cette transaction dans le traitement multi-thread. Le document officiel avait l'explication de spécification suivante, donc je l'ai vérifié en exécutant le code.

Pour un ou plusieurs groupes d'entités communs, si plusieurs transactions tentent de modifier une entité en même temps, seule la première transaction qui valide le changement réussira et toutes les autres transactions échoueront. Devenir.

Nous avons également confirmé ce qui se passe lorsque le traitement via l'objet Transaction et le traitement via l'objet Datastore sont mélangés.

Documentation Documents sur les transactions

Ce que j'ai fait

Vérifiez ce qui se passe lorsque vous essayez de mettre à jour une entité à partir de plusieurs threads dans les trois cas suivants

Scénario 1

Obtenir une entité de Thread1 via Transaction et dormir -> Obtenir l'entité de Thread2 via Transaction et mise à jour -> Mise à jour via Transaction avec Thread1

Scénario 2

Obtenir une entité de Thread1 via Transaction et dormir -> Obtenir l'entité de Thread2 via Datastore et mettre à jour -> Mise à jour via Transaction avec Thread1

Scénario 3

Obtenir une entité de Thread1 via Datastore et dormir -> Obtenir l'entité de Thread2 via Transaction et mise à jour -> Mise à jour via Datastore avec Thread1

Conclusion

Dans le cas de transaction.update, mettez à jour après avoir confirmé si l'entité a changé depuis le moment de l'acquisition. L'exception est lorsque l'état de l'entité a changé. Peu importe que le processus de mise à jour se fasse via un objet de transaction ou un objet de banque de données.

Code de confirmation

Scénario 1

code


package jp.ne.opt.spinapp.runner;

import com.google.cloud.datastore.*;

public final class DatastoreTest {
    final static String NAME_SPACE = "dataflow";
    final static String LOCK_KIND = "lock";
    final static String LOCK_PROP_VALUE = "value";
    final static Datastore DATASTORE = DatastoreOptions.getDefaultInstance().getService();
    final static KeyFactory KEY_FACTORY = DATASTORE.newKeyFactory().setNamespace(NAME_SPACE).setKind(LOCK_KIND);
    final static Transaction TRANSACTION = DATASTORE.newTransaction();

    public static void main(final String[] args) throws InterruptedException {
        MultiThread1 mt1 = new MultiThread1();
        MultiThread2 mt2 = new MultiThread2();
        mt1.start();
        Thread.sleep(1000);
        mt2.start();
    }
}

class MultiThread1 extends Thread {
    public void run() {
        Entity lock = DatastoreTest.TRANSACTION.get(DatastoreTest.KEY_FACTORY.newKey("test"));
        System.out.println("got lock from 1: " + lock.getLong((DatastoreTest.LOCK_PROP_VALUE)));
        try {
            Thread.sleep(3000);
            System.out.println("sleep 1 ended");
            Entity entity = Entity.newBuilder(lock).set(DatastoreTest.LOCK_PROP_VALUE, 1).build();
            DatastoreTest.TRANSACTION.update(entity);
            DatastoreTest.TRANSACTION.commit();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (DatastoreTest.TRANSACTION.isActive()) {
                DatastoreTest.TRANSACTION.rollback();
            }
        }
        System.out.println("thread1 done.");
    }
}

class MultiThread2 extends Thread {
    public void run() {
        Entity lock = DatastoreTest.TRANSACTION.get(DatastoreTest.KEY_FACTORY.newKey("test"));
        System.out.println("got lock from 2: " + lock.getLong((DatastoreTest.LOCK_PROP_VALUE)));
        try {
            Entity entity = Entity.newBuilder(lock).set(DatastoreTest.LOCK_PROP_VALUE, 2).build();
            DatastoreTest.TRANSACTION.update(entity);
            DatastoreTest.TRANSACTION.commit();
        } finally {
            if (DatastoreTest.TRANSACTION.isActive()) {
                DatastoreTest.TRANSACTION.rollback();
            }
        }
        System.out.println("thread2 done.");
    }
}
got lock from 2: 0
got lock from 1: 0
thread2 done.
sleep 1 ended
[WARNING]
com.google.cloud.datastore.DatastoreException: transaction is no longer active

Après la validation de thread2, j'obtiens une erreur de transaction n'est plus active lors de la mise à jour sur thread1. La banque de données est mise à jour avec Thread2.

Scénario 2


class MultiThread1 extends Thread {
    public void run() {
        Entity lock = DatastoreTest.TRANSACTION.get(DatastoreTest.KEY_FACTORY.newKey("test"));
        System.out.println("got lock from 1: " + lock.getLong((DatastoreTest.LOCK_PROP_VALUE)));
        try {
            Thread.sleep(10000);
            System.out.println("sleep 1 ended");
            Entity entity = Entity.newBuilder(lock).set(DatastoreTest.LOCK_PROP_VALUE, 1).build();
            DatastoreTest.TRANSACTION.update(entity);
            DatastoreTest.TRANSACTION.commit();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (DatastoreTest.TRANSACTION.isActive()) {
                DatastoreTest.TRANSACTION.rollback();
            }
        }
        System.out.println("thread1 done.");
    }
}

class MultiThread2 extends Thread {
    public void run() {
        Entity lock = DatastoreTest.DATASTORE.get(DatastoreTest.KEY_FACTORY.newKey("test"));
        System.out.println("got lock from 2: " + lock.getLong((DatastoreTest.LOCK_PROP_VALUE)));
        Entity entity = Entity.newBuilder(lock).set(DatastoreTest.LOCK_PROP_VALUE, 2).build();
        DatastoreTest.DATASTORE.update(entity);
        System.out.println("thread2 done.");
    }
}
got lock from 1: 0
got lock from 2: 0
thread2 done.
sleep 1 ended
[WARNING]
com.google.cloud.datastore.DatastoreException: too much contention on these datastore entities. please try again. entity groups: [(app=b~spinapptest-151310!dataflow, lock, "test")]

Après la mise à jour avec thread2, une erreur lors de la tentative de mise à jour avec thread1. La banque de données est mise à jour avec Thread2.

Scénario 3


class MultiThread1 extends Thread {
    public void run() {
        try {
            Entity lock = DatastoreTest.DATASTORE.get(DatastoreTest.KEY_FACTORY.newKey("test"));
            Thread.sleep(10000);
            System.out.println("sleep 1 ended");
            System.out.println("got lock from 1: " + lock.getLong((DatastoreTest.LOCK_PROP_VALUE)));
            Entity entity = Entity.newBuilder(lock).set(DatastoreTest.LOCK_PROP_VALUE, 1).build();
            DatastoreTest.DATASTORE.update(entity);
            System.out.println("thread1 done.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class MultiThread2 extends Thread {
    public void run() {
        Entity lock = DatastoreTest.TRANSACTION.get(DatastoreTest.KEY_FACTORY.newKey("test"));
        System.out.println("got lock from 2: " + lock.getLong((DatastoreTest.LOCK_PROP_VALUE)));
        try {
            Entity entity = Entity.newBuilder(lock).set(DatastoreTest.LOCK_PROP_VALUE, 2).build();
            DatastoreTest.TRANSACTION.update(entity);
            DatastoreTest.TRANSACTION.commit();
        } finally {
            if (DatastoreTest.TRANSACTION.isActive()) {
                DatastoreTest.TRANSACTION.rollback();
            }
        }
        System.out.println("thread2 done.");
    }
}
got lock from 2: 0
thread2 done.
sleep 1 ended
got lock from 1: 0
thread1 done.

Les deux processus Thread réussissent.

Recommended Posts

Remarques sur les transactions dans la bibliothèque client Java dans la banque de données
Remarques sur l'utilisation de la guimauve dans la bibliothèque de schémas
Remarques sur imshow () d'OpenCV
Remarques sur la coloration par valeur dans le diagramme de dispersion matplotlib
Remarques sur l'utilisation de matplotlib sur le serveur
Remarques sur l'installation d'Ubuntu 18.04 sur XPS 15 7590
Essayez d'envoyer un e-mail avec la bibliothèque cliente de l'API Gmail pour Java
Note de nfc.ContactlessFrontend () de nfcpy de python
Remarques sur la création de fichiers statiques avec Django
Implémenter OAuth sans bibliothèque client (Java)
Qu'est-ce que "mahjong" dans la bibliothèque Python? ??
Retour sur 2016 dans le langage Crystal
SELECT des données à l'aide de la bibliothèque cliente avec BigQuery
Comment utiliser la bibliothèque C en Python
Exécutez des tâches en arrière-plan sur le serveur sur lequel vous vous êtes connecté
Notes fréquemment utilisées (personnellement) pour la commande tar
Client de streaming Twitter à apprécier dans le terminal
Remarques sur l'utilisation de dict avec python [Competition Pro]
ABC125_C --GCD sur tableau noir [Notes résolues en Python]
Utilisez l'application LibreOffice en Python (3) Ajouter une bibliothèque
Installez la bibliothèque d'apprentissage automatique TensorFlow sur fedora23
Une note sur l'implémentation de la bibliothèque qui explore les hyperparamètres à l'aide de l'optimisation bayésienne en Python