19.Spring中ORM关系对象映射持久化数据

说到持久化或者ORM关系对象映射的框架,我们可能会首先想到Hibernate,随之又出现了IBatis,MyBatis等等ORM的框架。其中Spring也对多个持久化的框架提供了支持,Hibernate,IBATIS,MYBATIS,JPA,JDO等等。
Spring对ORM框架的支持提供了与这些框架的集成点以及一些附加的服务:
(1)支持集成Spring声明式服务
(2)透明的异常处理
(3)线程安全的,轻量级的模板类
(4)DAO支持类
(5)资源管理
1.Hibernate
使用Hibernate所需要的主要接口是org.hibernate.Session。该接口提供了基本的数据访问功能。通过该接口,应用程序的Repository能够满足所有的持久化需求。获取Hiberante Session对象的标准方式是借助Hibernate SessionFactory接口的实现类。SessionFactory主要负责Hibernate Session的打开,关闭和管理。该接口定义如下:


package org.hibernate;

import java.io.Serializable;
import java.sql.Connection;

import org.hibernate.jdbc.Work;
import org.hibernate.stat.SessionStatistics;

public interface Session extends Serializable {

    public EntityMode getEntityMode();

    public Session getSession(EntityMode entityMode);

    public void flush() throws HibernateException;

    public void setFlushMode(FlushMode flushMode);

    public FlushMode getFlushMode();

    public void setCacheMode(CacheMode cacheMode);

    public CacheMode getCacheMode();

    public SessionFactory getSessionFactory();

    public Connection connection() throws HibernateException;

    public Connection close() throws HibernateException;

    public void cancelQuery() throws HibernateException;

    public boolean isOpen();

    public boolean isConnected();

    public boolean isDirty() throws HibernateException;

    public Serializable getIdentifier(Object object) throws HibernateException;

    public boolean contains(Object object);

    public void evict(Object object) throws HibernateException;

    public Object load(Class theClass, Serializable id, LockMode lockMode) throws HibernateException;

    public Object load(String entityName, Serializable id, LockMode lockMode) throws HibernateException;

    public Object load(Class theClass, Serializable id) throws HibernateException;

    public Object load(String entityName, Serializable id) throws HibernateException;

    public void load(Object object, Serializable id) throws HibernateException;

    public void replicate(Object object, ReplicationMode replicationMode) throws HibernateException;

    public void replicate(String entityName, Object object, ReplicationMode replicationMode) throws HibernateException;

    public Serializable save(Object object) throws HibernateException;

    public Serializable save(String entityName, Object object) throws HibernateException;

    public void saveOrUpdate(Object object) throws HibernateException;

    public void saveOrUpdate(String entityName, Object object) throws HibernateException;

    public void update(Object object) throws HibernateException;

    public void update(String entityName, Object object) throws HibernateException;

    public Object merge(Object object) throws HibernateException;

    public Object merge(String entityName, Object object) throws HibernateException;

    public void persist(Object object) throws HibernateException;

    public void persist(String entityName, Object object) throws HibernateException;

    public void delete(Object object) throws HibernateException;

    public void delete(String entityName, Object object) throws HibernateException;

    public void lock(Object object, LockMode lockMode) throws HibernateException;

    public void lock(String entityName, Object object, LockMode lockMode) throws HibernateException;

    public void refresh(Object object) throws HibernateException;

    public void refresh(Object object, LockMode lockMode) throws HibernateException;

    public LockMode getCurrentLockMode(Object object) throws HibernateException;

    public Transaction beginTransaction() throws HibernateException;

    public Transaction getTransaction();

    public Criteria createCriteria(Class persistentClass);

    public Criteria createCriteria(Class persistentClass, String alias);

    public Criteria createCriteria(String entityName);

    public Criteria createCriteria(String entityName, String alias);

    public Query createQuery(String queryString) throws HibernateException;

    public SQLQuery createSQLQuery(String queryString) throws HibernateException;

    public Query createFilter(Object collection, String queryString) throws HibernateException;

    public Query getNamedQuery(String queryName) throws HibernateException;

    public void clear();

    public Object get(Class clazz, Serializable id) throws HibernateException;

    public Object get(Class clazz, Serializable id, LockMode lockMode) throws HibernateException;

    public Object get(String entityName, Serializable id) throws HibernateException;

    public Object get(String entityName, Serializable id, LockMode lockMode) throws HibernateException;

    public String getEntityName(Object object) throws HibernateException;

    public Filter enableFilter(String filterName);

    public Filter getEnabledFilter(String filterName);

    public void disableFilter(String filterName);
    
    public SessionStatistics getStatistics();

