Сидя на прошлой линуксовке рядом с Mabel'ом он спросил после 8 кружки Пива что такое Hibernate? Я как смог объяснил :) Этот разговор натолкнул меня на мысль что в русском сегменте интернета нет практически полных статей на тему что такое Hibernate и как его настроить и использовать, по этому я Начинаю ряд статей посвяшенных Hibernate 3 версии.
Нам потребуется:
1. jdk 1.6
2. ant 1.6.5
3. mysql 5
4. hibernate-3.2.0
5 mysql-connector-java-3.1.13-bin.jar
Что такое Hibernate - это object relational mapping (ORM). Коротко ORM - это отображение(mapping) структуры данных(полей) таблицы Базы Данных - на
POJO-объект. POJO-объект - это Java Bean компонент который не наследует(extend) ни каких классов. Объясню все на примере пусть у нас существует таблица:
CREATE TABLE `persons` ( `id` int(11) NOT NULL auto_increment, -- уникальный номер `firstName` varchar(20) default NULL, -- имя `lastName` varchar(20) default NULL, -- фамилия `BirthDate` date default NULL, -- дата рождения PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Нам надо отобразить поля таблицы на POJO-объект, описываем переменные и get- и set- методы доступа к ним, то есть одна запись из Базы данных будет
соответствовать 1 POJO-объекту.
package org.vit.domain;
import java.util.Date;
public class Person {
private Integer id; //уникальный номер
private String firstName; //имя
private String lastName; //фамилия
private Date birthDate; //дата рождения
public Person() { //
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
}
Далее нам надо настроить hibernate что бы мы могли оперировать POJO-объектами как записями в БД. Настроить его можно ч\з 2 файла hibernate.cfg.xml или
hibernate.properties. Я использую hibernate.cfg.xml:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- configure JDBC connection -->
<property name="connection.useUnicode">true</property>
<property name="connection.characterEncoding">UTF-8</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/test</property>
<property name="connection.username">root</property>
<property name="connection.password">xor21</property>
<!-- configure hibernate -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="current_session_context_class">thread</property>
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
<!-- "Import" the mapping resources here -->
<mapping resource="org/vit/domain/Person.hbm.xml"/>
</session-factory>
</hibernate-configuration>
В секции <!-- configure JDBC connection --> я настраиваю подключение по JDBC драйверу к БД mysql
В секции <!-- configure hibernate --> настройки самого hibernate
Строчка <property name="dialect">org.hibernate.dialect.MySQLDialect</property> говорит hibernate что мы будем работать с БД mysql. Полный перечень поддерживаемых БД можно посмотреть в документации.
Следующие 2 строчки настраиваю поведение транзакции в hibernate
<property name="current_session_context_class">thread</property> - стратегия управления транзакцией
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
- Класс доступа к Transaction API hibernat'a
В секции <!-- "Import" the mapping resources here --> указываем файлы mapping, файлы которые связывают поля таблицы БД с полями PoJO-объекта. Имя файла состоит из имени Класса Person + расширение .hbm.xml (hbm - hibernate mapping):
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE
hibernate-mapping
PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping >
<!-- связываем класс org.vit.domain.Person с таблицей Persons-->
<class name="org.vit.domain.Person" table="Persons">
<!-- связываем поле id Person-класса(name) с полем
id(column) таблицы Persons при этом указав тип данных int,
тег <id> - соответствует уникальному ключу по которому должен
определяться каждый pojo-объект - это особенность hibernate т.е.
каждая таблица должна иметь primary key (тип целое число) -->
<id name="id" type="int" column="id">
<!-- как генерируется id в POJO-объекте Person,
native - Базой Данных а именно по отношению к mysql -
работает auto_increment поля id-->
<generator class="native"/>
</id>
<!-- property
firstName полю класса org.vit.domain.Person(name="firstName") сопоставляем
из таблицы Persons колонку firstName(column="firstName") тип type="string"
2 следующие property описываются аналогично :)
-->
<property name="firstName" type="string" column="firstName"/>
<property name="lastName" type="string" column="lastName"/>
<property name="birthDate" type="date" column="BirthDate"/>
</class>
</hibernate-mapping>
Основной рабочей единицей hibernate является сессия Session. Для того чтобы получить session надо настроить и создать объект SessionFactory. SessionFactory - должен быть Singelton-ом (настоятельная рекомендация разработчиков hibernate). Я пользуюсь классом HibernateUtil (взято из документации hibernat'a):
package org.hibernate.tutorial.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Создаем SessionFactory с настройками из файла hibernate.cfg.xml
return new Configuration().
configure("hibernate.cfg.xml").buildSessionFactory();
}
catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
// возвращаем сессию
return sessionFactory;
}
}
и вот после всех настроек мы можем пользоваться hibernate в нашей программе:
package org.vit;
import org.hibernate.tutorial.util.HibernateUtil;
import org.hibernate.Session;
import org.vit.domain.Person;
import java.util.Date;
import java.util.Calendar;
public class Vit {
public static void main(String[] args) {
// получаем сессию
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
try {
// начинаем транзакцию
session.beginTransaction();
//создаем pojo-объек
Person person = new Person();
//заполняем его данными
person.setFirstName("Vit");
person.setLastName("Lo");
Calendar c =Calendar.getInstance();
c.set(2009, 11, 4);
person.setBirthDate(c.getTime());//new Date(2009, 11, 3));
//сохраняем в сессии и в БД применяем транзакцию
session.save(person);
session.getTransaction().commit();
} finally {
//если открыта сессия закрываем её
if (session.isOpen()) session.close();
}
}
}
Какие мы библиотеки должны положить в classpath - всё это написано в файле ./hibernate-3.2.0/lib/README.txt пробегаемся по библиотекам и:
commons-logging-1.0.4.jar (1.0.4)
- Commons Logging
- runtime, required
- runtime, required - говорит что необходима при выполнении (НУЖНО ВСЕГДА)
c3p0-0.9.0.jar (0.9.0)
- C3P0 JDBC connection pool
- runtime, optional
- runtime, optional - говорит что необходима, если настроили hibernate c C3P0 JDBC pool'om при выполнении можно не включать(ЕСЛИ НАСТРОИЛИ Кинуть в classpath)
checkstyle-all.jar (unknown)
- Checkstyle
- buildtime
- buildtime - необходима при компиляции библиотек hibernat'a (сборка из исходников)
(НЕ НУЖНО)
+ нужно кинуть драйверок mysql-connector-java-3.1.13-bin.jar.
Скачиваем архив, Собираем проект и запускаем на выполнение:
# ant
....
[echo] If you see this, it works!!!
BUILD SUCCESSFUL
Total time: 3 seconds
Лезем в БД и видим запись:
1 Vit Lo 4.12.2009
ЗЫ ВАЖНО уточните пользователя, пароль и путь к вашей БД, скачав исходник в папку lib - положите все необходимые библиотеки hibernate-3.2.0 + mysql-connector-java-3.1.13-bin.jar
| Вложение | Размер |
|---|---|
| hibernat3_1.zip | 11.28 кб |


