|
9. Client/Server
Now that we have seen how transactions work in db4o conceptually, we are prepared to tackle concurrently executing transactions.
We start by preparing our database in the familiar way.
[setFirstCar]
Pilot pilot = new Pilot("Rubens Barrichello", 99);
Car car = new Car("BMW");
car.Pilot = pilot;
db.set(car);
|
[setSecondCar]
Pilot pilot = new Pilot("Michael Schumacher", 100);
Car car = new Car("Ferrari");
car.Pilot = pilot;
db.set(car);
|
9.1. Embedded server
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.
[accessLocalServer]
ObjectServer server = Db4o.openServer(Util.YapFileName, 0);
try
{
ObjectContainer client = server.openClient();
// Do something with this client, or open more clients
client.close();
}
finally
{
server.close();
}
|
Again, we will delegate opening and closing the server to our environment to focus on client interactions.
[queryLocalServer]
ObjectContainer client = server.openClient();
listResult(client.get(new Car(null)));
client.close();
|
OUTPUT: 2
Ferrari[Michael Schumacher/100]/0
BMW[Rubens Barrichello/99]/0
[db4o 4.3.003 2005-03-17 15:15:19]
Connection closed by client %.
[db4o 4.3.003 2005-03-17 15:15:19]
'C:\DOCUME~1\Carl\LOCALS~1\Temp\formula111396.yap' close request
[db4o 4.3.003 2005-03-17 15:15:19]
'C:\DOCUME~1\Carl\LOCALS~1\Temp\formula111396.yap' closed
|
|
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.
public static void listRefreshedResult{
Console.WriteLine(items.size());
while (items.hasNext())
{
object item = items.next();
container.ext().refresh(item, depth);
Console.WriteLine(item);
}
}
|
[demonstrateLocalReadCommitted]
ObjectContainer client1 =server.openClient();
ObjectContainer client2 =server.openClient();
Pilot pilot = new Pilot("David Coulthard", 98);
ObjectSet result = client1.get(new Car("BMW"));
Car car = (Car)result.next();
car.Pilot = pilot;
client1.set(car);
listResult(client1.get(new Car(null)));
listResult(client2.get(new Car(null)));
client1.commit();
listResult(client1.get(typeof(Car)));
listRefreshedResult(client2, client2.get(typeof(Car)), 2);
client1.close();
client2.close();
|
OUTPUT: 2
Ferrari[Michael Schumacher/100]/0
BMW[David Coulthard/98]/0
2
Ferrari[Michael Schumacher/100]/0
BMW[Rubens Barrichello/99]/0
2
Ferrari[Michael Schumacher/100]/0
BMW[David Coulthard/98]/0
2
Ferrari[Michael Schumacher/100]/0
BMW[David Coulthard/98]/0
[db4o 4.3.003 2005-03-17 15:15:20]
Connection closed by client %.
[db4o 4.3.003 2005-03-17 15:15:20]
Connection closed by client %.
[db4o 4.3.003 2005-03-17 15:15:20]
'C:\DOCUME~1\Carl\LOCALS~1\Temp\formula111396.yap' close request
[db4o 4.3.003 2005-03-17 15:15:20]
'C:\DOCUME~1\Carl\LOCALS~1\Temp\formula111396.yap' closed
|
Simple rollbacks just work as you might expect now.
[demonstrateLocalRollback]
ObjectContainer client1 = server.openClient();
ObjectContainer client2 = server.openClient();
ObjectSet result = client1.get(new Car("BMW"));
Car car = (Car)result.next();
car.Pilot = new Pilot("Someone else", 0);
client1.set(car);
listResult(client1.get(new Car(null)));
listResult(client2.get(new Car(null)));
client1.rollback();
client1.ext().refresh(car, 2);
listResult(client1.get(new Car(null)));
listResult(client2.get(new Car(null)));
client1.close();
client2.close();
|
OUTPUT: 2
Ferrari[Michael Schumacher/100]/0
BMW[Someone else/0]/0
2
Ferrari[Michael Schumacher/100]/0
BMW[David Coulthard/98]/0
2
Ferrari[Michael Schumacher/100]/0
BMW[David Coulthard/98]/0
2
Ferrari[Michael Schumacher/100]/0
BMW[David Coulthard/98]/0
[db4o 4.3.003 2005-03-17 15:15:20]
[db4o 4.3.003 2005-03-17 15:15:20]
Connection closed by client %.
Connection closed by client %.
[db4o 4.3.003 2005-03-17 15:15:20]
'C:\DOCUME~1\Carl\LOCALS~1\Temp\formula111396.yap' close request
[db4o 4.3.003 2005-03-17 15:15:20]
'C:\DOCUME~1\Carl\LOCALS~1\Temp\formula111396.yap' closed
|
9.2. Networking
From here it's only a small step towards operating db4o over a TCP/IP network. We just specify a port number greater than zero and set up one or more accounts for our client(s).
[accessRemoteServer]
ObjectServer server = Db4o.openServer(Util.YapFileName, ServerPort);
server.grantAccess(ServerUser, ServerPassword);
try
{
ObjectContainer client = Db4o.openClient("localhost", ServerPort, ServerUser, ServerPassword);
// Do something with this client, or open more clients
client.close();
}
finally
{
server.close();
}
|
The client connects providing host, port, user name and password.
[queryRemoteServer]
ObjectContainer client = Db4o.openClient("localhost", port, user, password);
listResult(client.get(new Car(null)));
client.close();
|
OUTPUT: [db4o 4.3.003 2005-03-17 15:15:20]
Server listening on port: '56128'
[db4o 4.3.003 2005-03-17 15:15:20]
Client 'user' connected.
2
Ferrari[Michael Schumacher/100]/0
BMW[David Coulthard/98]/0
[db4o 4.3.003 2005-03-17 15:15:20]
Connection closed by client 'user'.
[db4o 4.3.003 2005-03-17 15:15:20]
'C:\DOCUME~1\Carl\LOCALS~1\Temp\formula111396.yap' close request
[db4o 4.3.003 2005-03-17 15:15:20]
'C:\DOCUME~1\Carl\LOCALS~1\Temp\formula111396.yap' closed
|
Everything else is absolutely identical to the local server examples above.
[demonstrateRemoteReadCommitted]
ObjectContainer client1 = Db4o.openClient("localhost", port, user, password);
ObjectContainer client2 = Db4o.openClient("localhost", port, user, password);
Pilot pilot = new Pilot("Jenson Button", 97);
ObjectSet result = client1.get(new Car(null));
Car car = (Car)result.next();
car.Pilot = pilot;
client1.set(car);
listResult(client1.get(new Car(null)));
listResult(client2.get(new Car(null)));
client1.commit();
listResult(client1.get(new Car(null)));
listResult(client2.get(new Car(null)));
client1.close();
client2.close();
|
OUTPUT: [db4o 4.3.003 2005-03-17 15:15:20]
Server listening on port: '56128'
[db4o 4.3.003 2005-03-17 15:15:20]
Client 'user' connected.
[db4o 4.3.003 2005-03-17 15:15:20]
Client 'user' connected.
2
Ferrari[Jenson Button/97]/0
BMW[David Coulthard/98]/0
2
Ferrari[Michael Schumacher/100]/0
BMW[David Coulthard/98]/0
2
Ferrari[Jenson Button/97]/0
BMW[David Coulthard/98]/0
2
Ferrari[Jenson Button/97]/0
BMW[David Coulthard/98]/0
[db4o 4.3.003 2005-03-17 15:15:20]
Connection closed by client 'user'.
[db4o 4.3.003 2005-03-17 15:15:20]
Connection closed by client 'user'.
[db4o 4.3.003 2005-03-17 15:15:21]
'C:\DOCUME~1\Carl\LOCALS~1\Temp\formula111396.yap' close request
[db4o 4.3.003 2005-03-17 15:15:21]
'C:\DOCUME~1\Carl\LOCALS~1\Temp\formula111396.yap' closed
|
[demonstrateRemoteRollback]
ObjectContainer client1 = Db4o.openClient("localhost", port, user, password);
ObjectContainer client2 = Db4o.openClient("localhost", port, user, password);
ObjectSet result = client1.get(new Car(null));
Car car = (Car)result.next();
car.Pilot = new Pilot("Someone else", 0);
client1.set(car);
listResult(client1.get(new Car(null)));
listResult(client2.get(new Car(null)));
client1.rollback();
client1.ext().refresh(car,2);
listResult(client1.get(new Car(null)));
listResult(client2.get(new Car(null)));
client1.close();
client2.close();
|
OUTPUT: [db4o 4.3.003 2005-03-17 15:15:21]
Server listening on port: '56128'
[db4o 4.3.003 2005-03-17 15:15:21]
Client 'user' connected.
[db4o 4.3.003 2005-03-17 15:15:21]
Client 'user' connected.
2
Ferrari[Someone else/0]/0
BMW[David Coulthard/98]/0
2
Ferrari[Jenson Button/97]/0
BMW[David Coulthard/98]/0
2
Ferrari[Jenson Button/97]/0
BMW[David Coulthard/98]/0
2
Ferrari[Jenson Button/97]/0
BMW[David Coulthard/98]/0
[db4o 4.3.003 2005-03-17 15:15:21]
Connection closed by client 'user'.
[db4o 4.3.003 2005-03-17 15:15:21]
Connection closed by client 'user'.
[db4o 4.3.003 2005-03-17 15:15:21]
'C:\DOCUME~1\Carl\LOCALS~1\Temp\formula111396.yap' close request
[db4o 4.3.003 2005-03-17 15:15:21]
'C:\DOCUME~1\Carl\LOCALS~1\Temp\formula111396.yap' closed
|
9.3. Conclusion
That's it, folks. No, of course it isn't. There's much more to db4o we haven't covered yet: schema evolution, custom persistence for your classes, writing your own query objects, etc.
This tutorial is work in progress. We will successively add chapters and incorporate feedback from the community into the existing chapters.
We hope that this tutorial has helped to get you started with db4o. How should you continue now?
-
(Interactive version only)While this tutorial is basically sequential in nature, try to switch back and forth between the chapters and execute the sample snippets in arbitrary order. You will be working with the same database throughout; sometimes you may just get stuck or even induce exceptions, but you can always reset the database via the console window.
- The examples we've worked through are included in your db4o distribution in full source code. Feel free to experiment with it.
- I you're stuck, see if the FAQ can solve your problem, browse the information on our
web site, check if your problem is submitted to
Bugzilla or join our newsgroup at
news://news.db4odev.com/db4o.users.
9.4. Full source
namespace com.db4o.f1.chapter5
{
using System;
using System.IO;
using com.db4o;
using com.db4o.f1;
public class ClientServerExample : Util
{
public static void Main(string[] args)
{
File.Delete(Util.YapFileName);
accessLocalServer();
File.Delete(Util.YapFileName);
ObjectContainer db = Db4o.openFile(Util.YapFileName);
try
{
setFirstCar(db);
setSecondCar(db);
}
finally
{
db.close();
}
configureDb4o();
ObjectServer server = Db4o.openServer(Util.YapFileName, 0);
try
{
queryLocalServer(server);
demonstrateLocalReadCommitted(server);
demonstrateLocalRollback(server);
}
finally
{
server.close();
}
accessRemoteServer();
server = Db4o.openServer(Util.YapFileName, ServerPort);
server.grantAccess(ServerUser, ServerPassword);
try
{
queryRemoteServer(ServerPort, ServerUser, ServerPassword);
demonstrateRemoteReadCommitted(ServerPort, ServerUser, ServerPassword);
demonstrateRemoteRollback(ServerPort, ServerUser, ServerPassword);
}
finally
{
server.close();
}
}
public static void setFirstCar(ObjectContainer db)
{
Pilot pilot = new Pilot("Rubens Barrichello", 99);
Car car = new Car("BMW");
car.Pilot = pilot;
db.set(car);
}
public static void setSecondCar(ObjectContainer db)
{
Pilot pilot = new Pilot("Michael Schumacher", 100);
Car car = new Car("Ferrari");
car.Pilot = pilot;
db.set(car);
}
public static void accessLocalServer()
{
ObjectServer server = Db4o.openServer(Util.YapFileName, 0);
try
{
ObjectContainer client = server.openClient();
// Do something with this client, or open more clients
client.close();
}
finally
{
server.close();
}
}
public static void queryLocalServer(ObjectServer server)
{
ObjectContainer client = server.openClient();
listResult(client.get(new Car(null)));
client.close();
}
public static void configureDb4o()
{
Db4o.configure().objectClass(typeof(Car)).updateDepth(3);
}
public static void demonstrateLocalReadCommitted(ObjectServer server)
{
ObjectContainer client1 =server.openClient();
ObjectContainer client2 =server.openClient();
Pilot pilot = new Pilot("David Coulthard", 98);
ObjectSet result = client1.get(new Car("BMW"));
Car car = (Car)result.next();
car.Pilot = pilot;
client1.set(car);
listResult(client1.get(new Car(null)));
listResult(client2.get(new Car(null)));
client1.commit();
listResult(client1.get(typeof(Car)));
listRefreshedResult(client2, client2.get(typeof(Car)), 2);
client1.close();
client2.close();
}
public static void demonstrateLocalRollback(ObjectServer server)
{
ObjectContainer client1 = server.openClient();
ObjectContainer client2 = server.openClient();
ObjectSet result = client1.get(new Car("BMW"));
Car car = (Car)result.next();
car.Pilot = new Pilot("Someone else", 0);
client1.set(car);
listResult(client1.get(new Car(null)));
listResult(client2.get(new Car(null)));
client1.rollback();
client1.ext().refresh(car, 2);
listResult(client1.get(new Car(null)));
listResult(client2.get(new Car(null)));
client1.close();
client2.close();
}
public static void accessRemoteServer()
{
ObjectServer server = Db4o.openServer(Util.YapFileName, ServerPort);
server.grantAccess(ServerUser, ServerPassword);
try
{
ObjectContainer client = Db4o.openClient("localhost", ServerPort, ServerUser, ServerPassword);
// Do something with this client, or open more clients
client.close();
}
finally
{
server.close();
}
}
public static void queryRemoteServer(int port, string user, string password)
{
ObjectContainer client = Db4o.openClient("localhost", port, user, password);
listResult(client.get(new Car(null)));
client.close();
}
public static void demonstrateRemoteReadCommitted(int port, string user, string password)
{
ObjectContainer client1 = Db4o.openClient("localhost", port, user, password);
ObjectContainer client2 = Db4o.openClient("localhost", port, user, password);
Pilot pilot = new Pilot("Jenson Button", 97);
ObjectSet result = client1.get(new Car(null));
Car car = (Car)result.next();
car.Pilot = pilot;
client1.set(car);
listResult(client1.get(new Car(null)));
listResult(client2.get(new Car(null)));
client1.commit();
listResult(client1.get(new Car(null)));
listResult(client2.get(new Car(null)));
client1.close();
client2.close();
}
public static void demonstrateRemoteRollback(int port, string user, string password)
{
ObjectContainer client1 = Db4o.openClient("localhost", port, user, password);
ObjectContainer client2 = Db4o.openClient("localhost", port, user, password);
ObjectSet result = client1.get(new Car(null));
Car car = (Car)result.next();
car.Pilot = new Pilot("Someone else", 0);
client1.set(car);
listResult(client1.get(new Car(null)));
listResult(client2.get(new Car(null)));
client1.rollback();
client1.ext().refresh(car,2);
listResult(client1.get(new Car(null)));
listResult(client2.get(new Car(null)));
client1.close();
client2.close();
}
}
}
|
--
generated by Doctor courtesy of db4objecs Inc.