Embedded

From the API side, there's no real difference between transactions executing concurrently within the same VM and transactions executed against a remote server. To use concurrent transactions within a single VM, we just open a db4o server on our database file, directing it to run on port 0, thereby declaring that no networking will take place.

ClientServerExample.java: accessLocalServer
01public static void accessLocalServer() { 02 ObjectServer server=Db4o.openServer(YAPFILENAME,0); 03 try { 04 ObjectContainer client=server.openClient(); 05 // Do something with this client, or open more clients 06 client.close(); 07 } 08 finally { 09 server.close(); 10 } 11 }

Again, we will delegate opening and closing the server to our environment to focus on client interactions.

ClientServerExample.java: queryLocalServer
1public static void queryLocalServer(ObjectServer server) { 2 ObjectContainer client=server.openClient(); 3 listResult(client.get(new Car(null))); 4 client.close(); 5 }

The transaction level in db4o is read committed. However, each client container maintains its own weak reference cache of already known objects. To make all changes committed by other clients immediately, we have to explicitly refresh known objects from the server. We will delegate this task to a specialized version of our listResult() method.

ClientServerExample.java: listRefreshedResult
1public static void listRefreshedResult(ObjectContainer container,ObjectSet result,int depth) { 2 System.out.println(result.size()); 3 while(result.hasNext()) { 4 Object obj = result.next(); 5 container.ext().refresh(obj, depth); 6 System.out.println(obj); 7 } 8 }

ClientServerExample.java: demonstrateLocalReadCommitted
01public static void demonstrateLocalReadCommitted(ObjectServer server) { 02 ObjectContainer client1=server.openClient(); 03 ObjectContainer client2=server.openClient(); 04 Pilot pilot=new Pilot("David Coulthard",98); 05 ObjectSet result=client1.get(new Car("BMW")); 06 Car car=(Car)result.next(); 07 car.setPilot(pilot); 08 client1.set(car); 09 listResult(client1.get(new Car(null))); 10 listResult(client2.get(new Car(null))); 11 client1.commit(); 12 listResult(client1.get(Car.class)); 13 listRefreshedResult(client2,client2.get(Car.class),2); 14 client1.close(); 15 client2.close(); 16 }

Simple rollbacks just work as you might expect now.

ClientServerExample.java: demonstrateLocalRollback
01public static void demonstrateLocalRollback(ObjectServer server) { 02 ObjectContainer client1=server.openClient(); 03 ObjectContainer client2=server.openClient(); 04 ObjectSet result=client1.get(new Car("BMW")); 05 Car car=(Car)result.next(); 06 car.setPilot(new Pilot("Someone else",0)); 07 client1.set(car); 08 listResult(client1.get(new Car(null))); 09 listResult(client2.get(new Car(null))); 10 client1.rollback(); 11 client1.ext().refresh(car,2); 12 listResult(client1.get(new Car(null))); 13 listResult(client2.get(new Car(null))); 14 client1.close(); 15 client2.close(); 16 }