Супер! Наконец-то кто-то
Супер! Наконец-то кто-то внятно объяснил. Спасибо, vit. А как оно по скорости по сравнению с обычными SQL-запросами? Если, например, надо обрабатывать в единицу времени огромное количество запросов насколько Hibernate уступает стандартному PreparedStatement?
не пойму что с сайтом по 1
не пойму что с сайтом по 1 недели доступа нет :) :) :) Hebernate - это обертка над JDBC соответственно она чуть медленей работает! попробуй тест какой нибудь прогнать допустим 10 000 записей считать :) Для сайтов самое то, но если быстродействие нужно всетаки JDBC - побыстрее будет :)
сохраняются связанные
сохраняются связанные обекты без транзакций
Здравствуйте!
Не могли бы Вы мне помочь
У меня следующая проблема:
я не использую транзакции в хибернейте,и, как следствие, часть методов действительно не пишет в базу, но есть методы, которые сохраняют объекты в базу вопреки логике
есть три бина
Section:Worker=one-to-many
section
@Entity
@Table(name = "sectionTable")
public class Section {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "section_id")
private int sectionId;
@Column(name = "section_name")
private String sectionName;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "section")
private List<Worker> workers;
public Section() {
}
public Section(int sectionId) {
this.sectionId = sectionId;
}
getters,setters...
}
worker
@Entity
@Table(name = "workerTable")
public class Worker {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "worker_id")
private int workerId;
@Column(name = "firstname")
private String firstName;
@Column(name = "lastname")
private String lastName;
@Column(name = "salary")
private String salary;
@Column(name = "birthDate")
private String birthDate;
@Column(name = "active")
private String active;
@ManyToOne(cascade = { CascadeType.PERSIST }, fetch = FetchType.LAZY)
@JoinColumn(name = "section_id")
private Section section;
public Worker() {
this.firstName = "";
this.lastName = "";
this.birthDate = "";
this.active = "false";
this.salary = "0.00";
this.section = null;
}
getters,setters...
}
user
и есть бин, ни с кем не связанный
@Entity
@Table(name = "user")
public class User{
@Id
@Column(name = "login)
private String login;
@Column(name = "pass")
private String pass;
public User() {
}
getters,setters...
}
dao
public class DAO extends HibernateDaoSupport{
...
public void addSection(String sectionName) {
session = getSession();
Section section = new Section();
section.setSectionName(sectionName);
try {
session.save(section);
} catch (Exception e) {
log.error(e);
}
releaseSession(session);
};
//section сохраняется в базу, не смотря на отсутствие транзакций
public void addUser(String login, String password) {
session = getSession();
User user = new User();
user.setLogin(login);
user.setPass(password);
try {
session.save(user);
} catch (Exception e) {
log.error(e);
}
releaseSession(session);
};
//а вот этот метод не сохраняет в базу usera, потому что нет транзакции
}
//и все это в одном классе
мой applicationContext
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="myTxManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="dao" class="dataBase.DAO" lazy-init="true" scope="singleton">
<property name="sessionFactory" ref="sessionFactory"/>
<property name="init" value="true"/>
</bean>
<bean id="page" class="web.pages.Page">
<property name="dao" ref="dao"/>
</bean>
<bean id="workerList" class="web.pages.WorkerList"/>
<bean id="workerEditor" class="web.pages.WorkerEditor"/>
<bean id="sectionList" class="web.pages.SectionList"/>
<bean id="sectionEditor" class="web.pages.SectionEditor"/>
<bean id="aboutWorker" class="web.pages.AboutWorker"/>
<bean id="register" class="web.pages.Register"/>
<bean id="interceptor" class="web.Interceptor"/>
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="interceptor"/>
</list>
</property>
<property name="mappings">
<props>
mappings
</props>
</property>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" lazy-init="true" scope="singleton">
<property name="driverClassName" value="org.gjt.mm.mysql.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/webproject"/>
<property name="username" value="${login}"/>
<property name="password" value="${pass}"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" lazy-init="true" scope="singleton">
<property name="dataSource" ref="dataSource"/>
<property name="annotatedClasses">
<list>
<value>dataBase.beans.Section</value>
<value>dataBase.beans.User</value>
<value>dataBase.beans.Worker</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.transaction.flush_before_completion">true</prop>
<prop key="hibernate.transaction.auto_close_session">true</prop>
</props>
</property>
</bean>
</beans>
Словом, почему в случае с несвязанным бином отсутствие транзакции срабатывает, а в случае связи не работает?.. Можете помочь? Спасибо!
P.S. с section delete и update не работают(как и должно быть без транзакций)
Что за метод releaseSession
Что за метод releaseSession ?
Делается ли session.flush(); ?
Отправить комментарий