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

spring学习:与JPA的实现集成

 
阅读更多

简介

    在前一篇文章里我们讨论了spring4和 hibernate3, hibernate4的集成。在前面示例中通过这种方式访问数据库有一些可以改进的地方。一个是原来的service实现里直接关联了sessionFactory,实际上在service这个业务的层面不应该关注具体的数据存储操作。另外一个就是使用hibernate导致和它的紧密绑定。如果以后我们想要用其他的orm框架的话,还是有一些麻烦。于是这里针对这几个方面做一些改进。

 

结构改造

    我们先来看第一个问题,在原来的示例里,ContactServiceImpl是直接引用了sessionFactory。如果我们仔细思考一下,会发现这里有一些可以改进的地方。首先一个,我们对数据的操作可以放到专门定义的DAO包里。这样我们还需要定义一个通用的接口。在这个通用的接口里定义最常用的CRUD操作。然后对于不同类的具体数据访问,我们可以再继承这个接口实现特定的类。按照这个思路,我们定义后面的类结构如下图:

    如前面所述,接口DAO是一个泛型的接口,它针对的是通用的数据类型的CRUD。针对具体示例中Contact类型,它有一个专门的ContactDao接口,除了类型特别针对Contact以外,它还包含了对于Contact数据的特别操作,比如findByEmail。而对于前面Dao接口的一个通用实现就放在抽象类AbstractHbnDao里。我们要实现的类HbnContactDao只需要继承它就自动获得了基本的CRUD功能了。

    按照这个思路的具体实现如下:

    Dao:

    

package com.yunzero.dao;

import java.io.Serializable;
import java.util.List;

public interface Dao<T extends Object> {
	
	void create(T t);
	
	T get(Serializable id);
	
	T load(Serializable id);
	
	List<T> getAll();
	
	void update(T t);
	
	void delete(T t);
	
	void deleteById(Serializable id);
	
	void deleteAll();
	
	long count();
	
	boolean exists(Serializable id);
}
     这里通用的地方就在于它是采用泛型的类型。还要一个值得注意的地方就是里面get, load, delete,exists等方法的参数是使用Serializable类型。这是因为我们在定义数据库表的键值时通常选用int, long等类型。而在java里,Integer, Long类型都是实现Serializable接口的,可以更通用一些。

 

    AbstractHbnDao的实现如下:

 

public abstract class AbstractHbnDao<T extends Object> implements Dao<T> {
	@PersistenceContext
	private EntityManager entityManager;
	private Class<T> domainClass;
	
	protected Session getSession() {
		return entityManager;
	}
	
	@SuppressWarnings("unchecked")
	private Class<T> getDomainClass() {
	    if (domainClass == null) {
	    	ParameterizedType thisType = (ParameterizedType) getClass().getGenericSuperclass();
	        this.domainClass = (Class<T>) thisType.getActualTypeArguments()[0];
	    }
	    return domainClass;
	}
	
	private String getDomainClassName() { return getDomainClass().getName(); }
	
