db4o Tutorial 中文翻译(十一)
9. 客户端/服务器
Now that we have seen how transactions work in db4o conceptually, we are prepared to tackle concurrently executing transactions.
现在我们已经明白db4o中事务的概念了,本章讲处理并行执行的事务。
现在按照以往熟悉的方法准备数据。
// setFirstCar
Pilot pilot = new Pilot("Rubens Barrichello", 99);
Car car = new Car("BMW");
car.Pilot = pilot;
db.Set(car);
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);
Pilot pilot = new Pilot("Michael Schumacher", 100);
Car car = new Car("Ferrari");
car.Pilot = pilot;
db.Set(car);
- 从API角度看,分布式事务和单一VM上的事务没有什么本质区别。在单机上使用事务,我们需要打开db4o服务器,指示它从0端口运行,从而其他的网络程序不可以占用。
// accessLocalServer
IObjectServer server = Db4oFactory.OpenServer(Util.YapFileName, 0);
try
{
IObjectContainer client = server.OpenClient();
// Do something with this client, or open more clients
client.Close();
}
finally
{
server.Close();
}
IObjectServer server = Db4oFactory.OpenServer(Util.YapFileName, 0);
try
{
IObjectContainer client = server.OpenClient();
// Do something with this client, or open more clients
client.Close();
}
finally
{
server.Close();
}
- 再次委托打开和关闭数据库的服务器作为运行环境,从而捕捉客户端交互。
// queryLocalServer
IObjectContainer client = server.OpenClient();
ListResult(client.Get(new Car(null)));
client.Close();
IObjectContainer client = server.OpenClient();
ListResult(client.Get(new Car(null)));
client.Close();
- 这个事务的级别在db4o里面被成为“read committed”。但是,每个客户端维护它自己的已知对象缓存的引用。为了让其他客户端的变化快速执行,我们需要在服务器端直接引用已知的对象。我们将这个任务代理为一个专门的ListResult()方法的版本。
public static void ListRefreshedResult(IObjectContainer container, IObjectSet items, int depth)
{
Console.WriteLine(items.Count);
foreach (object item in items)
{
container.Ext().Refresh(item, depth);
Console.WriteLine(item);
}
}
{
Console.WriteLine(items.Count);
foreach (object item in items)
{
container.Ext().Refresh(item, depth);
Console.WriteLine(item);
}
}
// demonstrateLocalReadCommitted
IObjectContainer client1 =server.OpenClient();
IObjectContainer client2 =server.OpenClient();
Pilot pilot = new Pilot("David Coulthard", 98);
IObjectSet 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();
IObjectContainer client1 =server.OpenClient();
IObjectContainer client2 =server.OpenClient();
Pilot pilot = new Pilot("David Coulthard", 98);
IObjectSet 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();
会滚也可以这样工作,就像你预料的一样:
// demonstrateLocalRollback
IObjectContainer client1 = server.OpenClient();
IObjectContainer client2 = server.OpenClient();
IObjectSet 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();
IObjectContainer client1 = server.OpenClient();
IObjectContainer client2 = server.OpenClient();
IObjectSet 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();
9.2. 网络
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).
到了这里,距离通过TCP/IP协议操作db4o没有多少步骤了。我们需要专门指定一个大于0的端口号码,为客户端设置一个或者更多的帐户。
// accessRemoteServer
IObjectServer server = Db4oFactory.OpenServer(Util.YapFileName, ServerPort);
server.GrantAccess(ServerUser, ServerPassword);
try
{
IObjectContainer client = Db4oFactory.OpenClient("localhost", ServerPort, ServerUser, ServerPassword);
// Do something with this client, or open more clients
client.Close();
}
finally
{
server.Close();
}
IObjectServer server = Db4oFactory.OpenServer(Util.YapFileName, ServerPort);
server.GrantAccess(ServerUser, ServerPassword);
try
{
IObjectContainer client = Db4oFactory.OpenClient("localhost", ServerPort, ServerUser, ServerPassword);
// Do something with this client, or open more clients
client.Close();
}
finally
{
server.Close();
}
.
这个客户端的连接需要提供一个主机、端口、用户名和密码。
// queryRemoteServer
IObjectContainer client = Db4oFactory.OpenClient("localhost", port, user, password);
ListResult(client.Get(new Car(null)));
client.Close();
IObjectContainer client = Db4oFactory.OpenClient("localhost", port, user, password);
ListResult(client.Get(new Car(null)));
client.Close();
- 刚才的所有数据都通过上面的例子检索出来了
// demonstrateRemoteReadCommitted
IObjectContainer client1 = Db4oFactory.OpenClient("localhost", port, user, password);
IObjectContainer client2 = Db4oFactory.OpenClient("localhost", port, user, password);
Pilot pilot = new Pilot("Jenson Button", 97);
IObjectSet 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();
IObjectContainer client1 = Db4oFactory.OpenClient("localhost", port, user, password);
IObjectContainer client2 = Db4oFactory.OpenClient("localhost", port, user, password);
Pilot pilot = new Pilot("Jenson Button", 97);
IObjectSet 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();
// demonstrateRemoteRollback
IObjectContainer client1 = Db4oFactory.OpenClient("localhost", port, user, password);
IObjectContainer client2 = Db4oFactory.OpenClient("localhost", port, user, password);
IObjectSet 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();
IObjectContainer client1 = Db4oFactory.OpenClient("localhost", port, user, password);
IObjectContainer client2 = Db4oFactory.OpenClient("localhost", port, user, password);
IObjectSet 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();
9.3. 消息传输
- 有时候客户端需要请求服务器做一些事情,就要发送一个特殊的消息给服务器。服务器需要接受消息、发送消息到涉及的对象。
- 可以通过SETMESSAGERECIPIENT()方法,找到发送消息的对象。
public void RunServer()
{
lock(this)
{
IObjectServer db4oServer = Db4oFactory.OpenServer(FILE, PORT);
db4oServer.GrantAccess(USER, PASS);
// Using the messaging functionality to redirect all
// messages to this.processMessage
db4oServer.Ext().Configure().ClientServer().SetMessageRecipient(this);
try
{
if (! stop)
{
// wait forever for Notify() from Close()
Monitor.Wait(this);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
db4oServer.Close();
}
}
{
lock(this)
{
IObjectServer db4oServer = Db4oFactory.OpenServer(FILE, PORT);
db4oServer.GrantAccess(USER, PASS);
// Using the messaging functionality to redirect all
// messages to this.processMessage
db4oServer.Ext().Configure().ClientServer().SetMessageRecipient(this);
try
{
if (! stop)
{
// wait forever for Notify() from Close()
Monitor.Wait(this);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
db4oServer.Close();
}
}
消息已经接收到了,并且被PROCESSMESSAGE() 方法传递。
db4o允许一个客户端以无格式的类的对象的形式发送一个任意的消息或者信号给服务器。服务器收到后会发回一个收到消息,包含从客户发来的对象。服务器可以任意定义消息的格式。
9.4. 整合--一个简单但是完整的db4oserver
- 让我们将以上的信息整合,从而写出一个带有专门客户端的简单服务器,客户端可以通知服务器关闭。
- 首先,服务器和客户端都需要一些共享的设置信息。我们提供一个接口:
namespace Db4objects.Db4o.Tutorial.F1.Chapter5
{
/// <summary>
/// Configuration used for StartServer and StopServer.
/// </summary>
public class ServerConfiguration
{
/// <summary>
/// the host to be used.
/// If you want to run the client server examples on two computers,
/// enter the computer name of the one that you want to use as server.
/// </summary>
public const string HOST = "localhost";
/// <summary>
/// the database file to be used by the server.
/// </summary>
public const string FILE = "formula1.yap";
/// <summary>
/// the port to be used by the server.
/// </summary>
public const int PORT = 4488;
/// <summary>
/// the user name for access control.
/// </summary>
public const string USER = "db4o";
/// <summary>
/// the pasword for access control.
/// </summary>
public const string PASS = "db4o";
}
}
{
/// <summary>
/// Configuration used for StartServer and StopServer.
/// </summary>
public class ServerConfiguration
{
/// <summary>
/// the host to be used.
/// If you want to run the client server examples on two computers,
/// enter the computer name of the one that you want to use as server.
/// </summary>
public const string HOST = "localhost";
/// <summary>
/// the database file to be used by the server.
/// </summary>
public const string FILE = "formula1.yap";
/// <summary>
/// the port to be used by the server.
/// </summary>
public const int PORT = 4488;
/// <summary>
/// the user name for access control.
/// </summary>
public const string USER = "db4o";
/// <summary>
/// the pasword for access control.
/// </summary>
public const string PASS = "db4o";
}
}
创建server:
锘縰sing System;
using System.Threading;
using Db4objects.Db4o;
using Db4objects.Db4o.Messaging;
namespace Db4objects.Db4o.Tutorial.F1.Chapter5
{
/// <summary>
/// starts a db4o server with the settings from ServerConfiguration.
/// This is a typical setup for a long running server.
/// The Server may be stopped from a remote location by running
/// StopServer. The StartServer instance is used as a MessageRecipient
/// and reacts to receiving an instance of a StopServer object.
/// Note that all user classes need to be present on the server side
/// and that all possible Db4oFactory.Configure() calls to alter the db4o
/// configuration need to be executed on the client and on the server.
/// </summary>
public class StartServer : ServerConfiguration, IMessageRecipient
{
/// <summary>
/// setting the value to true denotes that the server should be closed
/// </summary>
private bool stop = false;
/// <summary>
/// starts a db4o server using the configuration from
/// ServerConfiguration.
/// </summary>
public static void Main(string[] arguments)
{
new StartServer().RunServer();
}
/// <summary>
/// opens the IObjectServer, and waits forever until Close() is called
/// or a StopServer message is being received.
/// </summary>
public void RunServer()
{
lock(this)
{
IObjectServer db4oServer = Db4oFactory.OpenServer(FILE, PORT);
db4oServer.GrantAccess(USER, PASS);
// Using the messaging functionality to redirect all
// messages to this.processMessage
db4oServer.Ext().Configure().ClientServer().SetMessageRecipient(this);
try
{
if (! stop)
{
// wait forever for Notify() from Close()
Monitor.Wait(this);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
db4oServer.Close();
}
}
/// <summary>
/// messaging callback
/// see com.db4o.messaging.MessageRecipient#ProcessMessage()
/// </summary>
public void ProcessMessage(IObjectContainer con, object message)
{
if (message is StopServer)
{
Close();
}
}
/// <summary>
/// closes this server.
/// </summary>
public void Close()
{
lock(this)
{
stop = true;
Monitor.PulseAll(this);
}
}
}
}
using System.Threading;
using Db4objects.Db4o;
using Db4objects.Db4o.Messaging;
namespace Db4objects.Db4o.Tutorial.F1.Chapter5
{
/// <summary>
/// starts a db4o server with the settings from ServerConfiguration.
/// This is a typical setup for a long running server.
/// The Server may be stopped from a remote location by running
/// StopServer. The StartServer instance is used as a MessageRecipient
/// and reacts to receiving an instance of a StopServer object.
/// Note that all user classes need to be present on the server side
/// and that all possible Db4oFactory.Configure() calls to alter the db4o
/// configuration need to be executed on the client and on the server.
/// </summary>
public class StartServer : ServerConfiguration, IMessageRecipient
{
/// <summary>
/// setting the value to true denotes that the server should be closed
/// </summary>
private bool stop = false;
/// <summary>
/// starts a db4o server using the configuration from
/// ServerConfiguration.
/// </summary>
public static void Main(string[] arguments)
{
new StartServer().RunServer();
}
/// <summary>
/// opens the IObjectServer, and waits forever until Close() is called
/// or a StopServer message is being received.
/// </summary>
public void RunServer()
{
lock(this)
{
IObjectServer db4oServer = Db4oFactory.OpenServer(FILE, PORT);
db4oServer.GrantAccess(USER, PASS);
// Using the messaging functionality to redirect all
// messages to this.processMessage
db4oServer.Ext().Configure().ClientServer().SetMessageRecipient(this);
try
{
if (! stop)
{
// wait forever for Notify() from Close()
Monitor.Wait(this);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
db4oServer.Close();
}
}
/// <summary>
/// messaging callback
/// see com.db4o.messaging.MessageRecipient#ProcessMessage()
/// </summary>
public void ProcessMessage(IObjectContainer con, object message)
{
if (message is StopServer)
{
Close();
}
}
/// <summary>
/// closes this server.
/// </summary>
public void Close()
{
lock(this)
{
stop = true;
Monitor.PulseAll(this);
}
}
}
}
最后但并不是最不重要的(一点),客户端停止服务器。
db4o已经是一个家族了。不,当然他不是。有太多db4o没有覆盖的内容:schema 进展,为你的对象定制持久层,书写你自己的查询对象。。等等。更多的文档需要提供,你也可下载获得。
我们希望这个教程已经帮助你开始使用db4o,你该怎么继续呢?
你应该浏览剩下的章节。他们是从我们的网站http://forums.db4o.com/forums/.选择的话题。
(只是交互版本),实际上,这个教程只是基本的步骤而已,试着在章节间来回,运行代码片段,你便可以完全掌握db4o。有时候,你有了困难,甚至发生异常,但是随时可以在命令窗口重置数据库。
这些例子都有源代码。所以你可以自由的实验。
如果遇到困难,看看FAQ有没有作用。 在我们的web site浏览信息, 看看你的问题是否被提交到 Jira ,或者访问我们的论坛:http://forums.db4o.com/forums/.
锘縰sing System;
using Db4objects.Db4o;
using Db4objects.Db4o.Messaging;
namespace Db4objects.Db4o.Tutorial.F1.Chapter5
{
/// <summary>
/// stops the db4o Server started with StartServer.
/// This is done by opening a client connection
/// to the server and by sending a StopServer object as
/// a message. StartServer will react in it's
/// processMessage method.
/// </summary>
public class StopServer : ServerConfiguration
{
/// <summary>
/// stops a db4o Server started with StartServer.
/// </summary>
/// <exception cref="Exception" />
public static void Main(string[] args)
{
IObjectContainer IObjectContainer = null;
try
{
// connect to the server
IObjectContainer = Db4oFactory.OpenClient(HOST, PORT, USER, PASS);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
if (IObjectContainer != null)
{
// get the messageSender for the IObjectContainer
IMessageSender messageSender = IObjectContainer.Ext()
.Configure().ClientServer().GetMessageSender();
// send an instance of a StopServer object
messageSender.Send(new StopServer());
// close the IObjectContainer
IObjectContainer.Close();
}
}
}
}
using Db4objects.Db4o;
using Db4objects.Db4o.Messaging;
namespace Db4objects.Db4o.Tutorial.F1.Chapter5
{
/// <summary>
/// stops the db4o Server started with StartServer.
/// This is done by opening a client connection
/// to the server and by sending a StopServer object as
/// a message. StartServer will react in it's
/// processMessage method.
/// </summary>
public class StopServer : ServerConfiguration
{
/// <summary>
/// stops a db4o Server started with StartServer.
/// </summary>
/// <exception cref="Exception" />
public static void Main(string[] args)
{
IObjectContainer IObjectContainer = null;
try
{
// connect to the server
IObjectContainer = Db4oFactory.OpenClient(HOST, PORT, USER, PASS);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
if (IObjectContainer != null)
{
// get the messageSender for the IObjectContainer
IMessageSender messageSender = IObjectContainer.Ext()
.Configure().ClientServer().GetMessageSender();
// send an instance of a StopServer object
messageSender.Send(new StopServer());
// close the IObjectContainer
IObjectContainer.Close();
}
}
}
}
9.5. 总结
db4o已经是一个家族了。不,当然他不是。有太多db4o没有覆盖的内容:schema 进展,为你的对象定制持久层,书写你自己的查询对象。。等等。更多的文档需要提供,你也可下载获得。
我们希望这个教程已经帮助你开始使用db4o,你该怎么继续呢?
你应该浏览剩下的章节。他们是从我们的网站http://forums.db4o.com/forums/.选择的话题。
(只是交互版本),实际上,这个教程只是基本的步骤而已,试着在章节间来回,运行代码片段,你便可以完全掌握db4o。有时候,你有了困难,甚至发生异常,但是随时可以在命令窗口重置数据库。
这些例子都有源代码。所以你可以自由的实验。
如果遇到困难,看看FAQ有没有作用。 在我们的web site浏览信息, 看看你的问题是否被提交到 Jira ,或者访问我们的论坛:http://forums.db4o.com/forums/.
Surance Yin@ Surance Center
转载请注明出处
转载请注明出处