Профессиональная реализация
Используя заданную выше последовательность, для инициализации mapping-файлов и для корректного манипулирования соединением с базой данных создается класс ConnectionFactory. Было замечено, что в некоторых версиях hibernate, несмотря на директиву autoReconnect=true, автоматическое переподключение к БД происходит со второго раза, то есть подключение происходит сразу же, но появляется исключение о невозможности подключиться к БД.
/* пример # 8: инициализация mapping и подключение к БД :
ConnectionFactory.java */
package com.hib;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.MappingException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.cfg.Configuration;
import java.util.Date;
public class ConnectionFactory {
public static long timer = 0;
public static SessionFactory sessionFactory = null;
public static void initConnectionFactory() {
Date dt = new Date();
timer = dt.getTime();
try {
//добавление mapping-файлов в конфигурацию подключения
Configuration cfg = new Configuration() .addClass(Student.class).addClass(Course.class);
//создание подключения к БД
sessionFactory = cfg.buildSessionFactory();
} catch (MappingException e) {
System.err.print(e);
} catch (HibernateException e) {
System.err.print(e);
destroy();
}
}
public static Session getOrInitSession() {
try {
Date curDate = new Date();
long curTime = curDate.getTime();
long tenminutes = 10 * 60 * 1000;
if (curTime - timer > tenminutes){
destroy();
}
else {
curDate = new Date();
timer = curDate.getTime();
}
if (sessionFactory == null) {
initConnectionFactory();
}
return sessionFactory.openSession();
} catch (HibernateException e) {
System.err.print(e);
destroy();
return null;
}
}
public static void destroy() {
timer = 0;
try {
//необходимо вызывать, т.к. иначе будут утечки памяти
sessionFactory.close();
} catch (Exception e) {
e.printStackTrace();
}
sessionFactory = null;
}
}
Данный класс проверяет наличие подключения к БД и сохраняет время проверки. Если на момент проверки класс «простаивает» больше 10 минут, то идет повторное подключение к базе данных. В случае удаления класса он предотвращает утечки памяти. Хотя в Hibernate есть средства для того, чтобы исключить необходимость подключать каждый hbm.xml файл по отдельности, всё же лучше это делать вручную во избежание указанных выше ошибок.
Этот класс обрабатывает ошибки, которые возникали на практике при работе c Hibernate, JDBC драйвером MySQL и сервером баз данных MySQL.
Взаимодействие с БД
При работе с базой данных удобно функции манипулирования с объектами собирать воедино и создавать менеджеры транзакций.
/* пример # 9: инициализация mapping и подключение к БД : StudentDAO.java */
package com.hib;
import net.sf.hibernate.*;
public class StudentDAO {
//проверка на существование записи в базе данных
public static Boolean studentExists(String login) {
Session session =
ConnectionFactory.getOrInitSession();
Student _student = null;
try {
// создание запроса к БД
Query query =
session.createQuery(
"from Student a where a.login = :login");
query.setParameter("login", login);
/*этот метод позволяет получать уникальные результаты. Необходимо обеспечить уникальность результатов на уровне БД, если используется данная функция */
_student = (Student) query.uniqueResult();
} catch (HibernateException e) {
e.printStackTrace();
ConnectionFactory.destroy();
} finally {
if (session != null) {
try {
session.close();
} catch (HibernateException e) {
e.printStackTrace();
ConnectionFactory.destroy();
}
}
}
if (_student != null) {
return new Boolean(true);
} else {
return null;
}
}
public static Student getStudent(String login,
String password) {
Session session =
ConnectionFactory.getOrInitSession();
Student _student = null;
try {
Query query =
session.createQuery(
"from Student a where a.login = :login");
query.setParameter("login", login);
_student = (Student) query.uniqueResult();
} catch (HibernateException e) {
e.printStackTrace();
ConnectionFactory.destroy();
} finally {
if (session != null) {
try {
session.close();
} catch (HibernateException e) {
e.printStackTrace();
ConnectionFactory.destroy();
}
}
}
if (_student != null) {
if (password.equals(_student.getPassword())) {
return _student;
} else
return null;
} else
return null;
}
//обновление учетной записи студента
//для возможности таких обновлений прописывался тег id в mapping
public static void updateStudent(Student _student) {
Session session =
ConnectionFactory.getOrInitSession();
try {
Transaction tx = null;
tx = session.beginTransaction();
session.update(_student);
tx.commit();
} catch (HibernateException e) {
e.printStackTrace();
tx.rollback();
ConnectionFactory.destroy();
} finally {
if (session != null) {
try {
session.close();
} catch (Exception e) {
e.printStackTrace();
ConnectionFactory.destroy();
}
}
}
}
//добавление учетной записи студента
// в этом случае работает директива native из mapping
public static Boolean addStudent(Student _student) {
Session session =
ConnectionFactory.getOrInitSession();
try {
Transaction tx = null;
tx = session.beginTransaction();
session.save(_student);
tx.commit();
} catch (HibernateException e) {
e.printStackTrace();
tx.rollback();
ConnectionFactory.destroy();
return null;
} finally {
if (session != null) {
try {
session.close();
} catch (Exception e) {
e.printStackTrace();
ConnectionFactory.destroy();
return null;
}
}
}
return new Boolean(true);
}
//удаление учетной записи студента
public static void deleteStudent(Student _student) {
Session session =
ConnectionFactory.getOrInitSession();
try {
Transaction tx = null;
tx = session.beginTransaction();
session.delete(_student);
tx.commit();
} catch (HibernateException e) {
e.printStackTrace();
tx.rollback();
ConnectionFactory.destroy();
} finally {
if (session != null) {
try {
session.close();
} catch (Exception e) {
e.printStackTrace();
ConnectionFactory.destroy();
}
}
}
}
}
Класс SessionFactory относится к потокобезопасным классам, поэтому обычно его объект будет создаваться один раз и храниться в статической переменной. Если же возникли проблемы с базой данных, с пулом соединений либо
с освобождением ресурсов, которые хранятся в объекте SessionFactory, то, возможно, придется поддержать вышеприведенный подход.
Для управления Session используются два похода:
Session для каждой операции с базой данных, либо Session per request в контексте транзакции.
Начиная с версии 3.1, в Hibernate появился новый параметр hibernate.current_session_context_class, который может принимать одно из трех коротких значений, "jta", "thread" и "managed",
либо классов, которые реализуют интерфейс org.hibernate.context.CurrentSessionContext и будут ответственны за открытие/закрытие сессии.
Если данный параметр установлен в конфигурационном файле, то в коде для получения сессии нужно только вызвать метод SessionFactory.getCurrentSession(),который либо вернет уже привязанную к данному контексту сессию, либо создаст новую.
Установив свойство в конфигурационном файле
<property name= "current_session_context_class">thread </property> метод deleteStudent() можно переписать следующим образом.
public static void deleteStudent(Student _student) {
Session session =
ConnectionFatory.sessionFactory
.getCurrentSession();
try {
Transaction tx = null;
tx = session.beginTransaction();
session.delete(_student);
tx.commit();
} catch (HibernateException e) {
e.printStackTrace();
tx.rollback();
}
}
В данном случае управление соединением будет производиться классом org.hibernate.context.ThreadLocalSessionContext,который будет использовать соединение, пока метод beginTransaction() не был вызван,
и соответственно отпустит соединение при вызове метода commit() либо rollback().
Запуск из-под Apache Ant
Для того чтобы запустить проект из-под Apache Ant, необходимо, чтобы папки проекта были организованы следующим образом:
+lib
<Hibernate and third-party libraries>
+src
<All source files and packages including hbm files>
hibernate.cfg.xml
build.xml
Файл build.xml служит руководством к действию для Ant. Изначально он должен выглядеть следующим образом:
<project name="hibernate-tutorial" default="compile">
<property name="sourcedir" value="${basedir}/src"/>
<property name="targetdir" value="${basedir}/bin"/>
<property name="librarydir" value="${basedir}/lib"/>
<path id="libraries">
<fileset dir="${librarydir}">
<include name="*.jar"/>
</fileset>
</path>
<target name="clean">
<delete dir="${targetdir}"/>
<mkdir dir="${targetdir}"/>
</target>
<target name="compile" depends=
"clean, copy-resources">
<javac srcdir="${sourcedir}"
destdir="${targetdir}"
classpathref="libraries"/>
</target>
<target name="copy-resources">
<copy todir="${targetdir}">
<fileset dir="${sourcedir}">
<exclude name="**/*.java"/>
</fileset>
</copy>
</target>
</project>
Далее выполняется команда ant, находясь в папке проекта или явно указывая рабочую папку. Если компиляция прошла успешно, то в файл build.xml необходимо добавить следующие строки:
<target name="run" depends="compile">
<java fork="true" classname="ClassName"
classpathref="libraries">
<classpath path="${targetdir}"/>
</java>
</target>
где параметр ClassName содержит имя класса, который можно запустить (есть метод main, правильно объявленный). В конце концов, для запуска используется команда ant run.
STRUTS
Проект Struts был запущен в мае 2000 г. К. Макклэнаном (Craig R. McClanahan) для обеспечения возможности разработки приложений с архитектурой, базирующейся на парадигме Model/View/Controller. В июле 2001 г. был выпущен первый релиз Struts 1.0. Struts является частью проекта Jakarta, поддерживаемого Apache Software Foundation. Цель проекта Jakarta Struts – разработка среды с открытым кодом для создания Web-приложений с помощью технологий Java Servlet and JSP.