    public void setReadOnly(Object entity, boolean readOnly);

    public void doWork(Work work) throws HibernateException;

    Connection disconnect() throws HibernateException;

    void reconnect() throws HibernateException;
 
    void reconnect(Connection connection) throws HibernateException;
}

在Spring中,我们要通过Spring的某一个Hibernate Session工厂Bean来获取Hibernate SessionFactory。3.1开始,Spring提供了三个Session工厂bean供我们选择:

(1)org.springframework.orm.hibernate3.LocalSessionFactoryBean
(2)org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean
(3)org.springframework.orm.hibernate4.LocalSessionFactoryBean

上述三种Bean都是Spring FactoryBean的实现。它们会产生一个Hibernate SessionFactoryBean,能够装配进任何SessionFactory类型的属性中。
FactoryBean接口的定义:

package org.springframework.beans.factory;

public interface FactoryBean<T> {
    T getObject() throws Exception;//返回一个对象
    Class<?> getObjectType();//返回对象的类型
    boolean isSingleton();//是否为单例
}


类可以通过注解的方式表明要使用Hibernate进行持久化,这些类可以使用的注解包括JPA的@Entity或者@MappedSuperclass以及Hibernate的@Entity注解。
HibernateTemplate能够保证每个事务使用同一个Session,但是这种方式的缺点是我们的Repository的实现会直接与Spring耦合。
推荐使用上下文Session,通过上下文Session的方式,会直接将Hibernate SessionFactory装配到Repository中,并且用它来获取Session


@Repository注解
是Spring的另外一种构造注解,它能够像其他注解一样被Spring的组件扫描到。


2.JPA
(1)JPA也叫做Java Persostence API,Spring中使用JPA的第一步是要在Spring应用的上下文中将实体管理器工厂按照bean的形式来进行配置。
(2)基于JPA的应用程序需要使用EntityManagerFactory的实现类来获取EntityManager实例,其中JPA定义了两种类型的实体管理器:
A.应用程序管理类型:
当应用程序向实体管理器工厂直接请求实体管理器时,工厂会创建一个实体管理器。在这种模式下,程序要负责打开或关闭实体管理器并在事务中对其进行控制。这种方式的实体管理器适合于不运行在JavaEE容器中的独立应用程序。
B.容器管理类型:
实体管理器由JavaEE创建和管理。应用程序根本不会与实体管理器工厂打交道。相反,实体管理器直接通过注入或者JNDI来获取。容器负责配置实体管理器工厂。这种类型的实体管理器最适用于JavaEE容器,在这种情况下会希望再persistence.xml指定的JPA配置之外保持一些自己对JPA的控制。
上述两种的区别在于EntityManager的创建和管理方式。应用程序管理类型的EntityManager是由EntityManagerFactory创建的,容器管理类型是通过PersistenceProvider的createEntityManagerFactory方法得到的。
(3)Spring提供了两种工厂Bean来创建上述的两种实体管理类型:

LocalEntityManagerFactoryBean//生成应用程序管理类型的EntityManagerFactory
LocalContainerEntityFactoryBean//生成容器管理类型的EntityManagerFactory

(4)persistence.xml文件
a、必须位于类路劲META-INF目录下。
b、用于定义一个或者多个持久化单元,持久化单元是同一个数据源下的一个或者多个持久化类,识别持久化单元中的实体类。
(5)jpaVendorAdapter属性
a.用来指明所使用的是哪一个厂商的JPA实现
b.Spring提供了多个JPA厂商的适配器:

EclipseLinkJpaVendorAdapter
HibernateJpaVendorAdapter
OpenJpaVendorAdapter
Hibernate的JPA适配器支持多种数据库.jpg

(5)从JNDI获取实体管理器工厂

<jee:jndi-lookup id="id" jndi-name="persistence/aaa"/>

Java形式:

JndiObjectFactoryBean jndi = new JndiObjectFactoryBean();
jndi.setJndiName("jdbc/aaa");
return jndi;

它的返回结果是一个EntityFactory bean。
(6)@PersistenceContext注解
该注解并不会真正注入EntityManager.它没有将真正的EntityManager设置给Repository,而是给了它一个EntityManager的代理。真正的EntityManager是与事务相关联的那个,如果不存在这样的EntityManager,就会创建一个新的。此时,就能始终以线程安全的方式使用实体管理器。
(7)@Transactional
该注解表示这个Repository中的持久化方法是在事务上下文中执行的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,427评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,551评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,747评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,939评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,955评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,737评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,448评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,352评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,834评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,992评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,133评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,815评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,477评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,022评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,147评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,398评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,077评论 2 355

推荐阅读更多精彩内容