文档章节

spring学习:与JPA的实现集成

architect刘源源
 architect刘源源
发布于 2018/01/15 13:09
字数 1490
阅读 6
收藏 1

结构改造

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

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

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

    Dao:

    

Java代码  收藏代码

  1. package com.yunzero.dao;  
  2.   
  3. import java.io.Serializable;  
  4. import java.util.List;  
  5.   
  6. public interface Dao<T extends Object> {  
  7.       
  8.     void create(T t);  
  9.       
  10.     T get(Serializable id);  
  11.       
  12.     T load(Serializable id);  
  13.       
  14.     List<T> getAll();  
  15.       
  16.     void update(T t);  
  17.       
  18.     void delete(T t);  
  19.       
  20.     void deleteById(Serializable id);  
  21.       
  22.     void deleteAll();  
  23.       
  24.     long count();  
  25.       
  26.     boolean exists(Serializable id);  
  27. }  

     这里通用的地方就在于它是采用泛型的类型。还要一个值得注意的地方就是里面get, load, delete,exists等方法的参数是使用Serializable类型。这是因为我们在定义数据库表的键值时通常选用int, long等类型。而在java里,Integer, Long类型都是实现Serializable接口的,可以更通用一些。

 

    AbstractHbnDao的实现如下:

 

Java代码  收藏代码

  1. public abstract class AbstractHbnDao<T extends Object> implements Dao<T> {  
  2.     @PersistenceContext  
  3.     private EntityManager entityManager;  
  4.     private Class<T> domainClass;  
  5.       
  6.     protected Session getSession() {  
  7.         return entityManager;  
  8.     }  
  9.       
  10.     @SuppressWarnings("unchecked")  
  11.     private Class<T> getDomainClass() {  
  12.         if (domainClass == null) {  
  13.             ParameterizedType thisType = (ParameterizedType) getClass().getGenericSuperclass();  
  14.             this.domainClass = (Class<T>) thisType.getActualTypeArguments()[0];  
  15.         }  
  16.         return domainClass;  
  17.     }  
  18.       
  19.     private String getDomainClassName() { return getDomainClass().getName(); }  
  20.       
  21.     @Override  
  22.     public void create(T t) {  
  23.           
  24.         // If there's a setDateCreated() method, then set the date.  
  25.         Method method = ReflectionUtils.findMethod(  
  26.                 getDomainClass(), "setDateCreated", new Class[] { Date.class });  
  27.         if (method != null) {  
  28.             try {  
  29.                 method.invoke(t, new Date());  
  30.             } catch (Exception e) {  
  31.                 // Ignore any exception here; simply abort the setDate() attempt  
  32.             }  
  33.         }  
  34.           
  35.         getSession().save(t);  
  36.     }  
  37.       
  38.     @Override  
  39.     @SuppressWarnings("unchecked")  
  40.     public T get(Serializable id) {  
  41.         return (T) getSession().get(getDomainClass(), id);  
  42.     }  
  43.       
  44.     @Override  
  45.     @SuppressWarnings("unchecked")  
  46.     public T load(Serializable id) {  
  47.         return (T) getSession().load(getDomainClass(), id);  
  48.     }  
  49.       
  50.     @SuppressWarnings("unchecked")  
  51.     public List<T> getAll() {  
  52.         return getSession()  
  53.             .createQuery("from " + getDomainClassName())  
  54.             .list();  
  55.     }  
  56.       
  57.     @Override  
  58.     public void update(T t) { getSession().update(t); }  
  59.       
  60.     @Override  
  61.     public void delete(T t) { getSession().delete(t); }  
  62.       
  63.     @Override  
  64.     public void deleteById(Serializable id) { delete(load(id)); }  
  65.       
  66.     @Override  
  67.     public void deleteAll() {  
  68.         getSession()  
  69.             .createQuery("delete " + getDomainClassName())  
  70.             .executeUpdate();  
  71.     }  
  72.       
  73.     @Override  
  74.     public long count() {  
  75.         return (Long) getSession()  
  76.             .createQuery("select count(*) from " + getDomainClassName())  
  77.             .uniqueResult();  
  78.     }  
  79.       
  80.     @Override  
  81.     public boolean exists(Serializable id) { return (get(id) != null); }  
  82. }  

    有了这个基础,HbnContactDao的实现就很简单了:

Java代码  收藏代码

  1. package com.yunzero.dao.hibernate;  
  2.   
  3. import static org.springframework.util.Assert.notNull;  
  4.   
  5. import java.util.List;  
  6.   
  7. import org.springframework.stereotype.Repository;  
  8.   
  9. import com.yunzero.dao.ContactDao;  
  10. import com.yunzero.model.Contact;  
  11.   
  12. @Repository  
  13. public class HbnContactDao extends AbstractHbnDao<Contact> implements ContactDao {  
  14.   
  15.     @Override  
  16.     @SuppressWarnings("unchecked")  
  17.     public List<Contact> findByEmail(String email) {  
  18.         notNull(email, "email can't be null");  
  19.         return getSession()  
  20.             .getNamedQuery("findContactsByEmail")  
  21.             .setString("email", "%" + email + "%")  
  22.             .list();  
  23.     }  
  24. }  

 

jpa

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

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

 

配置

     具体的配置文件如下:

