Пример интеграции Spring Hibernate (Spring 4 + Hibernate 3 и Hibernate 4) Учебное пособие

Весна является одним из наиболее используемых фреймворков Java EE, а Hibernate – самым популярным фреймворком ORM. Поэтому комбинация Spring Hibernate часто используется в корпоративных приложениях. Недавно я много писал для руководства по Spring и руководства по Hibernate, так что статья о интеграции Spring и Hibernate давно была в должке.

Spring Hibernate

Сегодня, в этом учебнике, мы будем использовать Spring 4 и интегрировать его с Hibernate 3, а затем обновим тот же проект, чтобы использовать Hibernate 4. Поскольку существует множество версий как для Spring, так и для Hibernate, и артефакт Spring ORM поддерживает как Hibernate 3, так и Hibernate 4, хорошо, что я перечисляю все зависимости, которые я использовал в своем проекте. Обратите внимание, что я заметил, что не все версии Spring и Hibernate совместимы. Нижеуказанные версии работали для меня, поэтому я считаю, что они совместимы. Если вы используете другие версии и получаете ошибку java.lang.NoClassDefFoundError, то это означает, что они не совместимы. В основном это происходит потому, что классы Hibernate перемещаются из одного пакета в другой, вызывая эту ошибку. Например, класс org.hibernate.engine.FilterDefinition перемещен в org.hibernate.engine.spi.FilterDefinition в последних версиях Hibernate.

  • Версия Spring Framework: 4.0.3.RELEASE
  • Версия Hibernate Core и Hibernate EntityManager: 3.6.9.Final и 4.3.5.Final
  • Версия Spring ORM: 4.0.3.RELEASE

Настройка базы данных

I am using MySQL database for my project, so below setup.sql script will create the necessary table for this example.

CREATE TABLE `Person` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '',
  `country` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
commit;

Пример структуры проекта интеграции Spring и Hibernate

Ниже представлена окончательная структура проекта, мы рассмотрим каждый из компонентов поочередно.

Maven Dependencies

Сначала мы рассмотрим файл pom.xml для всех необходимых зависимостей и их версий.

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>org.springframework.samples</groupId>
	<artifactId>SpringHibernateExample</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>

		<!-- Generic properties -->
		<java.version>1.6</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

		<!-- Spring -->
		<spring-framework.version>4.0.3.RELEASE</spring-framework.version>

		<!-- Hibernate / JPA -->
		<!-- <hibernate.version>4.3.5.Final</hibernate.version> -->
		<hibernate.version>3.6.9.Final</hibernate.version>

		<!-- Logging -->
		<logback.version>1.0.13</logback.version>
		<slf4j.version>1.7.5</slf4j.version>

	</properties>

	<dependencies>
		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Spring ORM support -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Logging with SLF4J & LogBack -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
			<scope>runtime</scope>
		</dependency>

		<!-- Hibernate -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.version}</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>${hibernate.version}</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.9</version>
		</dependency>
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.4</version>
		</dependency>
	</dependencies>
</project>

Важные зависимости для проекта интеграции Spring и Hibernate:

  • spring-context и spring-tx для основных функций Spring. Обратите внимание, что используется версия 4.0.3.RELEASE.
  • Зависимость spring-orm для поддержки Spring ORM, она необходима для интеграции Hibernate в наш проект Spring.
  • Зависимости hibernate-entitymanager и hibernate-core для фреймворка Hibernate. Обратите внимание, что версия – 3.6.9.Final. Чтобы использовать Hibernate 4, достаточно заменить ее на 4.3.5.Final, как указано в вышеуказанном файле pom.xml.
  • mysql-connector-java для подключения к базе данных MySQL.

Класс модели или сущность Bean

Мы можем использовать отображение на основе Hibernate XML, а также отображение на основе аннотаций JPA. Здесь я использую аннотации JPA для отображения, потому что Hibernate предоставляет реализацию JPA.

package com.journaldev.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * Entity bean with JPA annotations
 * Hibernate provides JPA implementation
 * @author pankaj
 *
 */
@Entity
@Table(name="Person")
public class Person {

	@Id
	@Column(name="id")
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private int id;
	
