Ejemplo de Integración de Spring Hibernate Tutorial (Spring 4 + Hibernate 3 y Hibernate 4)

Spring es uno de los frameworks de Java EE más utilizados y Hibernate es el framework ORM más popular. Por eso, la combinación de Spring Hibernate se utiliza mucho en aplicaciones empresariales. Recientemente he escrito mucho sobre Tutorial de Spring y Tutorial de Hibernate, así que un artículo sobre integración de Spring Hibernate estaba pendiente desde hace mucho tiempo.

Spring Hibernate

Hoy, en este tutorial, utilizaremos Spring 4 e integraremos con Hibernate 3, luego actualizaremos el mismo proyecto para utilizar Hibernate 4. Dado que hay varias versiones tanto para Spring como para Hibernate, y el artefacto Spring ORM es compatible con Hibernate 3 y Hibernate 4, es bueno que liste todas las dependencias que he utilizado en mi proyecto. Ten en cuenta que he observado que no todas las versiones de Spring y Hibernate son compatibles. Las siguientes versiones han funcionado para mí, así que creo que son compatibles. Si estás utilizando otras versiones y obtienes un error `java.lang.NoClassDefFoundError`, significa que no son compatibles. En su mayoría, esto se debe a que las clases de Hibernate se han trasladado de un paquete a otro, causando este error. Por ejemplo, la clase `org.hibernate.engine.FilterDefinition` se trasladó a `org.hibernate.engine.spi.FilterDefinition` en las últimas versiones de Hibernate.

  • Versión del Marco de Trabajo Spring: 4.0.3.RELEASE

  • Versión del Núcleo de Hibernate y del Gestor de Entidades de Hibernate: 3.6.9.Final y 4.3.5.Final
  • Versión de Spring ORM: 4.0.3.RELEASE

Configuración de la Base de Datos

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;

Ejemplo de Estructura de Proyecto de Integración de Spring y Hibernate

A continuación se muestra la estructura final del proyecto. Vamos a revisar cada uno de los componentes uno por uno.

Dependencias de Maven

Primero, revisaremos nuestro archivo pom.xml para conocer todas las dependencias necesarias y sus versiones.

<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>

Dependencias importantes para el proyecto de integración de Spring e Hibernate son:

  • spring-context y spring-tx para las funcionalidades principales de Spring. Observa que estoy utilizando la versión 4.0.3.RELEASE.
  • Dependencia spring-orm para el soporte de Spring ORM, necesario para la integración de Hibernate en nuestro proyecto de Spring.
  • Dependencias hibernate-entitymanager y hibernate-core para el framework Hibernate. Observa que la versión es 3.6.9.Final; para usar Hibernate 4, solo necesitamos cambiarla a 4.3.5.Final, como se indica en el archivo pom.xml anterior.
  • mysql-connector-java para el controlador MySQL para la conexión a la base de datos.

Clase de modelo o Bean de entidad

Podemos usar el mapeo basado en XML de Hibernate, así como el mapeo basado en anotaciones JPA. Aquí estoy usando anotaciones JPA para el mapeo porque Hibernate proporciona implementación 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;
	}
}

Clases DAO

Implementaremos dos métodos en nuestras clases DAO, primero para guardar el objeto Persona en la tabla y segundo para obtener todos los registros de la tabla y devolver la lista de Personas.

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();
	
}

La implementación de la clase DAO sería como sigue.

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;
	}

}

Observe que este es el único lugar donde estamos utilizando clases relacionadas con Hibernate. Este patrón hace que nuestra implementación sea flexible y fácil de migrar de una tecnología a otra. Por ejemplo, si queremos usar el marco de trabajo ORM iBatis, todo lo que necesitamos es proporcionar una implementación DAO para iBatis y luego cambiar el archivo de configuración de beans de Spring. En el ejemplo anterior, estoy usando la gestión de transacciones de sesión de Hibernate. Pero también podemos usar la gestión de transacciones declarativa de Spring utilizando la anotación @Transactional, lee más en Gestión de Transacciones de Spring.

Archivo de Configuración de Beans de Spring para la Integración de Hibernate 3

Veamos primero las configuraciones de beans de primavera que necesitamos para la integración de Hibernate 3, profundizaremos más tarde.

<?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>

Hay dos formas en las que podemos proporcionar detalles de conexión a la base de datos a Hibernate, primero pasando todo en hibernateProperties y segundo creando un DataSource y luego pasándolo a hibernate. Prefiero el segundo enfoque, por eso tenemos la dependencia de Apache Commons DBCP para crear un BasicDataSource configurando las propiedades de conexión a la base de datos. Para la integración de Spring y Hibernate 3, Spring ORM proporciona dos clases: org.springframework.orm.hibernate3.LocalSessionFactoryBean cuando los mapeos de hibernate son basados en XML y org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean para mapeos basados en anotaciones. He proporcionado una configuración de bean simple de LocalSessionFactoryBean en comentarios, si estás utilizando mapeos basados en XML. AnnotationSessionFactoryBean extiende la clase LocalSessionFactoryBean, por lo que tiene todas las propiedades básicas para la integración de hibernate. Las propiedades son autoexplicativas y en su mayoría están relacionadas con hibernate, así que no entraré en muchos detalles para ellas. Pero si te preguntas de dónde vienen hibernateProperties, annotatedClasses, necesitas mirar el código fuente de la clase de bean. Observa la definición de bean de personDAO, como mencioné antes, si tenemos que cambiar a otro marco de ORM, necesitamos cambiar la clase de implementación aquí y configurar cualquier otra propiedad que necesitemos.

Programa de prueba de Spring 4 Hibernate 3

Nuestra configuración está lista ahora, escribamos un programa simple para probar nuestra aplicación.

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);
		}
		//cerrar recursos
		context.close();	
	}
}

Cuando ejecutamos el programa anterior, obtenemos mucha salida relacionada con Hibernate porque no he configurado adecuadamente el registro, pero eso está fuera del alcance de este tutorial. Sin embargo, obtenemos la siguiente salida generada por nuestro programa.

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

Cambios en la integración de Spring 4 Hibernate 4

Ahora cambiemos nuestra aplicación para usar Hibernate 4 en lugar de Hibernate 3. Para esta migración, solo necesitamos hacer los siguientes cambios de configuración.

  1. Cambiar la versión de Hibernate a 4.3.5.Final en el archivo pom.xml, como se muestra en los comentarios anteriores.

  2. Cambia el archivo de configuración de beans de primavera, hasta ahora debes haber deducido que el archivo de configuración de beans de Spring es clave para la integración del marco de Spring y Hibernate. El siguiente archivo de configuración de beans de primavera funcionará para las versiones Spring 4 y 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>
    
    
    <!-- Definición del bean de 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>
    

    Para Hibernate 4, necesitamos usar org.springframework.orm.hibernate4.LocalSessionFactoryBean para el bean de SessionFactory, Spring ORM ha fusionado ambas clases para Hibernate 3 y ahora hay una única clase, esto es bueno para evitar confusiones. Todas las demás configuraciones son iguales que antes.

Y eso es todo, nuestro proyecto se ha migrado con éxito a Hibernate 4, ¿no es genial? Solo cambie la clase SpringHibernateMain para usar spring4.xml para la configuración de los beans y funcionará bien, obtendrá la misma salida que antes. Puede descargar el proyecto final desde el siguiente enlace y experimentar con más configuraciones para aprender más.

Descargar Proyecto de Integración de Spring y Hibernate

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