`
frank-liu
  • 浏览: 1684058 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

spring学习:hibernate orm集成

 
阅读更多

简介

    使用spring访问数据的框架就少不了使用到hibernate。 最近尝试手动去构建一些这样的示例时碰到了不少问题。本文结合hibernate 3, hibernate 4两个版本实现一个示例的过程,顺便也对它们的配置与使用做一个总结。

 

示例

    我们从一个简单的对一个实体类进行增删查改的操作来看怎么使用hibernate。因为针对不同版本的hibernate,后面的配置有点不一样,这里会专门标注出来。

 

依赖关系定义 

    假设我们使用hibernate4和spring4集成,则依赖的pom.xml文件定义如下:

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

	<name>SpringExample</name>
	<url>http://maven.apache.org</url>

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

        <!-- Hibernate -->
        <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>org.apache.commons</groupId>
    		<artifactId>commons-dbcp2</artifactId>
    		<version>2.1</version>
	</dependency>

	<dependency>
    		<groupId>javax.inject</groupId>
    		<artifactId>javax.inject</artifactId>
    		<version>1</version>
	</dependency>
	<dependency>
    		<groupId>org.hibernate</groupId>
    		<artifactId>hibernate-validator</artifactId>
    		<version>5.1.3.Final</version>
	</dependency>
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.11</version>
		<scope>test</scope>
	</dependency>
    </dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.2</version>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

     以上是程序主要所依赖的包,主要包含的和程序相关的有spring-context, spring-tx,和hibernate相关的有hibernate-core, hibernate-validator。留意到前面配置里设定的hibernate-core的版本是4,所以这部分主要针对hibernate4的配置。而对于hibernate3的依赖,只需要修改一下前面hibernate-core依赖项的版本号就可以了。

 

对象模型定义

     我们首先需要在数据库中创建一个表contact:

   

drop table if exists contact;
create table contact (
    id bigint unsigned not null auto_increment primary key,
    last_name varchar(40) not null,
    first_name varchar(40) not null,
    mi char(1),
    email varchar(80),
    date_created timestamp default 0,
    date_modified timestamp default current_timestamp on update current_timestamp,
    unique index contact_idx1 (last_name, first_name, mi)
) engine = InnoDB;

    以上仅仅是一个普通的表定义。为了实现对应的实体类映射,我们需要做一个如下的定义:

 

package com.yunzero.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;


/**
 * @author Willie Wheeler (willie.wheeler@gmail.com)
 */
@Entity
@Table(name = "contact")
@NamedQuery(
	name = "findContactsByEmail",
	query = "from Contact where email like :email")
public class Contact {
	private Long id;
	private String lastName;
	private String firstName;
	private String middleInitial;
	private String email;
	
	@Id
	@Column
	@GeneratedValue(strategy = GenerationType.AUTO)
	public Long getId() { return id; }
	
	public void setId(Long id) { this.id = id; }
	
	@NotNull
	@Length(min = 1, max = 40)
	@Column(name = "last_name")
	public String getLastName() { return lastName; }
	
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	
	@NotNull
	@Length(min = 1, max = 40)
	@Column(name = "first_name")
	public String getFirstName() { return firstName; }
	
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	
	@Length(max = 1)
	@Column(name = "mi")
	public String getMiddleInitial() { return middleInitial; }
	
	public void setMiddleInitial(String mi) {
		this.middleInitial = mi;
	}
	
	@Email
	@Column
	public String getEmail() { return email; }
	
	public void setEmail(String email) {
		this.email = email;
	}
	
	@Transient
	public String getFullName() {
		String fullName = lastName + ", " + firstName;
		if (! (middleInitial == null || "".equals(middleInitial.trim()))) {
			fullName += " " + middleInitial + ".";
		}
		return fullName;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "[Contact: id=" + id
			+ ", firstName=" + firstName
			+ ", middleInitial=" + middleInitial
			+ ", lastName=" + lastName
			+ ", email=" + email
			+ "]";
	}
}
    其实上述的代码也没有什么特殊的。Table标记对应映射到某个数据库表,Length, Column对应某些列和它的长度。针对对数据库操作的实现常用的模式是首先定义一个DAO接口如下:

 

package com.yunzero.service;

import java.util.List;

import com.yunzero.model.Contact;


public interface ContactService {

	void createContact(Contact contact);

	List<Contact> getContacts();
	
	List<Contact> getContactsByEmail(String email);


	Contact getContact(Long id);
	
	void updateContact(Contact contact);

	void deleteContact(Long id);
}
    有了这个接口之后然后就是对它的具体实现了:

 

package com.yunzero.service.impl;

import static org.springframework.util.Assert.notNull;

import java.util.List;

import javax.inject.Inject;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.yunzero.model.Contact;
import com.yunzero.service.ContactService;


@Service
@Transactional
public class ContactServiceImpl implements ContactService {
	@Inject private SessionFactory sessionFactory;

	@Override
	public void createContact(Contact contact) {
		notNull(contact, "contact can't be null");
		getSession().save(contact);
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<Contact> getContacts() {
		return getSession()
			.createQuery("from Contact")
			.list();
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public List<Contact> getContactsByEmail(String email) {
		notNull(email, "email can't be null");
		return getSession()
			.getNamedQuery("findContactsByEmail")
			.setString("email", "%" + email + "%")
			.list();
	}

	@Override
	public Contact getContact(Long id) {
		notNull(id, "id can't be null");
		return (Contact) getSession().get(Contact.class, id);
	}

	@Override
	public void updateContact(Contact contact) {
		notNull(contact, "contact can't be null");
		getSession().update(contact);
	}

	@Override
	public void deleteContact(Long id) {
		notNull(id, "id can't be null");
		getSession().delete(getContact(id));
	}
	
	private Session getSession() {
		return sessionFactory.getCurrentSession();
	}
}
    ContactServiceImpl的实现能够操作数据库就依赖于sessionFactory。而后面最关键的部分就是对sessionFactory的定义和注入。sessionFactory在这里类似于一个实现了一部分功能的类,可以将一些执行对应sql语句的功能强化一下。

    针对Hibernate 3, 4,他们的定义和实现有不同。我们再来看看他们的配置。

 

Hibernate4

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:c="http://www.springframework.org/schema/c"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    	http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.1.xsd">
 
    <context:property-placeholder location="classpath:/environment.properties" />
	
	<bean id="dataSource"
		class="org.apache.commons.dbcp2.BasicDataSource"
		destroy-method="close"
		p:driverClassName="${dataSource.driverClassName}"
		p:url="${dataSource.url}"
		p:username="${dataSource.username}"
		p:password="${dataSource.password}" />

	<bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses">
            <list>
                <value>com.yunzero.model.Contact</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">false</prop>
            </props>
        </property>
    </bean>
    
    <bean id="transactionManager"
    	class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    	<property name="sessionFactory" ref="sessionFactory" />
   </bean>

	<tx:annotation-driven />
	
	<context:component-scan base-package="com.yunzero.service.impl" />
	
</beans>
     一个需要注意的地方就是,在hibernate4里,我们定义的sessionFactory需要用到的类是:org.springframework.orm.hibernate4.LocalSessionFactoryBean。另外,在前面定义的ContactServiceImpl类里我们定义了Transactional修饰,表示所有的方法执行都是事物性的。为了能够支持事物,需要在配置里定义transactionManager以及对这些Transactional修饰的支持。spring需要扫描给定的包范围来找到需要进行事物包装的类和方法。所以这里还需要增加一个<tx:annotation-driven/>。

 

 hibernate 3

   

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:c="http://www.springframework.org/schema/c"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jee="http://www.springframework.org/schema/jee"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context-3.1.xsd
		http://www.springframework.org/schema/jee
		http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
		http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
		http://www.springframework.org/schema/util
		http://www.springframework.org/schema/util/spring-util-3.1.xsd">
	
	<context:property-placeholder location="classpath:/environment.properties" />
	
	<bean id="dataSource"
		class="org.apache.commons.dbcp2.BasicDataSource"
		destroy-method="close"
		p:driverClassName="${dataSource.driverClassName}"
		p:url="${dataSource.url}"
		p:username="${dataSource.username}"
		p:password="${dataSource.password}" />
	
	<util:properties id="hibernateProperties">
		<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
		<prop key="hibernate.show_sql">false</prop>
	</util:properties>
	
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
		p:dataSource-ref="dataSource"
		p:packagesToScan="com.yunzero.model"
		p:hibernateProperties-ref="hibernateProperties" />
	
	<bean id="transactionManager"
		class="org.springframework.orm.hibernate3.HibernateTransactionManager"
		p:sessionFactory-ref="sessionFactory" />
	
	<tx:annotation-driven />
	
	<context:component-scan base-package="com.yunzero.service.impl" />
</beans>

    hibernate3使用的sessionFactory类不一样,是org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean。它的配置其实和前面的没什么区别。

     程序执行的代码如下:

package org.springframework.samples.SpringExample;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.yunzero.model.Contact;
import com.yunzero.service.ContactService;


public class App 
{
    public static void main( String[] args )
    {
    	ClassPathXmlApplicationContext context = 
    			new ClassPathXmlApplicationContext("beans-service.xml");
    	ContactService service = context.getBean(ContactService.class);
    	for(Contact contact : service.getContacts()) {
    		System.out.println(contact.toString());
    	}
    	context.close();
    }
}

    这里是列出来了表里面所有项。和普通使用spring的方式没什么差别。

 

总结

    用spring集成hibernate去操作数据库算是最典型的orm应用。其实这种方式没有什么特别的,都是固定的套路,就是里面的配置要小心。尤其针对hibernate 3和hibernate 4这两个版本。由于版本的变化带来一些使用的差别,在配置的时候一旦引用错了库会导致错误,而且查找这些错误还比较麻烦。在测试上面的示例程序时也存在一些环境依赖的坑,比如说如果安装的java版本是8的话,修改配置之后运行程序会出现一些错误,而在低版本的环境下没有。

    上述办法其实还存在一个不足的地方,就是我们需要定义数据库表,然后定义实体类和表的映射。这样其实还是比较繁琐的。如果有一种办法可以让我们更关注于业务逻辑的定义而不用太操心数据库表的定义是不是更好呢?其实在之前讨论JPA的文章里已经实现过类似的示例了。如果用过ruby on rails或者django之类框架的会很熟悉这种套路。这种模式是采用定义实体对象类,通过它来映射生成对应的数据库表。这样一方面可以提高效率,同时也提高了代码的可移植性。在后面的文章里我会结合spring和jpa来讨论实现这种套路。

 

参考材料

spring in practice

spring in action

分享到:
评论

相关推荐

    Spring与Hibernate集成

    **Spring与Hibernate集成详解** 在Java企业级应用开发中,Spring和Hibernate是两个非常重要的框架。Spring是一个全方位的轻量级应用框架,提供了强大的依赖注入、AOP(面向切面编程)以及各种服务管理功能。而...

    hibernate-orm-master.zip

    5. **配置与集成**:Hibernate的配置文件(hibernate.cfg.xml)用于设置数据库连接信息、缓存策略等,而在Spring框架中,通常通过SessionFactoryBean进行集成,实现依赖注入。 在实际开发中,理解并熟练运用这些...

    spring4.2+hibernate5环境开发全部jar包

    在实际项目中,这个压缩包"spring4.2+hibernate5"包含了所有开发所需的基础库,包括Spring核心模块、Spring MVC、Spring ORM(与Hibernate集成)以及Hibernate本身,还有可能包含一些依赖的JDBC驱动和其他辅助库。...

    org.springframework.orm.hibernate3.LocalSessionFactoryBean

    ### 关于 "org.springframework.orm.hibernate3.LocalSessionFactoryBean" 未找到问题的知识点解析 #### 一、问题背景 在开发基于Spring与Hibernate整合的应用时,可能会遇到“`org.springframework.orm.hibernate...

    Spring2 Hibernate3集成

    ### Spring2 Hibernate3集成知识点详解 #### 一、Spring与Hibernate简介 - **Spring框架**:作为一款轻量级的Java开发框架,Spring的核心特性包括依赖注入(DI)和面向切面编程(AOP),这使得它在企业级应用开发...

    SpringMVC+Spring3+hibernate4集成必备jar包

    5. spring-orm.jar:支持ORM框架,如Hibernate。 **Hibernate4** Hibernate是一个流行的Java ORM(对象关系映射)框架,它简化了数据库操作,使得开发者可以使用面向对象的方式处理数据库。在集成Hibernate4时,...

    spring-orm-hibernate4源码

    Spring ORM框架与Hibernate4的集成是Java开发中的常见实践,这个源码库提供了直接导入Eclipse工程的便利,让我们有机会深入了解这两个强大工具的内部工作机制。本文将围绕Spring如何管理和驱动Hibernate4进行详细的...

    spring4集成hibernate3:xml方式

    在IT行业中,Spring框架与Hibernate的集成是常见的数据访问技术组合,它们可以帮助开发者构建高效、模块化的应用程序。本文将深入探讨如何在Spring 4中集成Hibernate 3,以XML配置方式进行,这是一种相对传统但仍然...

    Spring之Spring2.5集成Hibernate3.6

    在IT行业中,Spring框架是Java开发中的一个核心组件,它为构建企业级应用程序提供了全面的解决...为了深入学习和实践这个集成,你可以尝试从其他来源获取类似项目的代码示例,或者参考Spring和Hibernate的官方文档。

    spring 与hibernate的集成

    通过这种方式,Spring和Hibernate成功集成,使得我们可以利用Spring的IoC和AOP特性来管理事务,同时利用Hibernate进行高效的数据持久化操作。这种集成方式大大提高了代码的可维护性和开发效率,降低了系统的耦合度。

    spring 2.5.6和hibernate3.2.2集成(1)

    在IT行业中,Spring和Hibernate是两个非常重要的框架,它们分别在应用上下文管理和对象关系映射(ORM)方面发挥着核心作用。这篇博客"spring 2.5.6和hibernate3.2.2集成(1)"显然是关于如何将这两个版本的框架整合...

    Spring集成Hibernate所需jar包

    在Java企业级开发中,Spring和Hibernate是两个非常重要的框架,Spring作为一个全面的轻量级容器,负责管理和协调应用组件,而Hibernate则是一个强大的对象关系映射(ORM)框架,处理数据库交互。将这两个框架集成...

    struts1+spring2.5+hibernate3.0集成带数据库

    Struts1、Spring2.5和Hibernate3.0是Java Web开发中经典的SSH(Spring、Struts、Hibernate)集成框架的三个组件,它们在2000年代末期至2010年代初广泛应用于企业级应用开发。SSH框架组合为开发者提供了模型-视图-...

    spring-orm.jar

    3. AOP集成:Spring的面向切面编程(AOP)使得可以在全局范围内处理持久化逻辑,如日志、事务控制等。 4. 对象/关系映射工具:Spring ORM为不同的ORM框架提供统一的API,减少学习成本,同时提高了代码的可移植性。 ...

    Spring Persistence with Hibernate

    3. Spring与Hibernate集成:如何在Spring应用中配置和使用Hibernate,包括SessionFactory的配置、事务管理、数据源的设置等。 4. ORM实践:使用Hibernate注解进行对象关系映射,以及HQL和Criteria查询的使用。 5. ...

    spring和hibernate集成Demo

    在IT领域,Spring和Hibernate是两个非常重要的框架,它们分别在应用上下文管理和持久化层提供了强大的支持。...这个Demo提供了学习和实践的基础,帮助开发者理解如何在Spring环境下有效地利用Hibernate进行数据库操作。

    spring-boot 集成hibernate

    在本文中,我们将深入探讨如何将Spring Boot与Hibernate集成,并使用Druid作为数据库连接池。首先,我们需要理解这三个核心组件: 1. **Spring Boot**: 是一个由Pivotal团队提供的开源框架,它简化了创建独立的、...

    springmvc-spring4.3-hibernate5框架整合

    标题 "springmvc-spring4.3-hibernate5框架整合" 暗示了这是一个关于集成Spring MVC、Spring 4.3和Hibernate 5的项目。这个项目可能是一个基础的Web应用开发环境,用于演示或教学如何将这三大流行Java框架协同工作。...

    org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException

    标题中的"org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException"是一个具体的异常类型,源自Spring框架的Hibernate4模块。这个异常通常在乐观锁(Optimistic Locking)机制失败时抛出,...

Global site tag (gtag.js) - Google Analytics