	private String name;
	
	private String country;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}
	
	@Override
	public String toString(){
		return "id="+id+", name="+name+", country="+country;
	}
}

Классы DAO

Мы реализуем два метода в наших классах DAO: первый для сохранения объекта Person в таблице, и второй – для извлечения всех записей из таблицы и возврата списка объектов Person.

package com.journaldev.dao;

import java.util.List;

import com.journaldev.model.Person;

public interface PersonDAO {

	public void save(Person p);
	
	public List<Person> list();
	
}

Реализация вышеописанного класса DAO будет выглядеть следующим образом.

package com.journaldev.dao;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.journaldev.model.Person;

public class PersonDAOImpl implements PersonDAO {

	private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    
	@Override
	public void save(Person p) {
		Session session = this.sessionFactory.openSession();
		Transaction tx = session.beginTransaction();
		session.persist(p);
		tx.commit();
		session.close();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Person> list() {
		Session session = this.sessionFactory.openSession();
		List<Person> personList = session.createQuery("from Person").list();
		session.close();
		return personList;
	}

}

Обратите внимание, что это единственное место, где мы используем классы, связанные с Hibernate. Этот подход делает нашу реализацию гибкой и легкой в миграции с одной технологии на другую. Например, если мы хотим использовать фреймворк iBatis ORM, все, что нам нужно сделать, – предоставить реализацию DAO для iBatis, а затем изменить файл конфигурации бина Spring. В приведенном выше примере я использую управление транзакциями Hibernate session, но мы также можем использовать управление транзакциями Spring с использованием аннотации @Transactional, подробнее читайте в Управление транзакциями Spring.

Файл конфигурации бина Spring для интеграции Hibernate 3

Давайте сначала рассмотрим конфигурации spring bean, которые нам нужны для интеграции с Hibernate 3. Мы более подробно изучим это позже.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:aop="https://www.springframework.org/schema/aop"
	xmlns:tx="https://www.springframework.org/schema/tx"
	xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-4.0.xsd
		https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
		destroy-method="close">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://localhost:3306/TestDB" />
		<property name="username" value="pankaj" />
		<property name="password" value="pankaj123" />
	</bean>

<!-- Hibernate 3 XML SessionFactory Bean definition-->
<!-- 	<bean id="hibernate3SessionFactory"
		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="mappingResources">
			<list>
				<value>person.hbm.xml</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<value>
				hibernate.dialect=org.hibernate.dialect.MySQLDialect
			</value>
		</property>
	</bean> -->

<!-- Hibernate 3 Annotation SessionFactory Bean definition-->
	<bean id="hibernate3AnnotatedSessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="annotatedClasses">
			<list>
				<value>com.journaldev.model.Person</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
				<prop key="hibernate.current_session_context_class">thread</prop>
				<prop key="hibernate.show_sql">false</prop>
			</props>
		</property>
	</bean>
	
	<bean id="personDAO" class="com.journaldev.dao.PersonDAOImpl">
		<property name="sessionFactory" ref="hibernate3AnnotatedSessionFactory" />
	</bean>
</beans>

Есть два способа предоставить сведения о подключении к базе данных Hibernate: первый – передать все через hibernateProperties, а второй – создать источник данных (DataSource) и затем передать его в Hibernate. Я предпочитаю второй подход, поэтому у нас есть зависимость от Apache Commons DBCP для создания BasicDataSource с установкой свойств подключения к базе данных. Для интеграции Spring и Hibernate 3 Spring ORM предоставляет два класса: org.springframework.orm.hibernate3.LocalSessionFactoryBean, когда сопоставления Hibernate выполняются на основе XML, и org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean для сопоставления на основе аннотаций. Я предоставил простую конфигурацию бина LocalSessionFactoryBean в комментариях, если вы используете сопоставления на основе XML. AnnotationSessionFactoryBean расширяет класс LocalSessionFactoryBean, поэтому у него есть все основные свойства для интеграции с Hibernate. Свойства понятны по себе и в основном относятся к Hibernate, поэтому я не буду вдаваться в подробности по этим свойствам. Но если вы задаетесь вопросом, откуда берутся hibernateProperties, annotatedClasses, вам следует посмотреть в исходный код класса бина. Обратите внимание на определение бина personDAO, как я уже говорил, если нам нужно переключиться на другой фреймворк ORM, нам нужно изменить класс реализации здесь и установить любые другие необходимые свойства.

Программа тестирования Spring 4 Hibernate 3

Теперь наша настройка готова, давайте напишем простую программу для тестирования нашего приложения.

package com.journaldev.main;

import java.util.List;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.journaldev.dao.PersonDAO;
import com.journaldev.model.Person;

public class SpringHibernateMain {

