Apache Empire-db

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 01:02, 21 января 2019.
Apache Empire-db
Логотип
Разработчики: Apache Software Foundation
Выпущена: 2.0.0 / 11 Января, 2008
Постоянный выпуск: 2.4.7 / 31 Октября, 2018
Предыдущий выпуск: 2.4.6 / 17 Января, 2017
Состояние разработки: Активное
Написана на: Java
Операционная система: Кросс-платформенное
Локализация: Английский
Тип ПО: Фреймворк с открытым исходным кодом
Лицензия: Apache License 2.0
Веб-сайт http://empire-db.apache.org/

Apache Empire-db - это мощный уровень абстракции реляционных баз данных (библиотека Java), предоставляющий объектно-ориентированный API высокого уровня для доступа к РСУБД через JDBC. Apache Empire-db имеет открытый исходный код, который предоставляется по лицензии Apache 2.0 от Apache Software Foundation. По сравнению с объектно-реляционным отображением (ORM) или другими решениями для постоянных данных, такими как Hibernate, iBATIS или TopLink, в Empire-db не используются XML-файлы или Java-аннотации. Вместо этого, в ней используется простая объектная модель Java для описания: базовой модели данных и API, который работает исключительно со ссылками на объект, а не со строковыми литералами.

Описание

Основная цель Empire-db заключается в обеспечении лучшего качества программной среды и повышения надежности её использования за счёт усиления безопасности во время компиляции (использование ссылок на объекты таблиц и столбцов повышает безопасность во время компиляции) и сокращения избыточности за счёт использования метаданных. Кроме того, по сравнению с большинством решений OR-mapping, приложения, функционирующие с Empire-db могут извлечь большую выгоду из-за повышения производительности за счёт полного контроля над операторами SQL и за счет наблюдения за их выполнением разработчиком. Благодаря уникальному интуитивно понятному, командному API без строк, Вы можете создавать практически любые операции выбора, вставки, обновления или удаления данных исключительно с помощью методов Java, независимо от предназначенной для этого СУБД (независимость от СУБД достигается при помощи встраиваемой модели драйвера). Объекты базы данных управляются через динамические компоненты Java, что позволяет изменять модели данных динамически, т.е. во время выполнения.

История

Empire-db была первоначально разработана в немецкой компании по разработке программного обеспечения ESTEAM Software, которая использовала Empire-db для создания приложений для разных отраслей. В январе 2008 года Empire-db был официально открыт и была впервые опубликована первая версия Empire-db 2.0.0 на SourceForge.net, которая стала первым выпуском немецкой компании ESTEAM Software. В июне 2008 года в Apache Software Foundation было подано предложение для Empire-db стать проектом Apache Incubator. В июле 2008 года Empire-db был принят как проект Apache Incubator, и все права на программное обеспечение данного продукта были переданы Apache Foundation. В октябре 2008 года Empire-db 2.0.4 стал первым официальным выпуском Apache Empire-db, в котором, начиная с org.apache.empire, все имена пакетов были изменены.[Источник 1]

Основные преимущества

Ниже представлены главные преимущества Apache Empire-db:

  • Максимальная безопасность во время компиляции по принципу написания кода без строк. Это приводит к улучшению качества кода и повышает его надежность;
  • Поддержка метаданных сокращает избыточность на всех уровнях реализации;
  • Неограниченное использование SQL-возможностей помогает повысить производительность приложений, сохраняя при этом полную переносимость баз данных;
  • Повышение производительности за счет использования IDE с функцией автозавершения кода для динамического создания запросов и доступа к метаданным;
  • Легкий в освоении, интуитивно приближенный к SQL командный API.

Особенности

