-
Notifications
You must be signed in to change notification settings - Fork 0
Java Multi Threading
OrientDB supports multi-threads access to the database. ODatabase*
instances are not thread-safe, so you've to get an instance per thread and each database instance can be used only in one thread per time.
Multiple database instances points to the same storage by using the same URL. In this case Storage is thread-save and orchestrates requests from different ODatabase*
instances.
ODatabaseDocument1------+
+----> OStorageLocal (url=local:/temp/db)
ODatabaseDocument2------+
Database instances share the following objects:
- schema
- index manager
- security
These objects are synchronized for concurrent contexts by storing the current database in the ThreadLocal variable. Every time you create, open or acquire a database connection, the database instance is automatically set into the current ThreadLocal space, so in normal use this is hidden from the developer.
The current database is always reset for all common operations like load, save, etc.
Example of using two database in the same thread:
ODocument rec1 = database1.newInstance();
ODocument rec2 = database2.newInstance();
rec1.field("name", "Luca");
database1.save(rec1); // force saving in database1 no matter where the record came from
rec2.field("name", "Luke");
database2.save(rec2); // force saving in database2 no matter where the record came from
Beware when you reuse database instances from different threads or then a thread handle multiple databases. In this case you can override the current database by calling this manually:
ODatabaseRecordThreadLocal.INSTANCE.set( database );
Where database is the current database instance. Example:
ODocument rec1 = database1.newInstance();
ODocument rec2 = database2.newInstance();
ODatabaseRecordThreadLocal.INSTANCE.set( database1 );
rec1.field("name", "Luca");
rec1.save();
ODatabaseRecordThreadLocal.INSTANCE.set( database2 );
rec2.field("name", "Luke");
rec2.save();
Since v1.2 Orient provides an interface to manage custom database management in MultiThreading cases:
public interface ODatabaseThreadLocalFactory {
public ODatabaseRecord getThreadDatabase();
}
Examples:
public class MyCustomRecordFactory implements ODatabaseThreadLocalFactory {
public ODatabaseRecord getDb(){
return ODatabaseDocumentPool.global().acquire(url, "admin", "admin");
}
}
public class MyCustomObjectFactory implements ODatabaseThreadLocalFactory {
public ODatabaseRecord getThreadDatabase(){
return OObjectDatabasePool.global().acquire(url, "admin", "admin").getUnderlying().getUnderlying();
}
}
Registering the factory:
ODatabaseThreadLocalFactory customFactory = new MyCustomRecordFactory();
Orient.instance().registerThreadDatabaseFactory(customFactory);
When a database is not found in current thread it will be called the factory getDb() to retrieve the database instance.
What happens if you are working with two databases and close one? The Thread Local isn't a stack, so you loose the previous database in use. Example:
ODatabaseDocumentTx db1 = new ODatabaseDocumentTx("local:/temo/db1").create();
ODatabaseDocumentTx db2 = new ODatabaseDocumentTx("local:/temo/db2").create();
...
db2.close();
// NOW NO DATABASE IS SET IN THREAD LOCAL. TO WORK WITH DB1 SET IT IN THE THREAD LOCAL
ODatabaseRecordThreadLocal.INSTANCE.set( db1 );
...
Transactions are bound to a database, so if you change the current database while a tx is running, the deleted and saved objects remain attached to the original database transaction. When it commits, the objects are committed.
Example:
ODatabaseDocumentTx db1 = new ODatabaseDocumentTx("local:/temo/db1").create();
db1.begin();
ODocument doc1 = new ODocument("Customer");
doc1.field("name", "Luca");
doc1.save(); // NOW IT'S BOUND TO DB1'S TX
ODatabaseDocumentTx db2 = new ODatabaseDocumentTx("local:/temo/db2").create(); // THE CURRENT DB NOW IS DB2
ODocument doc2 = new ODocument("Provider");
doc2.field("name", "Chuck");
doc2.save(); // THIS IS BOUND TO DB2 BECAUSE IT'S THE CURRENT ONE
db1.commit(); // WILL COMMIT DOC1 ONLY