Verwenden der Java-Clientbibliothek (Google Cloud-Clientbibliothek für Java) zur Verwendung des Datenspeichers Es gibt. Ich habe untersucht, wie diese Transaktion in der Multithread-Verarbeitung funktioniert. Das offizielle Dokument hatte die folgende Spezifikationserklärung, daher habe ich es beim Ausführen des Codes überprüft.
Wenn für eine oder mehrere allgemeine Entitätsgruppen mehrere Transaktionen gleichzeitig versuchen, eine Entität zu ändern, ist nur die erste Transaktion erfolgreich, die die Änderung festschreibt, und alle anderen Transaktionen können nicht festgeschrieben werden. Werden.
Wir haben auch bestätigt, was passiert, wenn die Verarbeitung über das Transaktionsobjekt und die Verarbeitung über das Datenspeicherobjekt gemischt werden.
Dokumentation Dokumente zu Transaktionen
Überprüfen Sie, was passiert, wenn Sie in den folgenden drei Fällen versuchen, eine Entität aus mehreren Threads zu aktualisieren
Holen Sie sich die Entität von Thread1 über Transaktion und Ruhezustand -> Entität von Thread2 über Transaktion & Update abrufen -> Update über Transaktion mit Thread1
Holen Sie sich die Entität von Thread1 über Transaktion und Ruhezustand -> Entität von Thread2 über Datenspeicher & Update abrufen -> Update über Transaktion mit Thread1
Holen Sie sich die Entität von Thread1 über den Datenspeicher und schlafen Sie -> Entität von Thread2 über Transaktion & Update abrufen -> Update über Datenspeicher mit Thread1
Aktualisieren Sie im Fall von transaction.update, nachdem Sie bestätigt haben, ob sich die Entität zum Zeitpunkt des Erwerbs geändert hat. Die Ausnahme ist, wenn sich der Status der Entität geändert hat. Es spielt keine Rolle, ob der Aktualisierungsprozess über ein Transaktionsobjekt oder ein Datenspeicherobjekt erfolgt.
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
Nach dem Festschreiben von Thread2 wird beim Versuch, ein Update auf Thread1 durchzuführen, eine Transaktion nicht mehr aktiv. Der Datenspeicher wird mit Thread2 aktualisiert.
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")]
Nach dem Update mit Thread2 tritt ein Fehler beim Aktualisieren mit Thread1 auf. Der Datenspeicher wird mit Thread2 aktualisiert.
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.
Beide Thread-Prozesse sind erfolgreich.
Recommended Posts