Главные отличительные особенности Apache Empire-db довольно-таки значительны и постоянно дополняются, вот их примерный список:

  • Apache Empire-db при работе с объектами БД не использует XML-файлы или Java-аннотации, а использует только простой Java-объект (POJO);
  • Полный контроль над соединением с БД и проведением операций (транзакций) с "нулевой конфигурацией" - т.е. с максимально простой настройкой;
  • Независимая от СУБД модель данных, используемая в Empire-db, сохраняет код переносимым ко всем SQL - базам данных;
  • Возможность расширения метаданных через стандартный Java-код;
  • Типобезопасный API для генерации динамических SQL-команд позволяет Вам создавать практически любые SQL-запросы;
  • Результаты запроса и другие данных могут быть альтернативно получены в формате XML;
  • Apache Empire-db работает с динамическими компонентами и предоставляет безопасный доступ к полям. Также предоставляется специальная поддержка обмена данными с JavaBeans / POJO;
  • Для обновления измененных полей присутствует автоматическое отслеживание их состояния (произошла ли новая запись или какая-то модификация поля);
  • Поддержка изменений модели данных (DDL) во время выполнения при помощи динамических компонентов.[Источник 2]

Инструкция по работе с Apache Empire-db

Эта инструкция даёт представление о том, как работать с Empire-db и выполнять наиболее распространенные, основные действия с данными, такие как: вставка, обновление и удаление записей, а также выполнение запросов. Пример приложения, используемого для этого руководства, поставляется с дистрибутивом Empire-db и расположен в каталоге examples/DBSample. Если вы используете Eclipse IDE, то существует также файл проекта Eclipse, позволяющий сразу открыть проект. В среде отладки IDE установите точку останова в первой строке основной функции в SampleApp.java и отладьте пример. Данный пример работает с базой данных HSQL, которая поставляется с файлами дистрибутива, и позволяет приложению работать "без изменений, без доработок пользователя". Однако его можно легко перенастроить для работы с базой данных Microsoft SQL-Server или Oracle, изменив конфигурацию.XML-файла.

Данная инструкция даёт объяснение следующим вещам:

  • Как объявить модель данных с использованием классов и объектов Java;
  • Как сгенерировать DDL-скрипт из описания модели данных и создать все объекты базы данных на сервере;
  • Как вставлять, обновлять и удалять отдельные записи;
  • Как выполнить запрос к базе данных, включая операции соединения (Joins) и ограничения (Constraints);
  • Как получить доступ к результатам запроса последовательно или построчно, в виде списка компонентов или в виде XML-документа.

Загрузка демонстрационного приложения

Загрузить приложение-образец и поэкспериментировать с ним можно по данной ссылке.

Структура демонстрационного приложения

Данное приложение-образец состоит из четырех файлов:

  1. SampleDB.java - это файл описания базы данных, содержащий макет (модель) базы данных с таблицами, индексами, отношениями, представлениями и т.д.
  2. SampleApp.java - этот файл содержит класс основного метода приложения, который вызывает другие методы для выполнения отдельных задач. Здесь нужно установить точку останова для пошагового выполнения приложения при помощи отладчика.
  3. SampleConfig.java - этот класс обеспечивает доступ к параметрам конфигурации, которые считываются из конфигурационного файла config.XML.
  4. SampleBean.java - этот класс используется для хранения результатов запроса в виде простого простого Java-объекта (POJO). Свойства этого класса содержат только поля запроса, а не все поля полной сущности базы данных.

Примечание: для того, чтобы запустить образец в системе базы данных, отличной от HSQLDB, сначала необходимо добавить соответствующий драйвер JDBC в путь к классам (classpath). После этого необходимо соответствующим образом изменить параметры поставщика базы данных и соединения JDBC в файле config.xml.

 1 <properties>
 2 <!-- provider name must match the property-section containing the connection data -->
 3     <databaseProvider>hsqldb</databaseProvider>
 4 </properties>
 5 <properties-hsqldb>
 6     <!-- jdbc properties -->
 7     <jdbcClass>org.hsqldb.jdbcDriver</jdbcClass>
 8     <jdbcURL>jdbc:hsqldb:file:hsqldb/sample;shutdown=true</jdbcURL>
 9     <jdbcUser>sa</jdbcUser>
10     <jdbcPwd></jdbcPwd>
11     <schemaName>DBSAMPLE</schemaName>
12 </properties-hsqldb>

В проекте Вы также можете найти подкаталог с именем «output», который содержит выходные данные отдельных этапов этой инструкции.

Определение модели данных (SampleDB.java)

Для определения модели данных создается класс «database» с именем SampleDB, который наследуется от de.esteam.empire.db.DBDatabase. Все таблицы (и, возможно, представления) модели данных объявляются как поля класса public final, которые назначаются соответствующей таблице или объекту представления. Кроме того, в конструкторе добавлена связь внешнего ключа из таблицы employees с таблицей departments.

 1 public class SampleDB extends DBDatabase {
 2 
 3     // Table class definition (see below)
 4     public static class Departments extends DBTable {... } 
 5     public static class Employees extends DBTable {... }
 6 
 7     // Table members
 8     public final Departments  DEPARTMENTS = new Departments(this);
 9     public final Employees    EMPLOYEES   = new Employees(this);
10 
11     // SampleDB constructor
12     public SampleDB()
13     {
14         // Define foreign key relations
15         addRelation(EMPLOYEES.DEPARTMENT_ID
16                 .referenceOn(DEPARTMENTS.DEPARTMENT_ID ));
17     }
18 }

В нашем примере мы создаем отдельный класс для каждой из двух таблиц. Однако вместо обычных классов, мы будем использовать вложенные классы. Хотя это и не обязательно, это удобный способ хранения всей модели данных в одном файле.

 1 public final class Employees extends DBTable
 2 {
 3     public DBTableColumn EMPLOYEE_ID;
 4     public DBTableColumn LASTNAME;
 5     public DBTableColumn GENDER;
 6     ...
 7     // Constructor for the table
 8     public Employees(DBDatabase db)
 9     {
10        super("EMPLOYEES", db);
11        // ID
12        EMPLOYEE_ID = addColumn("EMPLOYEE_ID", DataType.AUTOINC,  0, true, "EMPLOYEE_ID_SEQUENCE");
13        LASTNAME    = addColumn("LASTNAME",    DataType.TEXT,    40, true);
14        GENDER      = addColumn("GENDER",      DataType.TEXT,     1, false);
15        ...
16        // Primary key
17        setPrimaryKey(EMPLOYEE_ID);
18        // Set other indeces
19        addIndex("EMPLOYEE_NAME_IDX", true, 
20             new DBColumn[] { FIRSTNAME, LASTNAME, DATE_OF_BIRTH });
21        // Set timestamp column to save updates
22        setTimestampColumn(UPDATE_TIMESTAMP);
23         
24        // Create Options for GENDER column
25        Options genders = new Options();
26        genders.set("M", "Male");
27        genders.set("F", "Female");
28        GENDER.setOptions(genders);    
29     }    
30 }

В конструкторе каждого класса таблицы мы добавляем столбцы и назначаем объект столбца в поле класса public final. Это позволит нам просматривать и получать доступ к объектам столбцов непосредственно из нашего исходного кода. После этого, мы устанавливаем первичный ключ, добавляем другие индексы и устанавливаем поле метки времени. Также, здесь добавляются дополнительные метаданные столбцов (но они могут быть добавлены и в других местах).

Empire-db SampleApp

При запуске демонстрационного приложения точкой входа является основной метод, находящийся в SampleApp.java. Это позволит проделать следующие шаги:

Установка соединения с базой данных и её открытие

Сначала приложение должно создать соединение базы данных с её сервером. Для этого jdbcClass, jdbcURL, jdbcUser и jdbcPwd должны быть представлены со своей конфигурацией в файле config.xml. Файл конфигурации анализируется и считывается с помощью вызова функции config.init(). Чтобы использовать другой файл конфигурации, имя файла может быть основной функции в качестве аргумента. После этого создается JDBC - соединение.

1 // Init Configuration
2 config.init((args.length > 0 ? args[0] : "config.xml"));
3 // STEP 1: Get a JDBC Connection
4 Connection conn = getJDBCConnection();

На втором шаге создается и инициализируется объект драйвера базы данных для целевой СУБД. По умолчанию это HSQLDB.

1 // STEP 2: Choose a driver
2 DBDatabaseDriver driver = getDatabaseDriver(config.getDatabaseProvider());

Затем, на третьем шаге, при помощи драйвера открывается объект базы данных и мы проверяем, содержит ли этот объект какие-нибудь таблицы или нет. Только после открытия можно использовать другие методы объекта базы данных.

1 // STEP 3: Open Database and check if tables exist
2 db.open(driver, conn);
3 databaseExists(conn);

Чтобы проверить наличие базы данных, образец просто выполняет запрос к таблице Departments ("select count(*) from DEPARTMENTS"), используя следующий код:

1 DBCommand cmd = db.createCommand();
2 cmd.select(db.DEPARTMENTS.count());
3 db.querySingleInt(cmd.getSelect(), -1, conn);

Если выбор выполнен успешно, предполагается, что база данных существует, и шаг 4 пропускается. В противном случае, на шаге 4 создаются все объекты базы данных.

Создание скрипта DDL и объектов базы данных

На основе определения базы данных в классе SampleDB.java, генерируется сценарий DDL всей базы данных для создания всех таблиц, последовательностей, индексов и отношений.

1 // create DLL for Database Definition 
2 String ddlScript = db.getCreateDDLScript(driver);

Теперь отдельные команды DDL извлекаются и выполняются построчно с помощью метода драйвера executesql().

Примечание: если Вы хотите создать или удалить отдельные объекты базы данных, такие как таблицы, представления, столбцы и отношения, Вы можете получить для этого соответствующий SQL, вызвав метод драйвера driver.getDDLCommand().

Удаление данных

На этом шаге происходит очистка двух таблиц базы данных путем удаления всех записей данных:

1 DBCommand cmd = db.createCommand();
2 // Delete all Employees (no constraints)
3 db.executeSQL(cmd.getDelete(db.EMPLOYEES), conn);
4 // Delete all Departments (no constraints)
5 db.executeSQL(cmd.getDelete(db.DEPARTMENTS), conn);

Вставка данных

На этом шаге мы добавим примеры записей для таблиц Departments и Employees:

 1 // Insert a Department
 2 DBRecord rec = new DBRecord();
 3 rec.create(db.DEPARTMENTS);
 4 rec.setValue(db.DEPARTMENTS.NAME, "Development");
 5 rec.setValue(db.DEPARTMENTS.BUSINESS_UNIT, "ITTK");
 6 rec.update(conn);
 7 int depId = rec.getInt(db.DEPARTMENTS.DEPARTMENT_ID); 
 8 
 9 // Insert an Employee
10 DBRecord rec = new DBRecord();
11 rec.create(db.EMPLOYEES);
12 rec.setValue(db.EMPLOYEES.FIRSTNAME, "Peter");
13 rec.setValue(db.EMPLOYEES.LASTNAME, "Sharp");
14 rec.setValue(db.EMPLOYEES.GENDER, "M");
15 rec.setValue(db.EMPLOYEES.DEPARTMENT_ID, depId);
16 rec.update(conn);

Для приведенного выше кода, Empire-db формирует и выполняет следующие операторы вставки:

1 INSERT INTO DEPARTMENTS( DEPARTMENT_ID, NAME, BUSINESS_UNIT, UPDATE_TIMESTAMP) 
2 VALUES ( 2, 'Development', 'ITTK', '2008-01-08 07:31:11.120')
3 
4 INSERT INTO EMPLOYEES( EMPLOYEE_ID, FIRSTNAME, LASTNAME, DEPARTMENT_ID, GENDER, RETIRED, UPDATE_TIMESTAMP) 
5 VALUES ( 1, 'Peter', 'Sharp', 1, 'M', 0, '2008-01-08 07:31:11.151')

Драйвер базы данных DBDatabaseDriver создает значения идентификаторов автоматически, используя либо последовательности, предоставленные целевой СУБД, либо специальную внутреннюю таблицу для генерации номеров.

Обновление данных

На этом шаге демонстрируется обновление данных. Следующий код показывает как обновить номер телефона сотрудника:

1 // Update an Employee
2 DBRecord rec = new DBRecord();
3 rec.read(db.EMPLOYEES, idPers, conn);
4 rec.setValue(db.EMPLOYEES.PHONE_NUMBER, "+49-7531-457160");
5 rec.update(conn);

Для этого кода, Empire-db создает следующий оператор обновления:

1 UPDATE EMPLOYEES
2 SET PHONE_NUMBER='+49-7531-457160', 
3     UPDATE_TIMESTAMP='2008-01-08 07:31:11.183'
4 WHERE EMPLOYEE_ID=1 AND UPDATE_TIMESTAMP='2008-01-08 07:31:11.150'