	public static void main(String[] args) {

		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
		
		PersonDAO personDAO = context.getBean(PersonDAO.class);
		
		Person person = new Person();
		person.setName("Pankaj"); person.setCountry("India");
		
		personDAO.save(person);
		
		System.out.println("Person::"+person);
		
		List list = personDAO.list();
		
		for(Person p : list){
			System.out.println("Person List::"+p);
		}
		// закрытие ресурсов
		context.close();	
	}
}

При выполнении вышеуказанной программы мы получаем много вывода, связанного с Hibernate, потому что я не настроил логирование должным образом, но это не входит в рамки данного руководства. Тем не менее, мы получаем следующий вывод, сгенерированный нашей программой.

Person::id=3, name=Pankaj, country=India
Person List::id=1, name=Pankaj, country=India
Person List::id=2, name=Pankaj, country=India
Person List::id=3, name=Pankaj, country=India

Изменения в интеграции Spring 4 Hibernate 4

Теперь давайте изменим наше приложение так, чтобы оно использовало Hibernate 4 вместо Hibernate 3. Для этого мигрирования нам нужно сделать только следующие изменения в конфигурации.

  1. Измените версию Hibernate на 4.3.5.Final в файле pom.xml, как показано в комментариях выше.

  2. Измените файл конфигурации spring bean, до сих пор вы, должно быть, уже поняли, что файл конфигурации spring bean является ключом для интеграции фреймворков Spring и Hibernate. Ниже приведен файл конфигурации spring bean, который будет работать для версий Spring 4 и Hibernate 4.

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="https://www.springframework.org/schema/beans"
    	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:aop="https://www.springframework.org/schema/aop"
    	xmlns:tx="https://www.springframework.org/schema/tx"
    	xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    		https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-4.0.xsd
    		https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
    
    	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    		destroy-method="close">
    		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
    		<property name="url" value="jdbc:mysql://localhost:3306/TestDB" />
    		<property name="username" value="pankaj" />
    		<property name="password" value="pankaj123" />
    	</bean>
    
    
    <!-- Определение бина SessionFactory Hibernate 4 -->
    <bean id="hibernate4AnnotatedSessionFactory"
    		class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    		<property name="dataSource" ref="dataSource" />
    		<property name="annotatedClasses">
    			<list>
    				<value>com.journaldev.model.Person</value>
    			</list>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
    				<prop key="hibernate.current_session_context_class">thread</prop>
    				<prop key="hibernate.show_sql">false</prop>
    			</props>
    		</property>
    	</bean>
    
    	
    	<bean id="personDAO" class="com.journaldev.dao.PersonDAOImpl">
    		<property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
    	</bean>
    </beans>
    

    Для Hibernate 4 нам необходимо использовать org.springframework.orm.hibernate4.LocalSessionFactoryBean для бина SessionFactory, Spring ORM объединил обе классы для Hibernate 3, и теперь есть только один класс, что хорошо для избежания путаницы. Все остальные конфигурации такие же, как раньше.

Вот и все, наш проект успешно мигрировал на Hibernate 4, аккуратно, не так ли. Просто измените класс SpringHibernateMain, чтобы использовать spring4.xml для конфигурации бинов, и все будет работать нормально, вы получите тот же результат, что и раньше. Вы можете скачать финальный проект по ссылке ниже и поиграть с дополнительными конфигурациями, чтобы узнать больше.

Скачать проект интеграции Spring Hibernate

Source:
https://www.digitalocean.com/community/tutorials/spring-hibernate-integration-example-tutorial