	@Override
	public void create(T t) {
		
		// If there's a setDateCreated() method, then set the date.
		Method method = ReflectionUtils.findMethod(
				getDomainClass(), "setDateCreated", new Class[] { Date.class });
		if (method != null) {
			try {
				method.invoke(t, new Date());
			} catch (Exception e) {
				// Ignore any exception here; simply abort the setDate() attempt
			}
		}
		
		getSession().save(t);
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public T get(Serializable id) {
		return (T) getSession().get(getDomainClass(), id);
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public T load(Serializable id) {
		return (T) getSession().load(getDomainClass(), id);
	}
	
	@SuppressWarnings("unchecked")
	public List<T> getAll() {
		return getSession()
			.createQuery("from " + getDomainClassName())
			.list();
	}
	
	@Override
	public void update(T t) { getSession().update(t); }
	
	@Override
	public void delete(T t) { getSession().delete(t); }
	
	@Override
	public void deleteById(Serializable id) { delete(load(id)); }
	
	@Override
	public void deleteAll() {
		getSession()
			.createQuery("delete " + getDomainClassName())
			.executeUpdate();
	}
	
	@Override
	public long count() {
		return (Long) getSession()
			.createQuery("select count(*) from " + getDomainClassName())
			.uniqueResult();
	}
	
	@Override
	public boolean exists(Serializable id) { return (get(id) != null); }
}
    有了这个基础,HbnContactDao的实现就很简单了:
package com.yunzero.dao.hibernate;

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

import java.util.List;

import org.springframework.stereotype.Repository;

import com.yunzero.dao.ContactDao;
import com.yunzero.model.Contact;

@Repository
public class HbnContactDao extends AbstractHbnDao<Contact> implements ContactDao {

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

jpa

    前面的实现里已经把jpa的部分东西给用起来了。hibernate和jpa是一个什么样的关系呢?其实,hibernate最早出来作为一个orm的框架时,它带动了一个标准的成立。就是JPA这个规范。针对jpa这个规范的实现有很多,除了hibernate本身,还要eclipselink, openjpa等。所以,如果我们在实现中需要考虑不同的jpa实现时,为了保持这种灵活性,尽量使得使用的包和类是jpa 规范定义的。

    在前面的代码里,我们就可以看到差别。以前的示例是通过配置sessionFactory,而这里是配置的entityManager。因为我们实际上还是使用的hibernate,只是按照jpa规范的方式来用。这里就需要修改一下配置。

 

配置

     具体的配置文件如下:

<?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="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
		p:dataSource-ref="dataSource"
		p:packagesToScan="com.yunzero.model">
		
		<property name="persistenceProvider">
			<bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
		</property>
		<property name="jpaProperties">
			<props>
				<prop key="hibernate.hbm2ddl.auto">update</prop>
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
				<prop key="hibernate.show_sql">false</prop>
			</props>
		</property>
	</bean>
	
	<bean id="transactionManager"
		class="org.springframework.orm.jpa.JpaTransactionManager"
		p:entityManagerFactory-ref="entityManagerFactory" />
	
	<tx:annotation-driven />
    
    <!-- These automatically register the PersistenceAnnotationBeanPostProcessor, as indicated above. -->
	<context:component-scan base-package="com.yunzero.dao.jpa" />
	<context:component-scan base-package="com.yunzero.service.impl" />

</beans>

   这里配置的要点是entityManagerFactory,它实际上对应org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean,而使用的persistenceProvider是org.hibernate.jpa.HibernatePersistenceProvider这个类。

    还要一个比较有意思的地方就是配置项hibernate.hbm2ddl.auto,它配置的值为update。使用这个属性有一个作用。就是它可以自动生成数据库的表。除了update这个配置项,还要其他的选项。有了这个配置的话,当数据库里不存在对应的数据库表的话,它会自动生成表。这种方式带来的一个好处就是如果所有表都是通过orm自动生成的,它对于数据库的迁移有很大的好处。不需要人为的去考虑不同数据库平台的变化。每次选择好对应的数据库驱动就可以了 。另外,这种方式使得我们只需要关注领域模型的定义,对应的数据库表自动生成了。使用过ruby on rails或者django的同学会更加有深刻的体会。

 

总结

     spring和jpa实现的集成相当于一种官方规范的实现。它可以实现不同orm框架之间的切换而且不需要修改一行代码。最关键的是当使用spring和jpa框架集成的时候,需要考虑数据访问层的抽象和结构。里面的巧妙之处值得仔细推敲。

 

参考材料

spring in practice

spring in action

  • 大小: 14.2 KB
分享到:
评论

相关推荐

    spring学习:spring data jpa

    6. **Integration with Spring Transaction Management**:Spring Data JPA与Spring的事务管理无缝集成,可以方便地进行事务控制。 在实际使用中,我们需要配置Spring Data JPA,这通常涉及到以下步骤: 1. 添加...

    Spring和openJPA集成

    Spring 是一个强大的轻量级应用框架,而 OpenJPA 是一个开源的 Java Persistence API (JPA) 实现,它允许开发者将对象关系映射(ORM)功能无缝集成到应用程序中。在本文中,我们将深入探讨如何将 Spring 框架与 Open...

    Spring-data-jpa常用教程.pdf

    Spring-data-jpa 与 Spring 的整合非常紧密,它利用 Spring 的依赖注入和事务管理功能,使得开发者可以轻松地在应用程序中集成数据访问逻辑。下面将详细介绍整合的关键步骤: 1. **配置 JPA 实体管理器**: - 在 ...

    spring boot 集成JPA

    Spring Boot 集成 JPASpring Boot 集成 JPASpring Boot 集成 JPASpring Boot 集成 JPASpring Boot 集成 JPASpring Boot 集成 JPA

    Spring MVC 集成JPA

    #### 四、Spring MVC中的JPA集成步骤 1. **添加依赖**:在Maven或Gradle项目中添加Spring MVC、Spring Data JPA以及相应的数据库驱动的依赖。 2. **配置数据源**:在Spring配置文件中定义数据源,例如使用`...

    使用SpringBoot 集成Spring-data-jpa,Druid连接池,thymeleaf模板实现的一个简单网上商城项目.rar

    综上所述,这个项目利用SpringBoot简化项目构建,通过Spring-data-jpa与JPA集成实现高效的数据操作,Druid提供稳定高效的数据库连接管理,而Thymeleaf则负责前端模板的渲染,形成了一套完整的前后端分离的简单网上...

    Spring集成Jpa(Hibernate实现)

    这个"Spring集成JPA(Hibernate实现)"的例子,涵盖了从基础配置到实际使用的完整流程,对于理解Spring与JPA的集成非常有帮助。通过这个示例,开发者能够学习如何避免因版本不兼容而引发的问题,更好地掌握Spring与...

    Spring Data JPA中文文档[1.4.3]_springdatajpa_erlang_waitxpf_

    **Spring Data JPA** 是一个基于 **Java** 的开源框架,它是 **Spring Framework** 的一个模块,主要用于简化 **Java Persistence...在学习过程中,结合实际编程实践,能更好地理解和掌握 Spring Data JPA 的强大功能。

    SpringBoot + SpringSecurity + JPA 实现用户角色权限登录认证

    6. **security-jpa**:此文件名可能是某个模块或者配置文件,可能包含了与SpringSecurity和JPA整合的具体实现,比如用户Repository、安全配置类等。在项目中,它可能负责定义如何使用JPA来操作用户角色和权限数据,...

    SpringMVC+Spring+SpringDataJPA+Hibernate整合登录的效果

    这是整合SpringMVC+Spring+SpringDataJPA+Hibernate简单的实现登录的功能,用的是mysql数据库,这是一个web Project 如果你用的是JavaEE6那么你要注意bean-validator.jar和weld-osgi-bundle.jar与slf4j的jar包冲突。...

    Spring Data JPA系列2:SpringBoot集成JPA详细教程,快速在项目中熟练使用JPA.doc

    Spring Data JPA 在 Spring Boot 项目中的集成与应用 Spring Data JPA 是一款基于 Java 持久层 API(JPA)的框架,提供了一个通用的数据访问层解决方案,能够简化 Java 应用程序中的数据访问工作。Spring Boot 作为...

    spring mvc spring spring jpa集成

    在本教程中,我们将探讨如何将这些框架与MySQL数据库进行集成,以便实现数据的持久化存储。 Spring MVC 是Spring框架的一个模块,主要负责处理HTTP请求并返回响应。它提供了一个模型-视图-控制器(MVC)架构,使...

    Spring2.5集成JPA

    二、Spring 2.5与JPA集成的优势 1. 解耦:Spring的IoC容器能够管理JPA的EntityManager,使得业务逻辑与数据访问层之间实现解耦。 2. AOP支持:Spring的AOP(面向切面编程)可以用于事务管理,简化了事务处理代码。 3...

    Spring Data JPA 笔记

    5. **事务管理**:Spring Data JPA集成Spring的事务管理,可以方便地在方法级别控制事务的开始、提交、回滚,确保数据一致性。 6. ** auditing**:Spring Data JPA还提供了审计功能,通过`@CreationTimestamp`和`@...

    spring学习:hibernate orm集成

    确保包含Hibernate的核心库、JPA API(因为Spring ORM是基于JPA设计的)、以及Spring的数据访问/集成库。 2. **配置Hibernate**:创建一个名为`hibernate.cfg.xml`的配置文件,定义数据源、实体扫描路径、数据库...

    spring mvc + jpa 集成实例(有带包)

    集成Spring MVC和JPA可以实现高效且灵活的数据访问。首先,需要在Spring的配置文件中声明JPA的DataSource、EntityManagerFactory和TransactionManager。接着,定义Repository接口,Spring Data JPA会自动实现这些...

    spring-ssj.rar_spring_spring+Struts2+jpa集成

    Spring、Struts2和JPA是Java开发中常用的三大框架,它们各自负责应用程序的不同层面:...这个压缩包中的代码和配置文件将为我们提供一个直观的学习素材,让我们能够亲手实践并理解Spring、Struts2和JPA集成的全过程。

Global site tag (gtag.js) - Google Analytics