Xml代码  收藏代码

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:c="http://www.springframework.org/schema/c"  
  4.     xmlns:p="http://www.springframework.org/schema/p"  
  5.     xmlns:aop="http://www.springframework.org/schema/aop"  
  6.     xmlns:context="http://www.springframework.org/schema/context"  
  7.     xmlns:tx="http://www.springframework.org/schema/tx"  
  8.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  9.     xsi:schemaLocation="http://www.springframework.org/schema/beans   
  10.         http://www.springframework.org/schema/beans/spring-beans.xsd  
  11.         http://www.springframework.org/schema/aop   
  12.         http://www.springframework.org/schema/aop/spring-aop-4.1.xsd  
  13.         http://www.springframework.org/schema/tx   
  14.         http://www.springframework.org/schema/tx/spring-tx-4.1.xsd  
  15.         http://www.springframework.org/schema/context  
  16.         http://www.springframework.org/schema/context/spring-context-4.1.xsd">  
  17.           
  18.     <context:property-placeholder location="classpath:/environment.properties" />  
  19.       
  20.     <bean id="dataSource"  
  21.         class="org.apache.commons.dbcp2.BasicDataSource"  
  22.         destroy-method="close"  
  23.         p:driverClassName="${dataSource.driverClassName}"  
  24.         p:url="${dataSource.url}"  
  25.         p:username="${dataSource.username}"  
  26.         p:password="${dataSource.password}" />  
  27.   
  28.     <bean id="entityManagerFactory"  
  29.         class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"  
  30.         p:dataSource-ref="dataSource"  
  31.         p:packagesToScan="com.yunzero.model">  
  32.           
  33.         <property name="persistenceProvider">  
  34.             <bean class="org.hibernate.jpa.HibernatePersistenceProvider" />  
  35.         </property>  
  36.         <property name="jpaProperties">  
  37.             <props>  
  38.                 <prop key="hibernate.hbm2ddl.auto">update</prop>  
  39.                 <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>  
  40.                 <prop key="hibernate.show_sql">false</prop>  
  41.             </props>  
  42.         </property>  
  43.     </bean>  
  44.       
  45.     <bean id="transactionManager"  
  46.         class="org.springframework.orm.jpa.JpaTransactionManager"  
  47.         p:entityManagerFactory-ref="entityManagerFactory" />  
  48.       
  49.     <tx:annotation-driven />  
  50.       
  51.     <!-- These automatically register the PersistenceAnnotationBeanPostProcessor, as indicated above. -->  
  52.     <context:component-scan base-package="com.yunzero.dao.jpa" />  
  53.     <context:component-scan base-package="com.yunzero.service.impl" />  
  54.   
  55. </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框架集成的时候,需要考虑数据访问层的抽象和结构。里面的巧妙之处值得仔细推敲。

© 著作权归作者所有

architect刘源源

architect刘源源

粉丝 167
博文 555
码字总数 935372
作品 0
浦东
程序员
私信 提问
Java新手如何学习Spring、Struts、Hibernate三大框架?

ava三大框架的各自作用 一、Spring Spring是一个解决了许多在J2EE开发中常见的问题的强大框架。 Spring提供了管理业务对象的一致方法并且鼓励了注入对接口编程而不是对类编程的良好习惯。Spr...

懿涌
2017/06/02
893
9
《pro Spring》学习笔记之Spring HTTP 远程方法调用

除了使用Spring集成RMI,AXIS来实现Webservice,Spring也提供了一套自身的类WebService 实现,这就是传说中《Spring HTTP Invoker》,下面我们来看如何使用 同样,本文分别服务端和客户端两个p...

光石头
2011/05/19
237
0
Spring管理filter和servlet

在使用spring容器的web应用中,业务对象间的依赖关系都可以用context.xml文件来配置,并且由spring容器来负责依赖对象 的创建。如果要在filter或者servlet中使用spring容器管理业务对象,通常...

加油_张
2013/04/25
404
1
开发基于xfire的webservice的两种方式

一. 通过MyEclipse工具,导入webservice库到web project或新建webservice工程。自动将普通的javabean(必须要以接口和实现类的方式出现)发布为webservice。在WebRoot下生成一个WebServices目...

soothwolf
2013/09/29
98
0
Spring Data JPA 1.9.0 发布

Spring Data JPA 1.9.0 发布,此版本更新内容如下: * DATAJPA-787 - Release 1.9 GA (Gosling). * DATAJPA-785 - Make sure the build works with Hibernate 5 GA. * DATAJPA-779 - Update ......

淡漠悠然
2015/09/04
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周一乱弹 —— 熟悉的味道,难道这就是恋爱的感觉

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @xiaoshiyue :好久没分享歌了分享张碧晨的单曲《今后我与自己流浪》 《今后我与自己流浪》- 张碧晨 手机党少年们想听歌,请使劲儿戳(这里)...

小小编辑
今天
555
14
SpringBoot中 集成 redisTemplate 对 Redis 的操作(二)

SpringBoot中 集成 redisTemplate 对 Redis 的操作(二) List 类型的操作 1、 向列表左侧添加数据 Long leftPush = redisTemplate.opsForList().leftPush("name", name); 2、 向列表右......

TcWong
今天
19
0
排序––快速排序(二)

根据排序––快速排序(一)的描述,现准备写一个快速排序的主体框架: 1、首先需要设置一个枢轴元素即setPivot(int i); 2、然后需要与枢轴元素进行比较即int comparePivot(int j); 3、最后...

FAT_mt
昨天
4
0
mysql概览

学习知识,首先要有一个总体的认识。以下为mysql概览 1-架构图 2-Detail csdn |简书 | 头条 | SegmentFault 思否 | 掘金 | 开源中国 |

程序员深夜写bug
昨天
12
0
golang微服务框架go-micro 入门笔记2.2 micro工具之微应用利器micro web

micro web micro 功能非常强大,本文将详细阐述micro web 命令行的功能 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go-micro环境, golang微服务框架...

非正式解决方案
昨天
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部