Путеводитель по db4о для Java-разработчика: Транзакции, распределенный доступ и безопасность

Путеводитель по db4о для Java-разработчика: Транзакции, распределенный доступ и безопасность

В предыдущих статьях серии я освещал основы объектно-ориентированной работы с данными в db4o. Одним из вопросов, которые я обошел вниманием, является использование ООСУБД в Web-приложениях и чем оно отличается от использования в приложениях Swing или SWT. Кто-то может сказать, что я проигнорировал целый круг вопросов, которые обязан знать любой .NET- или Java-разработчик.

Дело в том, что я хотел сосредоточиться на наиболее привлекательных возможностях ООСУБД: объектно-ориентированном хранении, манипулировании и выборке данных. К тому же поставщики ООСУБД как правило реализуют базовые функции, такие как управление транзакциями и обеспечение безопасности, аналогично РСУБД, предоставляя столь же широкий набор опций.

В этой статье — последней части серии «Руководство db4о для Java-разработчика» — я расскажу о возможностях, которые должны присутствовать в любой системе для хранения данных, будь то объектно-ориентированная, реляционная или какая-либо еще. Вздохните поглубже и приготовьтесь слушать про обеспечение безопасности, распределенный доступ и транзакционность в db4o.

Поддержка множественных соединений

В примерах всех предыдущих частей подразумевалось, что только одно клиентское приложение будет работать с базой данных. Поэтому будет достаточно всего одного логического соединения, через которое будет проходить весь обмен данными. Это вполне логичное допущение для приложения Swing или SWT, работающего с базой данных настроек или локальным хранилищем. Но это гораздо менее реалистично для Web-приложения, даже если допустить, что все данные будут храниться в слое Web-представления.

В db4o открытие дополнительного логического соединения с базой данных является тривиальной задачей, даже если база данных расположена на локальном диске. Все, что требуется – это создать объект ObjectServer и получить от него экземпляр класса ObjectContainer. Если указать объекту ObjectServer, чтобы он ожидал входящие соединения через порт 0, то он будет работать во «встроенном» (embedded) режиме. Таким образом, в нашем пробном тесте он не будет открывать реальные порты TCP/IP, что могло бы помешать другим приложениям (листинг 1).

Листинг 1. Множественные соединения во встраиваемом режиме
@Test public void letsTryMultipleEmbeddedClientConnections()
{
ObjectServer server = Db4o.openServer(«persons.data», 0);

try
{
ObjectContainer client1 = server.openClient();
Employee ted1 = (Employee)
client1.get(
new Employee(«Ted», «Neward», null, null, 0, null))
.next();
System.out.println(«client1 found ted: » + ted1);

ObjectContainer client2 = server.openClient();
Employee ted2 = (Employee)
client2.get(
new Employee(«Ted», «Neward», null, null, 0, null))
.next();
System.out.println(«client2 found ted: » + ted2);

ted1.setTitle(«Lord and Most High Guru»);
client1.set(ted1);
System.out.println(«set(ted1)»);

System.out.println(«client1 found ted1: » +
client1.get(
new Employee(«Ted», «Neward», null, null, 0, null))
.next());

System.out.println(«client2 found ted2: » +
client2.get(
new Employee(«Ted», «Neward», null, null, 0, null))
.next());

client1.commit();
System.out.println(«client1.commit()»);

System.out.println(«client1 found ted1: » +
client1.get(
new Employee(«Ted», «Neward», null, null, 0, null))
.next());

System.out.println(«client2 found ted2: » +
client2.get(
new Employee(«Ted», «Neward», null, null, 0, null))
.next());

client2.ext().refresh(ted2, 1);
System.out.println(«After client2.refresh()»);
System.out.println(«client2 found ted2: » +
client2.get(
new Employee(«Ted», «Neward», null, null, 0, null))
.next());

client1.close();
client2.close();
}
finally
{
server.close();
}
}

Обновление представления объектов

Обратите внимание на строки для отладочного вывода в середине тестового примера. Очень важно постоянно контролировать состояние объектов, потому что db4o хранит ссылки на объекты, доступ к которым был получен ранее. Необходимо точно знать, как и когда изменения в данных объектах становятся видимыми для второго клиента.

Например, после вызова метода set(ted1) db4o помечает объект ted1 как «грязный» и требующий обновления. Но само обновление не происходит до момента подтверждения неявной транзакции с помощью вызова commit() класса ObjectContainer. В этот момент данные сохраняются на диске, но client2 по-прежнему видит предыдущее состояние объектов. Убедитесь в этом, просмотрев отладочный вывод демонстрационного тестового примера. Ведь вместе с браузером у вас открыто и окно консоли, в котором вы запускаете тесты, читая статьи этой серии, не так ли?

С этой проблемой легко справиться: client2 должен обновить свое представление графа объектов в памяти, вызвав метод refresh() объекта extension, который можно получить с помощью метода ext(). При этом необходимо помнить о глубине активации: она определяет, насколько далеко db4o должен углубиться в граф, обновляя состояние объектов. В нашем случае достаточно глубины, равной единице, но вообще решение должно приниматься с учетом конкретной ситуации.

client2 увидит изменения сразу после обновления представления объектов. В этом легко убедиться, выполнив запрос, возвращающий новое имя главы компании (возможно, оно выглядит несколько эгоистично).

 

Комментарии

Комментариев пока нет. Почему бы ’Вам не начать обсуждение?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *