Разработка кросс-платформенного, кросс-браузерного модулей ввода информации в базу данных

УДК 519.6

Разработка кросс-платформенного, кросс-браузерного модулей ввода информации в базу данных

Д.Е. Белов, к. б. н.,

А.Ф. Шалин, гл. специалист по информационной безопасности И.Н. Воронкина, преподаватель, Ставропольский региональный колледж вычислительной техники и электроники

Технология объектно-реляционного связывания (ORM - object relation mapping), основанная на реализации интерфейса java persistence API (JPA) провайдером Hibernate, предусматривает разработку доменной модели классов для организации взаимодействия СУБД с java-программой. Причем, как было показано в предыдущих исследованиях, при организации такого взаимодействия необходимо учитывать, что объектная модель накладывает ряд ограничений на реляционную. А именно, в результате реализации подобной технологии мы имеем следующие побочные эффекты:

a) в объектной модели перестают работать основные концепции теории множеств;

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

ORM предусматривает организацию связывания реляционной и объектной моделей следующим образом:

- Отношение > Контейнер объектов;

- Кортеж > Объект класса;

- Домен > Поле класса.

Положительным эффектом технологии ORM является возможность мягкой смены СУБД в рамках реализации JPA. Другими словами, именно это и обусловливает кросс-платформенность на уровне базы данных. Хотя для данного эффекта в английском языке есть более специализированный термин «Cross-database», однако, так как в русском аналоге «Кросс-база-данность» не получил широкого распространения, в своей работе под кросс-платформенностью мы подразумеваем не только возможность миграции между различными операционными системами, но и между системами управления базами данных.

Что касается кросс-браузерности, в это понятие мы вкладываем довольно стандартное значение, которое присуще большинству авторов. А именно, под кросс-браузерностью понимается свойство сайта отображаться и работать во всех популярных браузерах идентично, то есть способность отображать материал с одинаковой степенью читабельности. При разработке доменной модели классов было необходимо реализовать методы для поддержки CRUD (Create,

read, update and delete) - операций.

Так как реализация данных методов для каждого из классов является весьма рутинной и дорогой задачей, возникло естественное желание организовать обобщённые методы для большинства классов, которые позволят реализовать CRUD-операции. Для реализации данной идеи было принято решение использовать такие парадигмы языка java, как наследование и полиморфизм, так как интерфейс JPA поддерживает эту концепцию. Причем JPA позволят указать, как именно хранить данные наследуемых классов, например, если мы организуем иерархический справочник, то все данные разумно хранить в одной таблице в базе данных, однако классы в программе для доступа к каждому уровню иерархии необходимо реализовать отдельно.

Рисунок 1 - Графическое представление доменной модели классов.

Организация основных операций с базой предусматривала следующие функциональные возможности:

1) получение и сохранение ip-адреса пользователя при реализации любых операция с объектами БД;

2) получение и сохранение уникального идентификатора пользователя в системе;

3) получение и сохранение времени операции;

4) организация метода remove так, чтобы физически данные из БД не удалялись, а у пользователя складывалось впечатление об их удалении.

Для решения поставленных задач был организован основной класс -SuperAbstractBean, отвечающий за основную часть операций CRUD, кроме операции чтения. Для операции чтения возникла необходимость реализовывать более специализированные классы, например, такие как SuperReport для чтения информации об отчетах и SuperAbstractUnit для иерархического справочника местонахождения (рис.1).

При этом сами операции реализованы следующим образом:

1) Create:

@Transactional public void persist() {

if (this.entityManager == null) this.entityManager = entityManager();

if (WebApplication.get()!= null){

WebApplicationContext wc = ((WebApplicationContext) WebApplication.get().getContext()); setUserCreateID(WebApplication.get().getUser().getId()); setUserCreateIP(wc.getBrowser().getAddress()); setUserCreateTime(new Date());

}

this.entityManager.persist(this);

}

2) Update:

@Transactional

public SuperAbstractBean merge() { if (WebApplication.get()!= null) {

WebApplicationContext wc = ((WebApplicationContext) WebApplication.get().getContext());

if (this.entityManager == null) this.entityManager = entityManager(); this.setUserModifyID(WebApplication.get().getUser().getId()); this.setUserModifyIP(wc.getBrowser().getAddress()); this.setUserModifyTime(new Date());

SuperAbstractBean merged = this.entityManager.merge(this);

this.entityManager.flush();

return merged;

}

else {

if (this.entityManager == null) this.entityManager = entityManager(); SuperAbstractBean merged = this.entityManager.merge(this); this.entityManager.flush();

return merged;

}}

3) Remove:

@Transactional public void remove() {

if (WebApplication.get()!= null) {

WebApplicationContext wc =

WebApplication.get().getContext());

if (this.entityManager == null) this.entityManager = entityManager(); if (this.entityManager.contains(this)) { this.setUserDeleteID(WebApplication.get().getUser().getId()); this.setUserDeleteIP(wc.getBrowser().getAddress()); this.setUserDeleteTime(new Date()); this.falseDelete = true;

}

else {

SuperAbstractBean attached = findSuperAbstractBean(this.id); this.setUserDeleteID(WebApplication.get().getUser().getId()); this.setUserDeleteIP(wc.getBrowser().getAddress()); this.setUserDeleteTime(new Date()); this.falseDelete = true;

}

}

else {

if (this.entityManager == null) this.entityManager = entityManager(); if (this.entityManager.contains(this)) { this.entityManager.remove(this);

}

else {

SuperAbstractBean attached =

SuperAbstractBean. findSuperAbstractBean(this.id); this.entityManager.remove(attached);

}

}Что касается операции чтения (Read), то в нашем случае она была достаточно специализированной, и её реализация зависела от того, что именно мы хотели показать пользователю. Например, в классе SuperReport, который является базовым для всех отчетов и в то же время наследником класса SuperAbstractBean, операция чтения была реализована следующим образом:

4) Read для выборки данных по соответствующей подотчетной единице и дате составления отчета:

@SuppressWarnings

public static List<? extends SuperReport> findAllReportsByRayonAndDate(Class<? extends SuperReport> report, ReportingDate dateBean) { if (WebApplication.get()!= null){

return entityManager

.getResultList();

}

}

Такой подход к реализации классов доменной модели является достаточно универсальным и позволяет сократить затраты на написание кода для каждого класса. В результате появляется возможность работать практически со всеми классами в системе как с SuperAbstractBean, используя восходящее предобразование, а со всеми классами, предназначенными для хранения отчётной информации, как с SuperReport и т.д. (рис. 1).

Для подтверждения эффекта кросс-платформенности был проведен эксперимент, характеризующий работоспособность приложения при взаимодействии с системами управления базами данных Oracle, MySQL и FireBird.

При организации данного эксперимента основными проблемами миграции между различными СУБД были следующие:

1) длина названия полей и таблиц;

2) различия в генерации первичных ключей.

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

1) Oracle - 30 знаков;

2) FireBird - 31 знак;

3) MySQL- 64 знака.

Из данной ситуации существует два выхода: первый наиболее простой - назвать поля и таблицы таким образом, чтобы они не превышали 30 знаков. Но что делать, если, например, мы уже попали в подобную ситуацию, мигрируя между MySQL и Oracle? В этой ситуации становится полезной аннотация @column, позволяющая реализовать новое имя в базе данных, не совпадающее с названием поля класса. Например, благодаря коду, представленному ниже, имя поля в базе данных будет version, без спецификатора, при использовании провайдера Hibernate, оно будет таким: Version_Super_Abstract_Bean. @Version

@Column

private Integer versionSuperAbstractBean;

Что касается механизмов генерации первичных ключей, то для получения автоинкрементного поля с шагом 1 в СУБД MySQL был применен следующий код:

@Id

@GeneratedValue

@Column(name = "id") private Long id; для СУБД Oracle такой:

@Id

@Column(name = "id") protected Long id;

однако пришлось написать дополнительный метод и класс.

При тестировании программы на Oracle наиболее стабильным показал себя следующий подход:

1) был написан класс Identifier, исходный код приведен ниже: package ru.sniizhk.f24a.mixedbean;

@Transactional

@Configurable

@RunWith

@ContextConfiguration(locations =

"classpath:/META-INF/spring/applicationContext.xml") public class Identifier {

public static final Logger log = Logger.getLogger(Identifier.class);

@PersistenceContext

transient EntityManager entityManager;

private Long nextId;

@Test

/** В переменной s передается название класса */ public void sqlCallfromDual(String s){

HibernateEntityManager hem = entityManager.unwrap(HibernateEntityManager.class);

Session session = hem.getSession();

List l = session.createSQLQuery("select SQ_" + s + "_ID.nextval as nextMyId from dual").list(); log.info(" session.createSQLQuery l = " + l.get(0)); this.nextId = Long.parseLong(l.get(0).toString());

}

public Long getNextID(){ return this.nextId;

}

}

2) В классе SuperAbstractBean был добавлен следующий метод: @PrePersist // Событие возникает перед операцией создания (Create) public void setNextId(){

if (this. id == null){

Identifier i = new Identifier();

if(this.getClass().getSimpleName().equals("Region") || this.getClass().getSimpleName().equals("Rayon") || this.getClass().getSimpleName().equals("Company")){ i.sqlCallfromDual("Unit");

} else {

i.sqlCallfromDual(this.getClass().getSimpleName());

}

setId(i.getNextID());

}

}

Что касается кросс-браузерности, для тестирования работоспособности приложения использовались следующие просмотрщики:

1) Mozilla Firefox. Версия 11.0;

2) Google Chrom. Версия 19.0;

3) Internet Explorer. Версия 9.0;

4) Opera. Версия 12.11;

5) Safari. Версия 5.1.

Для решения проблемы одинакового отображения информации в браузерах различных производителей использовались open source, библиотеки, позволяющие генерировать java script и HTML на стороне клиента.

Литература:

1. Абонеев, В.В. Методика оценки мясной продуктивности овец /В.В. Абонеев, Ю.Д. Квитко, И.И. Селькин и др. //Ставрополь, 2009. -34с.

2. Абонеев, В.В. Стратегия развития овцеводства в Российской Федерации /В.В. Абонеев //Достижения науки и техники АПК. -2008.-№10. -С.37-39.

3. Абонеев, В.В. Приемы и методы повышения конкурентоспособности товарного овцеводства /В.В.Абонеев, Л.Н.Скорых, Д.В. Абонеев //ГНУ СНИИЖК, Ставрополь. -2011. -337с.

4. Абонеев, В.В. Перспективные направления селекции овец в условиях рыночной экономики /В.В.Абонеев, А.Н. Соколов //Овцы, козы, шерстяное дело. -2007. -№ 1. -С.7-11.

5. Абонеев, В.В. Развитие тонкорунного овцеводства в России /В.В. Абонеев, В.В. Марченко, А.И. Суров, А.А. Пикалов, А.И. Ерохин, С.А. Карасев //Овцы. Козы. Шерстяное дело. -2012. -№ 2. -С.6-13.

6. Василенко, В.Н. Племенная база овцеводства Ростовской области /В.Н. Василенко, Ю.А. Колосов //Зоотехния, 2002. -№8. -С.9-12.

7. Завгородняя, Г.В. Мясная продуктивность баранчиков разных генотипов и уровней кормления /Г.В. Завгородняя, Ю.Д. Квитко, И.И. Дмитрик, И.П. Будякова, И.Н. Шарко //Овцы. Козы. Шерстяное дело. -2012. - № 2- С. 42-44.

8. Квитко, Ю.Д. Проблемы и новые подходы в организации производства баранины /Ю.Д. Квитко //Сборник научных трудов Ставропольского научно-исследовательского института животноводства и кормопроизводства. -2005. -Т. 1. -№2. -С.3-7.

9. Квитко, Ю.Д. Мясная продуктивность и качество мяса молодняка овец разного происхождения /Ю.Д. Квитко, А.В. Скокова, С.Ф. Силкина //Овцы. Козы. Шерстяное дело. - 2012. -№ 2. -С.39-41.

10. Ковалюк, Н.В. Молекулярно-биологические методы для оздоровления стад крупного рогатого скота от лейкоза /Н.В. Ковалюк //Ветеринария. -2008. -№2. -С.22-26.

11. Ковалюк, Н.В. Методические рекомендации по использованию маркера BoLA DRB3 в селекционно-племенной работе с крупным рогатым скотом: Рекомендации СКНИИЖ /Н.В. Ковалюк, В.Ф. Сацук //Краснодар, 2010. -24с.

12. Ковалюк, Н.В. Использование генетического маркера BOLA-DRB3 для оптимизации селекционного процесса при скрещивании /Н.В. Ковалюк, В.Ф. Сацук //Молочное скотоводство.-2010.-№2.-С.10-12.

13. Ковалюк, Н.В. Современные методы диагностики лейкоза крупного рогатого скота /Н.В. Ковалюк, В.Ф. Сацук, Е.В. Мачульская //Ветеринария Кубани. -2007. -№ 1. -С.18-20.

14. Колосов, Ю.А. Информационное сопровождение селекционного процесса в овцеводстве: учебное пособие /Ю.А. Колосов, А.И. Бараников, В.Н. Василенко, Н.В. Михайлов //Изд-во Донского ГАУ, пос.Персиановский, 2012. -55с.

15. Колосов, Ю.А. Продуктивность молодняка породы советский меринос и её помесей с эдильбаевскими баранами /Ю.А. Колосов, С. В. Шихов //Овцы, козы, шерстяное дело. -2006. -№ 3. -С.7-10.

16. Колосов, Ю.А. Модель организации селекционно-племенной работы в овцеводстве с применением метода зависимых уровней отбора/Ю.А. Колосов, И.В. Засемчук //Новочеркасск, 2008.-С.76.

17. Новопашина, С.И. Переваримость питательных веществ рациона молочными козами при разном уровне протеина /С.И. Новопашина, Ю.Д. Квитко, М.Ю. Санников, Е.И. Кизилова //Овцы. Козы. Шерстяное дело. -2012. -№ 2. -С.64-67.

18. Ольховская, Л.В. Иммуногенетический анализ в селекции коз /Л.В. Ольховская, Л. Н. Чижова и др. //Ставрополь. ВНИИОК, 2000. -С.3-11.

19. Тимошенко, Н.К. Состояние и перспективы развития первичной обработки шерсти /Н.К. Тимошенко //Овцы, козы, шерстяное дело. -2007. -№ 4. -С.46-50.

20. Тимошенко, Н.К. Рынок шерсти: состояние и тенденции развития /Н.К. Тимошенко, В.В. Абонеев //Овцы, козы, шерстяное дело, 2012. -№

2. -С.50.

21. Чижова, Л. Н. Биохимические тест-системы, генетические маркеры продуктивности, их использование в селекции овец /Л.Н. Чижова //Автореф. дисс.... д-ра с.-х. наук. -Ставрополь, 2004. -58с.

22. Чижова, Л. Н. Методические рекомендации комплексной оценки крупного рогатого скота мясных пород по фенотипу и генотипу /Л.Н. Чижова и др. //Ставрополь, 2008. -52с.