Java
Найдено: 22 записи
Песочница →
JRebel Quickstart
В прошлой статье я немного рассказал о JRebel и для чего его можно использовать. Теперь попробую описать как можно попробовать JRebel использовать, шаг за шагом.
Для примера возьмём приложение Petclinic, исходной код которого можно найти на GitHub. В качестве IDE буду использовать свою любимую IntelliJIDEA.
Для примера возьмём приложение Petclinic, исходной код которого можно найти на GitHub. В качестве IDE буду использовать свою любимую IntelliJIDEA.
10.01.2012 01:11+0400
Песочница →
Микро-ORM своими руками (часть первая)
Что подвигло меня на написание данной библиотеки и чем плохи существующие решения:
К сожалению такие монстры как Hibernate «тяжеловесны» и навязывают свой API для работы с БД. Мне же нужна была простенькая библиотечка, использовать которую можно было бы в перемешку с обычным JDBC-кодом (по сути мне нужно было некоторое подобие Dapper.NET для JDBC).
Основные принципы, используемые при написании библиотеки:
К сожалению такие монстры как Hibernate «тяжеловесны» и навязывают свой API для работы с БД. Мне же нужна была простенькая библиотечка, использовать которую можно было бы в перемешку с обычным JDBC-кодом (по сути мне нужно было некоторое подобие Dapper.NET для JDBC).
Основные принципы, используемые при написании библиотеки:
- простота и атомарность — библиотечка представляет собой 1 java-файл, для добавления в проект достаточно просто добавить файлик к своим исходникам.
- ненавязчивость — библиотечка не навязывает свой API, возможно использование «вперемешку» с обычным JDBC-кодом
- независимость — библиотечка не использует ничего кроме Java SE 5
- расширяемость — библиотечка поддерживает добавление расширений, необходимых для конкретного проекта
08.01.2012 07:08+0400
Песочница →
JRebel
На Хабре несколько раз публиковались статьи, где JRebel либо просто упоминался, либо выкладывалась информация, что вышла новая версия. При этом, не всем читателям было понятно, о чём вообще речь, и как данное ПО работает.
Как непосредственному участнику разработки данного продукта, мне хотелось бы прояснить некоторые моменты, почему JRebel существует и как он может помочь Java-разработчику.
Изначальная проблема известна практически любому разработчику, который работает с Java: после каких-либо изменений в проекте, для того, чтобы увидеть результат, тратится довольно много времени на сборку и развёртывание в контейнере. На Хабре уже публиковались отличные статьи о том, как можно ускорить или автоматизировать процесс разработки, не стану повторяться. Но дело в том, что в упомянутых способах есть свои изъяны: далеко не все изменения возможно перегрузить в развёрнутом приложении штатными средствами; очень легко получить утечки памяти, которые приведут к надобности перезапуска контейнера. Технические детали хорошо расписаны в серии статей в нашем сайте — любопытных приглашаю почитать.
Как выглядит цикл разработки web-приложения, в классическом виде:
1. Сделали изменения в коде (или в ресурсах)
2. Собрали JAR/WAR/EAR
3. Развернули полученный архив в контейнере
4. Открыли развёрнутое приложение, и, после некоторых манипуляций увидели результаты своего труда.
В зависимости от размера приложения, используемого контейнера, и некоторых других факторов, этапы 2, 3 и 4 могут занимать от нескольких секунд, до совершенно невминяемых цифр. Наша компания проводила опрос разработчиков относительно используемых технологий и времени которое затрачивается на развёртывание приложения. Как оказалось, в среднем на развёртывание тратится около 3 минут за раз, и около 10 минут в час. В плачевных случаях, где на развёртывание уходит более полу часа, нет даже смысла спрашивать у человека, сколько раз в час он может повторить этот процесс. Ответ очевиден.
Когда перезапуск контейнера/приложения занимает считанные секунды, проблема, описанная выше, не ощущается так сильно. Однако, по мере роста и усложнения проекта, неудобства дадут о себе знать. Тут то и можно задуматься — может быть JRebel, это то что вам нужно?
Как непосредственному участнику разработки данного продукта, мне хотелось бы прояснить некоторые моменты, почему JRebel существует и как он может помочь Java-разработчику.
Откуда ноги растут?
Изначальная проблема известна практически любому разработчику, который работает с Java: после каких-либо изменений в проекте, для того, чтобы увидеть результат, тратится довольно много времени на сборку и развёртывание в контейнере. На Хабре уже публиковались отличные статьи о том, как можно ускорить или автоматизировать процесс разработки, не стану повторяться. Но дело в том, что в упомянутых способах есть свои изъяны: далеко не все изменения возможно перегрузить в развёрнутом приложении штатными средствами; очень легко получить утечки памяти, которые приведут к надобности перезапуска контейнера. Технические детали хорошо расписаны в серии статей в нашем сайте — любопытных приглашаю почитать.
Куда уходит время?
Как выглядит цикл разработки web-приложения, в классическом виде:
1. Сделали изменения в коде (или в ресурсах)
2. Собрали JAR/WAR/EAR
3. Развернули полученный архив в контейнере
4. Открыли развёрнутое приложение, и, после некоторых манипуляций увидели результаты своего труда.
В зависимости от размера приложения, используемого контейнера, и некоторых других факторов, этапы 2, 3 и 4 могут занимать от нескольких секунд, до совершенно невминяемых цифр. Наша компания проводила опрос разработчиков относительно используемых технологий и времени которое затрачивается на развёртывание приложения. Как оказалось, в среднем на развёртывание тратится около 3 минут за раз, и около 10 минут в час. В плачевных случаях, где на развёртывание уходит более полу часа, нет даже смысла спрашивать у человека, сколько раз в час он может повторить этот процесс. Ответ очевиден.
Когда перезапуск контейнера/приложения занимает считанные секунды, проблема, описанная выше, не ощущается так сильно. Однако, по мере роста и усложнения проекта, неудобства дадут о себе знать. Тут то и можно задуматься — может быть JRebel, это то что вам нужно?
02.01.2012 22:53+0400
Песочница →
Вышел Grails 2.0
После года разработки и трех релиз-кандидатов команда SpringSource презентовала новую версию веб фреймворка — Grails 2.0. Я часто использую Grails в своих проектах и внимательно слежу за процессом разработки и выпуска новых релизов.
Интересно заметить, что изначально релиз планировался под версией Grails 1.4, но фундаментальных изменений оказалось слишком много, и Grails присвоили версию 2.0.
Итак перечислю, что нового появилось в новой реинкарнации Grails:
Интересно заметить, что изначально релиз планировался под версией Grails 1.4, но фундаментальных изменений оказалось слишком много, и Grails присвоили версию 2.0.
Итак перечислю, что нового появилось в новой реинкарнации Grails:
18.12.2011 02:55+0400
Песочница →
@Autowired для сервлетов в OSGi-контейнере
Вместо введения отправляю читателя к отличной статье Использование Spring в OSGi-контейнере которая и послужила отправной точкой для практического изучения.
Итак, к делу. Рассмотрим классический вариант — есть бизнес-логика приложения и она как-то
взаимодействует с внешним миром. Используем такую связку:
клиент <-> транспорт <-> приемник <-> сериализатор/десериализатор <-> метод бизнес логики.
Сериализатор напрашивается заменяемым модулем, например сериализация в JSON или сериализация в XML.
Про бизнес-логику далее можно забыть, и сосредоточиться на связке приемника и сериализатора.
В качестве приемника используем сервлет, а для сериализатора, для простоты, используем реализацию следующего интерфейса:
Итак, к делу. Рассмотрим классический вариант — есть бизнес-логика приложения и она как-то
взаимодействует с внешним миром. Используем такую связку:
клиент <-> транспорт <-> приемник <-> сериализатор/десериализатор <-> метод бизнес логики.
Сериализатор напрашивается заменяемым модулем, например сериализация в JSON или сериализация в XML.
Про бизнес-логику далее можно забыть, и сосредоточиться на связке приемника и сериализатора.
В качестве приемника используем сервлет, а для сериализатора, для простоты, используем реализацию следующего интерфейса:
15.11.2011 20:00+0400
gdev →
Бот для браузерной игры, сетевой подход
Прочитав статьи о ботах решил поделится своим скромным опытом создания бота с помощью Java и использованием сетевого протокола (то есть никаких макросов или внедрений в AS).
Где-то пол года назад я встретил одну довольно популярную игру ВКонтакте — Zonk, сама игра представляет собой вариацию на игру в кости Zilch, и заключается в том, что вам необходимо набрать 10000 очков быстрей своего противника выкидывая на костях различные комбинации.
Введение
Где-то пол года назад я встретил одну довольно популярную игру ВКонтакте — Zonk, сама игра представляет собой вариацию на игру в кости Zilch, и заключается в том, что вам необходимо набрать 10000 очков быстрей своего противника выкидывая на костях различные комбинации.
31.08.2011 20:32+0400
Ни о чём →
JodaTime — учите матчасть, или важность существительных
Нашел у себя баг. Нужно было по некоторой логике получить временной интервал, причем без привязки к конкретным датам, то есть просто обертку вокруг количества милисекунд между некими событиями.
В моем коде я высчитывал startDate и endDate, и возвращал Duration вот таким образом:
Выяснилось, что если startDate и endDate отстояли друг от друга больше, чем на месяц, JodaTime кидал исключение. Решение было найдено быстро:
Починил, и задумался, почему я допустил такой ляп. JodaTime имеет очень богатый набор классов для описания всего, что связано со временем, и мне некогда было разбираться в разнице между Period, Interval, Duration и т.д. И очень зря.
Когда я писал код, в голове вертелось «за отчетный период хлеборобы Кубани убрали и намолотили....». Я, хотя и свободно говорю по-английски, выбрал первый попавшийся класс, похожий на «отчетный период», т.е. Period.
К чему я это все? К тому, как важно правильно называть свои классы/методы/переменные. Почитал я (вовремя, ага, после того, как закончил проект) документацию к JodaTime и позавидовал белой завистью. Ребята приложили кучу усилий к тому, чтобы назвать каждый класс нужным существительным. Interval — это не Period, и понятно почему (ага, теперь понятно). У меня так, к сожалению, получается не всегда. А жаль.
В моем коде я высчитывал startDate и endDate, и возвращал Duration вот таким образом:
return new Period(startDate, endDate).toDuration();
Выяснилось, что если startDate и endDate отстояли друг от друга больше, чем на месяц, JodaTime кидал исключение. Решение было найдено быстро:
return new Interval(startDate, endDate).toDuration();
Починил, и задумался, почему я допустил такой ляп. JodaTime имеет очень богатый набор классов для описания всего, что связано со временем, и мне некогда было разбираться в разнице между Period, Interval, Duration и т.д. И очень зря.
Когда я писал код, в голове вертелось «за отчетный период хлеборобы Кубани убрали и намолотили....». Я, хотя и свободно говорю по-английски, выбрал первый попавшийся класс, похожий на «отчетный период», т.е. Period.
К чему я это все? К тому, как важно правильно называть свои классы/методы/переменные. Почитал я (вовремя, ага, после того, как закончил проект) документацию к JodaTime и позавидовал белой завистью. Ребята приложили кучу усилий к тому, чтобы назвать каждый класс нужным существительным. Interval — это не Period, и понятно почему (ага, теперь понятно). У меня так, к сожалению, получается не всегда. А жаль.
18.08.2011 01:10+0400
humour →
Java Zone возвращается
Люди с конференции Java Zone 2010, которые выпустили трейлер к фильму Java 4-ever снова очень хорошо выступили.
На этот раз – клип Lady Java.
Советую почитать текст, который как бы между делом пролетает на фоне. Например то, что написано на BSoD.
На этот раз – клип Lady Java.
Советую почитать текст, который как бы между делом пролетает на фоне. Например то, что написано на BSoD.
14.08.2010 00:26+0400
humour →
Java 4-ever movie trailer
Трейлер новой волнующей драмы: Java 4-ever. Она рассказывает о том, что делает с семьями программная разработка и куда приводят сражения по поводу платформ.
А ещё это рекламный ролик для конференции JavaZone 2010 которая пройдёт в сентябре в Осло.
А ещё это рекламный ролик для конференции JavaZone 2010 которая пройдёт в сентябре в Осло.
25.06.2010 18:18+0400
humour →
Какой язык учить?
Хочешь программировать на выразительном и мощном языке: Python
Нужно по-быстрому веб-сайт: PHP
Желаешь в тусовку зовущих себя «рок-звездами» программирования: Ruby
Реально нужно научиться программировать: C
Ищешь просветления: Scheme
Уйти в хандру: SQL
Потерять одну хромосому: Microsoft Visual Basic
Для получения постоянной, заурядной, но хорошо оплачиваемой работы по созданию финансовых приложений в офисной загородке под лампами дневного света: Java
Тоже самое, но с аббревиатурами и списком сертификатов в своей подписи: C#
Получить волшебное ощущение детского изумления, которое сложно отличить от мании величия: Objective C
оригинал (en)
Нужно по-быстрому веб-сайт: PHP
Желаешь в тусовку зовущих себя «рок-звездами» программирования: Ruby
Реально нужно научиться программировать: C
Ищешь просветления: Scheme
Уйти в хандру: SQL
Потерять одну хромосому: Microsoft Visual Basic
Для получения постоянной, заурядной, но хорошо оплачиваемой работы по созданию финансовых приложений в офисной загородке под лампами дневного света: Java
Тоже самое, но с аббревиатурами и списком сертификатов в своей подписи: C#
Получить волшебное ощущение детского изумления, которое сложно отличить от мании величия: Objective C
оригинал (en)
07.05.2010 13:21+0400
humour →
Трудовые будни становятся чуточку веселее
public void commitChanges() throws TransformerException, IOException {
Transformer optimusPrime = TransformerFactory.newInstance().newTransformer();
optimusPrime.setOutputProperty(OutputKeys.INDENT, "yes");
StreamResult robot = new StreamResult(file);
DOMSource truck = new DOMSource(documentRoot);
optimusPrime.transform(truck, robot);
logger.info("Commited " + numberOfChanges.get() + " changes to " + file.getName());
numberOfChanges.set(0);
}
* This source code was highlighted with Source Code Highlighter.
Улыбнитесь :)
11.03.2010 23:52+0300
humour →
Трудовые будни становятся чуточку веселее
public void commitChanges() throws TransformerException, IOException {
Transformer optimusPrime = TransformerFactory.newInstance().newTransformer();
optimusPrime.setOutputProperty(OutputKeys.INDENT, "yes");
StreamResult robot = new StreamResult(file);
DOMSource truck = new DOMSource(documentRoot);
optimusPrime.transform(truck, robot);
logger.info("Commited " + numberOfChanges.get() + " changes to " + file.getName());
numberOfChanges.set(0);
}
* This source code was highlighted with Source Code Highlighter.
Улыбнитесь :)
11.03.2010 23:52+0300
Подсознание →
Lego Mindstorms для программиста
Мне очень нравится играть в Lego. Нравится собирать роботов и машинки.
А ещё мне очень нравится програмировать. Нравится писать программы и фреймворки.
А не так давно я нашел способ совместить эти два увлечения. Lego Mindstorms — это набор, включающий в себя несколько моторчиков, сенсоров и программируемый модуль, который может считывать информацию с сенсоров и управлять моторчиками.
В этом посте я расскажу больше о Mindstorms и о способах программирования.
А ещё мне очень нравится програмировать. Нравится писать программы и фреймворки.
А не так давно я нашел способ совместить эти два увлечения. Lego Mindstorms — это набор, включающий в себя несколько моторчиков, сенсоров и программируемый модуль, который может считывать информацию с сенсоров и управлять моторчиками.
В этом посте я расскажу больше о Mindstorms и о способах программирования.
04.11.2009 23:05+0300
development →
Введение в объектно-ориентированные базы данных
Объектно-ориентированные базы данных – базы данных, в которых информация представлена в виде объектов, как в объектно-ориентированных языках программирования.
Применять или не применять объектно-ориентированные системы управления базами данных (ООСУБД) в реальных проектах сегодня? В каких случаях их применять, а в каких нет?
Вот преимущества использования ООСУБД:
В статье описано все, что требуется для начала работы с ООСУБД db4o.
На сегодняшний день db4o – одна из самых популярных объектно-ориентированных систем управления базами данных.
Для начала скачиваем дистрибутив последней версии с сайта db4o (есть версии для Java, .NET 2.0, 3.5). На момент написания статьи последняя версия – 7.9. В дистрибутив также входит Object Manager Enterprise (OME) – полезный плагин для IDE (Eclipse, Visual Studio), который позволяет работать с базой данных автономно. В последнюю продуктивную поставку (на данный момент — 7.4) OME не входит, поэтому для ознакомления c ООСУБД рекомендуется версия 7.9.
Далее в статье для примеров будет использоваться язык C#. Для Java примеры аналогичны, за исключением раздела про LINQ, где необходимым условием является использование .NET 3.5.
После установки db4o в соответствующем месте можно найти отличный tutorial, входящий в комплект. Именно к нему я рекомендую обратиться после прочтения данной статьи, если сама тема покажется вам интересной.
Отмечаю, что все ПО для работы с db4o и сама СУБД бесплатны для некоммерческого использования.
Для проведения экспериментов над db4o создаем в нашей IDE проект любого типа, например, консольное приложение и добавляем ссылки на сборки (пакеты) db4o: Db4objects.Db4o.dll и Db4objects.Db4o.Linq.dll (если требуется).
Чтобы выполнять какие-либо действия над объектной базой в приложении, первым делом необходимо получить объект типа IObjectContainer. Это фасад к базе данных: через него выполняются запросы к БД на выборку, сохранение, добавление и удаление данных.
Способ получения объекта зависит от типа соединения с базой данных.
Самый простой способ – база данных размещается в локальном файле, к которому приложение получает доступ напрямую. Делается это так:
Файл базы данных в этом случае открывается в эксклюзивном режиме и, следовательно, возникают трудности при реализации многопользовательских приложений. Однако такое решение отлично подходит для однопользовательских stand-alone приложений, которые имеют сложную модель данных и которым необходимо сохранять эти данные между запусками приложения. Пример, САПР-приложения.
Следующий способ. Для поддержки многопользовательского режима, то есть возможности существования нескольких IObjectContainer для одной базы данных одновременно, следует использовать клиент-серверную архитектуру. В случае, когда клиент и сервер работают в рамках одного приложения, это делается так:
В данном случае при создании сервера все равно приходится указывать файл базы данных. Это необходимо делать для всех типов подключения к БД — привязка к файлу остается всегда (один файл — одна БД). Кстати, такой файл создается автоматически по первому требованию, если не был создан до этого.
Второй параметр функции OpenServer – номер порта, равный 0, означает, что сервер будет доступен только локальным клиентам, создаваемым с помощью server.OpenClient().
Приведенный пример искусственный. В реальном приложении клиенты, скорее всего, будут открываться в отдельных потоках.
И последний вариант – расширение предыдущего для случая удаленных клиентов.
Этот вариант отличается от предыдущего следующим.
Пусть где-то в нашем приложении объявлен класс User с полями Login, Password и Age, а db – это объект типа IObjectContainer (тот, что мы получили в прошлом разделе).
Это всё! Не требуется заранее или вручную задавать, какие объекты мы можем сохранять в БД, структуру этих объектов или что-либо ещё. При сохранении первого объекта ООСУБД сделает всю работу за нас.
Существует несколько способов выполнить запрос к данным, сохраненным в базе данных.
Применение естественных запросов (Native Queries, NQ) – гибкий, мощный и удобный метод выполнения запросов над данными в ООБД.
Здесь делается запрос к объектам класса User, причем всё, что только можно, в данном примере строго типизировано. Объекты фильтруются таким образом, чтобы удовлетворять условию: возраст пользователя больше или равен 18 и имя пользователя начинается с заглавной буквы «V». Вместо лямбда-выражения функции Query можно передавать делегаты или объекты типа Predicate<T>. Predicate<T> — интерфейс, содержащий единственную функцию Match, принимающую параметр типа T и возвращающую bool. Query вернет те объекты, для которых Match возвращает true.
Концепция ООБД отлично ложиться на идею использования интегрированных в язык запросов (LINQ).
Перепишем предыдущий запрос с использованием LINQ.
Запрос опять же строго типизирован и легко поддается рефакторингу.
Существуют и другие методы выполнения запросов, кроме NQ и LINQ.
Перед тем как обновить объект, извлечем его из БД, затем изменим его и сохраним обратно.
Удаление объектов происходит аналогично:
До этого момента мы рассматривали, как работать с достаточно простыми объектами User, которые содержали только поля элементарных типов (string и int). Однако объекты могут быть составными и ссылаться на другие объекты. Например, в классе User может быть объявлено поле friends (друзья пользователя):
Все операции с таким классом производятся также, как и раньше – составное поле корректно сохраняется в БД, однако есть некоторые особенности.
Допустим, мы пытаемся загрузить из БД объект одного конкретного пользователя (User), как это делалось в прошлом разделе. Если загружен сам пользователь, то должны загрузиться и его друзья, дальше – друзья его друзей, и так далее. Это может закончиться тем, что придется загрузить в память все объекты User или даже, если у User есть ссылки на объекты других типов, всю базу данных целиком. Естественно, такой эффект нежелателен. Поэтому, по умолчанию загружаются только сами объекты выборки и объекты, на которые они ссылаются, до 5-го уровня вложенности включительно. Для некоторых ситуаций это много, для других – мало. Существует способ настроить этот параметр, называемый глубиной активации (activation depth).
Здесь приведены примеры, устанавливающие глубину активации как для всех сразу, так и для отдельного класса. Функция Ext() возвращает расширенный объект IExtObjectContainer для доступа к продвинутым функциям вроде настроек конфигурации базы данных. Это сделано для удобства, чтобы не засорять основной интерфейс IObjectContainer.
В случае, когда запрос уже отработал, но каких-либо данных не хватает, то есть не все нужные данные были активированы (загружены в память), можно использовать метод Activate, применительно к отдельному хранимому объекту:
Во многом похожая проблема возникает при сохранении составных объектов. По умолчанию сохраняются только поля самого объекта, но не объектов, на которые он ссылается. То есть, глубина обновления (update depth) по умолчанию равна 1. Изменить её можно следующим образом:
В случае удаления объекта, по умолчанию также не происходит каскадного удаления: объекты, на которые ссылался удаленный объект, остаются. Настраивать поведение СУБД в случае удаления объектов можно следующим образом:
Понятия «глубины удаления» не предусмотрено.
Каждый раз, когда открывается контейнер (IObjectContainer), неявным образом создается контекст транзакции. При выполнении операции Close автоматически происходит commit текущей транзакции.
Для более гибкого управления транзакциями в интерфейсе IObjectContainer присутствуют два метода:
Цель данной статьи — показать, что имеется очень мощная альтернатива существующим подходам к разработке с использованием реляционных СУБД. Сам по себе подход, использующий объектные базы данных, очень современен – это СУБД, которая не отстает от основных тенденций, наблюдаемых в развитии языков программирования, таких как Java и C#.
В статье достаточно материала, чтобы начать работать с ООСУБД, создавая реальные приложения. Однако многие вопросы здесь затронуты не были, например, вопросы, связанные с производительностью и разработкой веб-приложений.
В любом случае, если и не начать применять объектные СУБД на практике уже сегодня, то стоит хотя бы задуматься, не лучшее ли это решение для вашего проекта?
Применять или не применять объектно-ориентированные системы управления базами данных (ООСУБД) в реальных проектах сегодня? В каких случаях их применять, а в каких нет?
Вот преимущества использования ООСУБД:
- Отсутствует проблема несоответствия модели данных в приложении и БД (impedance mismatch). Все данные сохраняются в БД в том же виде, что и в модели приложения.
- Не требуется отдельно поддерживать модель данных на стороне СУБД.
- Все объекты на уровне источника данных строго типизированы. Больше никаких строковых имен колонок! Рефакторинг объектно-ориентированной базы данных и работающего с ней кода теперь автоматизированный, а не однообразный и скучный процесс.
В статье описано все, что требуется для начала работы с ООСУБД db4o.
Установка db4o
На сегодняшний день db4o – одна из самых популярных объектно-ориентированных систем управления базами данных.
Для начала скачиваем дистрибутив последней версии с сайта db4o (есть версии для Java, .NET 2.0, 3.5). На момент написания статьи последняя версия – 7.9. В дистрибутив также входит Object Manager Enterprise (OME) – полезный плагин для IDE (Eclipse, Visual Studio), который позволяет работать с базой данных автономно. В последнюю продуктивную поставку (на данный момент — 7.4) OME не входит, поэтому для ознакомления c ООСУБД рекомендуется версия 7.9.
Далее в статье для примеров будет использоваться язык C#. Для Java примеры аналогичны, за исключением раздела про LINQ, где необходимым условием является использование .NET 3.5.
После установки db4o в соответствующем месте можно найти отличный tutorial, входящий в комплект. Именно к нему я рекомендую обратиться после прочтения данной статьи, если сама тема покажется вам интересной.
Отмечаю, что все ПО для работы с db4o и сама СУБД бесплатны для некоммерческого использования.
Cоединение с БД
Для проведения экспериментов над db4o создаем в нашей IDE проект любого типа, например, консольное приложение и добавляем ссылки на сборки (пакеты) db4o: Db4objects.Db4o.dll и Db4objects.Db4o.Linq.dll (если требуется).
Чтобы выполнять какие-либо действия над объектной базой в приложении, первым делом необходимо получить объект типа IObjectContainer. Это фасад к базе данных: через него выполняются запросы к БД на выборку, сохранение, добавление и удаление данных.
Способ получения объекта зависит от типа соединения с базой данных.
Самый простой способ – база данных размещается в локальном файле, к которому приложение получает доступ напрямую. Делается это так:
// получаем доступ к файлу БД
IObjectContainer db = Db4oFactory.OpenFile(filename);
try
{
// работаем с ООБД
}
finally
{
// закрываем файл, освобождаем ресурсы
db.Close();
}
* This source code was highlighted with Source Code Highlighter.
Файл базы данных в этом случае открывается в эксклюзивном режиме и, следовательно, возникают трудности при реализации многопользовательских приложений. Однако такое решение отлично подходит для однопользовательских stand-alone приложений, которые имеют сложную модель данных и которым необходимо сохранять эти данные между запусками приложения. Пример, САПР-приложения.
Следующий способ. Для поддержки многопользовательского режима, то есть возможности существования нескольких IObjectContainer для одной базы данных одновременно, следует использовать клиент-серверную архитектуру. В случае, когда клиент и сервер работают в рамках одного приложения, это делается так:
// создаем сервер
IObjectServer server = Db4oFactory.OpenServer(filename, 0);
try
{
// подключаем клиентов
IObjectContainer client = server.OpenClient();
IObjectContainer client2 = server.OpenClient();
// работаем с ООБД через экземпляры IObjectContainer
client.Close();
client2.Close();
}
finally
{
// закрываем файл, освобождаем ресурсы сервера
server.Close();
}
* This source code was highlighted with Source Code Highlighter.
В данном случае при создании сервера все равно приходится указывать файл базы данных. Это необходимо делать для всех типов подключения к БД — привязка к файлу остается всегда (один файл — одна БД). Кстати, такой файл создается автоматически по первому требованию, если не был создан до этого.
Второй параметр функции OpenServer – номер порта, равный 0, означает, что сервер будет доступен только локальным клиентам, создаваемым с помощью server.OpenClient().
Приведенный пример искусственный. В реальном приложении клиенты, скорее всего, будут открываться в отдельных потоках.
И последний вариант – расширение предыдущего для случая удаленных клиентов.
// создаем сервер
IObjectServer server = Db4oFactory.OpenServer(filename, serverPort);
server.GrantAccess(serverUser, serverPassword);
try
{
IObjectContainer client = Db4oFactory.OpenClient("localhost", serverPort,
serverUser, serverPassword);
// работаем с ООБД
client.Close();
}
finally
{
server.Close();
}
* This source code was highlighted with Source Code Highlighter.
Этот вариант отличается от предыдущего следующим.
- Указывается реальное значение порта, который будет прослушивать сервер (используется TCP/IP) при вызове OpenServer.
- Указываются авторизационные данные для доступа к БД.
- Клиент создается с использованием Db4oFactory.OpenClient и, таким образом, это может происходить не только в другом потоке, но и совершенно в другом приложении, запущенном на удаленной машине.
Работа с данными
Пусть где-то в нашем приложении объявлен класс User с полями Login, Password и Age, а db – это объект типа IObjectContainer (тот, что мы получили в прошлом разделе).
Сохранение объекта (INSERT)
User user1 = new User("Vasya", "123456", 25);
db.Store(user1);
* This source code was highlighted with Source Code Highlighter.
Это всё! Не требуется заранее или вручную задавать, какие объекты мы можем сохранять в БД, структуру этих объектов или что-либо ещё. При сохранении первого объекта ООСУБД сделает всю работу за нас.
Запросы к данным (SELECT)
Существует несколько способов выполнить запрос к данным, сохраненным в базе данных.
Применение естественных запросов (Native Queries, NQ) – гибкий, мощный и удобный метод выполнения запросов над данными в ООБД.
IList<User> result = db.Query<User>(usr => usr.Age >= 18
&& usr.Login.StartsWith("V"));
* This source code was highlighted with Source Code Highlighter.
Здесь делается запрос к объектам класса User, причем всё, что только можно, в данном примере строго типизировано. Объекты фильтруются таким образом, чтобы удовлетворять условию: возраст пользователя больше или равен 18 и имя пользователя начинается с заглавной буквы «V». Вместо лямбда-выражения функции Query можно передавать делегаты или объекты типа Predicate<T>. Predicate<T> — интерфейс, содержащий единственную функцию Match, принимающую параметр типа T и возвращающую bool. Query вернет те объекты, для которых Match возвращает true.
Концепция ООБД отлично ложиться на идею использования интегрированных в язык запросов (LINQ).
Перепишем предыдущий запрос с использованием LINQ.
IEnumerable<User> result = from User usr in db
where usr.Age >= 18 && usr.Login.StartsWith("V")
select usr;
* This source code was highlighted with Source Code Highlighter.
Запрос опять же строго типизирован и легко поддается рефакторингу.
Существуют и другие методы выполнения запросов, кроме NQ и LINQ.
- Запросы по образцу (query by example). Самый простой, но недостаточно мощный способ. Выборка данных осуществляется на основе сопоставления с заранее подготовленным экземпляром объекта — образцом. Результат-выборка не является строго типизированной. Сложно представить ситуации, когда этот метод может оказаться полезным.
- SODA. Низкоуровневый язык запросов, с которым работает db4o. Запросы, использующие синтаксис SODA, не безопасны с точки зрения типов, не строго типизированы, занимают много места, но зато максимально гибки и позволяют отточить производительность приложения там, где это требуется.
Обновление объектов (UPDATE)
Перед тем как обновить объект, извлечем его из БД, затем изменим его и сохраним обратно.
User usr = db.Query<User>(usr => usr.Login == "Vasya")[0];
usr.SetPassword("111111");
db.Store(usr);
* This source code was highlighted with Source Code Highlighter.
Удаление объектов (DELETE)
Удаление объектов происходит аналогично:
User usr = db.Query<User>(usr => usr.Login == "Vasya")[0];
db.Delete(usr);
* This source code was highlighted with Source Code Highlighter.
Составные объекты
До этого момента мы рассматривали, как работать с достаточно простыми объектами User, которые содержали только поля элементарных типов (string и int). Однако объекты могут быть составными и ссылаться на другие объекты. Например, в классе User может быть объявлено поле friends (друзья пользователя):
public class User
{
// ...
IList<User> friends = new List<User>();
}
* This source code was highlighted with Source Code Highlighter.
Все операции с таким классом производятся также, как и раньше – составное поле корректно сохраняется в БД, однако есть некоторые особенности.
Допустим, мы пытаемся загрузить из БД объект одного конкретного пользователя (User), как это делалось в прошлом разделе. Если загружен сам пользователь, то должны загрузиться и его друзья, дальше – друзья его друзей, и так далее. Это может закончиться тем, что придется загрузить в память все объекты User или даже, если у User есть ссылки на объекты других типов, всю базу данных целиком. Естественно, такой эффект нежелателен. Поэтому, по умолчанию загружаются только сами объекты выборки и объекты, на которые они ссылаются, до 5-го уровня вложенности включительно. Для некоторых ситуаций это много, для других – мало. Существует способ настроить этот параметр, называемый глубиной активации (activation depth).
// глубина активации глобально для всех классов
db.Ext().Configure().ActivationDepth(2);
// глубина активации для класса User
db.Ext().Configure().ObjectClass(typeof(User)).MinimumActivationDepth(3);
db.Ext().Configure().ObjectClass(typeof(User)).MaximumActivationDepth(4);
// каскадная активация для объектов User (нет ограничения на глубину)
db.Ext().Configure().ObjectClass(typeof(User)).CascadeOnActivate(true);
* This source code was highlighted with Source Code Highlighter.
Здесь приведены примеры, устанавливающие глубину активации как для всех сразу, так и для отдельного класса. Функция Ext() возвращает расширенный объект IExtObjectContainer для доступа к продвинутым функциям вроде настроек конфигурации базы данных. Это сделано для удобства, чтобы не засорять основной интерфейс IObjectContainer.
В случае, когда запрос уже отработал, но каких-либо данных не хватает, то есть не все нужные данные были активированы (загружены в память), можно использовать метод Activate, применительно к отдельному хранимому объекту:
// первый параметр – активируемый объект, второй – глубина активации
db.Activate(usr, 5);
* This source code was highlighted with Source Code Highlighter.
Во многом похожая проблема возникает при сохранении составных объектов. По умолчанию сохраняются только поля самого объекта, но не объектов, на которые он ссылается. То есть, глубина обновления (update depth) по умолчанию равна 1. Изменить её можно следующим образом:
// глубина обновления глобально для всех классов
db.Ext().Configure().UpdateDepth(2);
// глубина обновления для класса User
db.Ext().Configure().ObjectClass(typeof(User)).UpdateDepth(3);
// каскадное обновление для объектов User (нет ограничений на вложенность)
db.Ext().Configure().ObjectClass(typeof(User)).CascadeOnUpdate(true);
* This source code was highlighted with Source Code Highlighter.
В случае удаления объекта, по умолчанию также не происходит каскадного удаления: объекты, на которые ссылался удаленный объект, остаются. Настраивать поведение СУБД в случае удаления объектов можно следующим образом:
// каскадное удаление (нет ограничений на вложенность)
db.Ext().Configure().ObjectClass(typeof(User)).CascadeOnDelete(true);
* This source code was highlighted with Source Code Highlighter.
Понятия «глубины удаления» не предусмотрено.
Транзакции
Каждый раз, когда открывается контейнер (IObjectContainer), неявным образом создается контекст транзакции. При выполнении операции Close автоматически происходит commit текущей транзакции.
Для более гибкого управления транзакциями в интерфейсе IObjectContainer присутствуют два метода:
- Commit(). Явное завершение транзакции (commit) с записью всех изменений в БД.
- Rollback(). Откат транзакции – изменения произошедшие с момента открытия транзакции (контейнера) не будут зафиксированы в БД.
Заключение
Цель данной статьи — показать, что имеется очень мощная альтернатива существующим подходам к разработке с использованием реляционных СУБД. Сам по себе подход, использующий объектные базы данных, очень современен – это СУБД, которая не отстает от основных тенденций, наблюдаемых в развитии языков программирования, таких как Java и C#.
В статье достаточно материала, чтобы начать работать с ООСУБД, создавая реальные приложения. Однако многие вопросы здесь затронуты не были, например, вопросы, связанные с производительностью и разработкой веб-приложений.
В любом случае, если и не начать применять объектные СУБД на практике уже сегодня, то стоит хотя бы задуматься, не лучшее ли это решение для вашего проекта?
03.04.2009 23:25+0400
humour →
Какой язык учить?
Хочешь программировать на выразительном и мощном языке: Python
Нужно по-быстрому веб-сайт: PHP
Желаешь в тусовку зовущих себя «рок-звездами» программирования: Ruby
Реально нужно научиться программировать: C
Ищешь просветления: Scheme
Уйти в хандру: SQL
Потерять одну хромосому: Microsoft Visual Basic
Для получения постоянной, заурядной, но хорошо оплачиваемой работы по созданию финансовых приложений в офисной загородке под лампами дневного света: Java
Тоже самое, но с аббревиатурами и списком сертификатов в своей подписи: C#
Получить волшебное ощущение детского изумления, которое сложно отличить от мании величия: Objective C
оригинал (en)
Нужно по-быстрому веб-сайт: PHP
Желаешь в тусовку зовущих себя «рок-звездами» программирования: Ruby
Реально нужно научиться программировать: C
Ищешь просветления: Scheme
Уйти в хандру: SQL
Потерять одну хромосому: Microsoft Visual Basic
Для получения постоянной, заурядной, но хорошо оплачиваемой работы по созданию финансовых приложений в офисной загородке под лампами дневного света: Java
Тоже самое, но с аббревиатурами и списком сертификатов в своей подписи: C#
Получить волшебное ощущение детского изумления, которое сложно отличить от мании величия: Objective C
оригинал (en)
30.11.1999 00:00+0300