Важные уточнения, на которые следует обратить внимание:

  1. Только те поля, которые были изменены, обновляются в базе данных. Вы можете в любое время проверить статус изменения записей или отдельного поля БД;
  2. Отметка времени обновления генерируется автоматически. Используя ограничение на столбец отметки времени, Empire-db проверяет, была ли запись одновременно изменена другим пользователем;
  3. Вы можете расширить DBRecord, создав специальные классы записей сущностей для вашей базы данных. Это не только обеспечит дополнительную безопасность типов, но также позволит Вам добавлять новые методы или переопределять существующие методы по необходимости.

Выполнение запроса и получение доступа к результатам

На этом шаге демонстрируется то, как выполнить запрос к базе данных и получить доступ к результатам запроса. Для нашего примера, мы запрашиваем некоторые поля сотрудников из базы данных. Поля LASTNAME и FIRSTNAME объединяются для того, чтобы предоставить полное имя сотрудника. Кроме того, мы присоединяемся к таблице Departments, чтобы получить название отдела, к которому принадлежит сотрудник. Наконец, мы добавляем ограничения и порядок, в котором хотим, чтобы данные поступали из СУБД.

Для создания этого выражения, нам нужен объект DBCommand. Его можно получить из нашего объекта базы данных. Объект command предлагает методы, имена которых совпадают с именами ключевых слов SQL: select, where, group by, having и order by. Нет необходимости указывать, из какой таблицы мы хотим получить доступ к нашим данным. Однако соединения должны быть объявлены вручную при помощи метода join(). Окончательный код выглядит следующим образом:

 1 // Define the query
 2 DBCommand cmd = db.createCommand();
 3 DBColumnExpr EMPLOYEE_FULLNAME= db.EMPLOYEES.LASTNAME.append(", ")
 4                         .append(db.EMPLOYEES.FIRSTNAME).as("FULL_NAME");
 5 // Select required columns
 6 cmd.select(db.EMPLOYEES.EMPLOYEE_ID, EMPLOYEE_FULLNAME);
 7 cmd.select(db.EMPLOYEES.GENDER, db.EMPLOYEES.PHONE_NUMBER);
 8 cmd.select(db.DEPARTMENTS.NAME.as("DEPARTMENT"));
 9 cmd.select(db.DEPARTMENTS.BUSINESS_UNIT);
10 // Set Joins
11 cmd.join(db.EMPLOYEES.DEPARTMENT_ID, db.DEPARTMENTS.DEPARTMENT_ID);
12 // Set contraints and order
13 cmd.where(EMP.LASTNAME.length().isGreaterThan(0));
14 cmd.orderBy(EMP.LASTNAME);

Для этого кода, Empire-db создает следующий оператор выбора:

1 SELECT t2.EMPLOYEE_ID, t2.LASTNAME + ', ' + t2.FIRSTNAME AS FULL_NAME, t2.GENDER, t2.PHONE_NUMBER, 
2     t1.NAME AS DEPARTMENT, t1.BUSINESS_UNIT
3 FROM EMPLOYEES t2 INNER JOIN DEPARTMENTS t1 ON t1.DEPARTMENT_ID = t2.DEPARTMENT_ID
4 WHERE len(t2.LASTNAME)>0 
5 ORDER t2.LASTNAME

Важные уточнения, на которые следует обратить внимание:

  1. Кроме переименования столбцов, для создания запроса не нужно никаких строковых литералов, что обеспечивает максимальную безопасность во время компиляции. Помимо этого, код является переносимым и не привязан к конкретной СУБД.
  2. Ограничения для фильтрации можно добавить при помощи метода-команды where(), который можно вызывать любое количество раз. Это позволяет условно добавлять ограничения, не влияя на читаемость кода;
  3. При создании команды, все необходимые объекты таблиц и столбцов, а также функции SQL могут быть легко добавлены с помощью функции автозавершения кода в среде IDE. Это позволяет ускорить процесс написания кода и предотвратить ошибки, сделанные неопытными программистами.

Наконец, нам нужно выполнить запрос и показать результаты. Для этого мы используем три разных варианта:

  1. Итерация результатов по строкам;
  2. Получение списка объектов JavaBean/POJO, каждый из которых содержит данные одной строки результатов. Для этого нам нужно использовать класс SampleBean, свойства которого соответствуют результату запроса (см. SampleBean.java);
  3. Получение результатов из документа XML, который содержит результаты запроса и даже включает метаданные столбца.

Вариант 1: этот код показывает, как перебирать и выводить результаты итеративно по строкам:

 1 // Open the reader using command object
 2 DBReader reader = new DBReader();
 3 reader.open(cmd, conn);
 4 // Text-Output by iterating through all records. 
 5 while (reader.moveNext()) { 
 6     System.out.println(reader.getString(EMP.EMPLOYEE_ID)
 7               + "\t" + reader.getString(EMPLOYEE_FULLNAME)
 8               + "\t" + EMP.GENDER.getOptions().get(reader.getString(EMP.GENDER))
 9               + "\t" + reader.getString(DEP.NAME));
10 }

Вариант 2: этот код показывает, как получить список объектов JavaBean/POJO:

1 // Open the reader using command object
2 DBReader reader = new DBReader();
3 reader.open(cmd, conn);
4 // Text-Output using a list of Java Beans supplied by the DBReader 
5 List<SampleBean> beanList = reader.getBeanList(SampleBean.class);
6 for (SampleBean b : beanList) { 
7     System.out.println(b.toString());
8 }

Вариант 3: чтобы получить результат в виде XML-документа, необходим следующий код:

1 // Open reader
2 DBReader reader = new DBReader();
3 reader.open(cmd, conn);
4 // XML output
5 Document doc = reader.getXmlDocument();
6 // Print XML document to System.out
7 XMLWriter.debug(doc);

Документ XML, полученный с помощью этого кода, выглядит следующим образом:

 1 <rowset>
 2     <column key="1" mandatory="1" name="EMPLOYEE_ID"></column>
 3     <column mandatory="1" name="FULL_NAME" size="40"></column>
 4     <column name="GENDER" size="1">
 5         <option value="M">Male</option>
 6         <option value="F">Female</option>
 7     </column>
 8     <column name="PHONE_NUMBER" size="40"></column>
 9     <column mandatory="1" name="DEPARTMENT" size="80"></column>
10     <column mandatory="1" name="BUSINESS_UNIT" size="4"></column>
11     <row>
12         <EMPLOYEE_ID>41</EMPLOYEE_ID>
13         <FULL_NAME>Bloggs, Fred</FULL_NAME>
14         <GENDER>M</GENDER>
15         <PHONE_NUMBER>+49-5555-505050</PHONE_NUMBER>
16         <DEPARTMENT>Development</DEPARTMENT>
17         <BUSINESS_UNIT>ITTK</BUSINESS_UNIT>
18     </row>
19     <row>
20         <EMPLOYEE_ID>40</EMPLOYEE_ID>
21         <FULL_NAME>Sharp, Peter</FULL_NAME>
22         <GENDER>M</GENDER>
23         <PHONE_NUMBER>+49-7531-457160</PHONE_NUMBER>
24         <DEPARTMENT>Development</DEPARTMENT>
25         <BUSINESS_UNIT>ITTK</BUSINESS_UNIT>
26     </row>
27     <row>
28         <EMPLOYEE_ID>42</EMPLOYEE_ID>
29         <FULL_NAME>White, Emma</FULL_NAME>
30         <GENDER>F</GENDER>
31         <PHONE_NUMBER>+49-040-125486</PHONE_NUMBER>
32         <DEPARTMENT>Sale</DEPARTMENT>
33         <BUSINESS_UNIT>ITTK</BUSINESS_UNIT>
34     </row>
35 </rowset>

Этот XML может быть легко преобразован в другой синтаксис путем применения преобразований XSLT.[Источник 3]

Источники

  1. Apache Empire-db - Wikipedia // Wikipedia. [2018-2018]. Дата обновления: 26.08.2018. URL: https://en.wikipedia.org/wiki/Apache_Empire-db (дата обращения: 08.12.2018).
  2. Empire-db - At a glance // The Apache Software Foundation. [2008-2012]. URL: http://empire-db.apache.org/empiredb/empiredb.htm (дата обращения: 09.12.2018).
  3. Empire-db - Tutorials // The Apache Software Foundation. [2008-2012]. URL: http://empire-db.apache.org/documentation/tutorial.htm (дата обращения: 09.12.2018).