這篇文章主要介紹Spring數據庫訪問之ORM的示例分析,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
Spring數據庫訪問中另外一大模塊就是ORM,ORM即對象/關系映射。Spring支持大多數ORM框架,比如Hibernate,JPA,JDO,TopLink和iBatis(Spring2支持iBatis2,現MyBatis3的Spring支持由MyBatis社區開發,并非Spring)。
首先我們從單獨使用ORM框架開始,來介紹Spring對ORM的支持,以Hibernate為例。使用ORM框架,需要提供持久化類,以課程管理為背景,如下設計課程類:
Java代碼
public class Course { private Long id; private String title; private java.util.Date startDate; private java.util.Date endDate; private int fee; //必須提供無參默認構造方法 public Course() { super(); } //省略其它構造方法,getter和setter等方法
作為對數據訪問的一種模式,我們仍然應用DAO模式,寫DAO類已經很熟練了,如下設計即可:
package org.ourpioneer.course.dao; import java.util.List; import org.ourpioneer.course.bean.Course; public interface CourseDAO { public void save(Course course); public void delete(Course course); public void update(Course course); public Course findById(Long courseId); public List findAll(); }
非常簡單的設計,包含CRUD操作,那么實現類中我們用Hibernate幫助我們進行數據庫訪問操作也非常簡單:
package org.ourpioneer.course.dao; import java.util.List; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.ourpioneer.course.bean.Course; public class CourseDAOImpl implements CourseDAO { private SessionFactory sessionFactory; public CourseDAOImpl() { Configuration cfg = new Configuration().configure(); sessionFactory = cfg.buildSessionFactory(); } public List findAll() { Session session = sessionFactory.openSession(); try { Query query = session.createQuery("from Course"); return query.list(); } finally { session.close(); } } public Course findById(Long courseId) { Session session = sessionFactory.openSession(); try { return (Course) session.get(Course.class, courseId); } finally { session.close(); } } public void save(Course course) { Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); try { tx.begin(); session.saveOrUpdate(course); tx.commit(); } catch (RuntimeException e) { tx.rollback(); throw e; } finally { session.close(); } } }
這里只展示幾個方法作為代表,其它方法類似可以寫出,非常簡單。首先是構造方法,初始化實現類時創建Hibernate的配置對象,new Configuration().configure()時,Hibernate會在類路徑的根路徑下自動尋找名為hibernate.cfg.xml的配置文件并加載,之后就是創建Hibernate的Session對象,利用Session對象提供和衍生出的方法來進行數據庫操作。下面來看配置文件,這是比較重要的,因為通過配置文件,把數據庫信息和實體Bean的信息都告訴Hibernate,可以省去我們很多在數據庫設計上的事情。
<?xml version='1.0' encoding='UTF-8'?> "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="connection.driver_class">com.mysql.jdbc.Driverproperty> <property name="connection.url">jdbc:mysql:///testproperty> <property name="connection.username">rootproperty> <property name="connection.password">123property> <property name="dialect">org.hibernate.dialect.MySQLDialectproperty> <property name="show_sql">trueproperty> <property name="hbm2ddl.auto">updateproperty> <mapping resource="org/ourpioneer/course/hbm/course.hbm.xml" /> session-factory> hibernate-configuration>
這里我們告訴Hibernate使用mysql數據庫,并配置數據庫信息,所用方言,并在執行應用程序時在控制臺打印出還原的SQL語句。使用hbm2ddl.auto可以讓Hibernate根據實體Bean的配置信息來自動建表,這是很方便的,最后的mapping就是配置實體bean映射信息的文件,我們來看一下:
<?xml version="1.0" encoding="UTF-8"?> "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="org.ourpioneer.course.bean"> <class name="Course" table="course"> <id name="id" type="java.lang.Long" column="ID"> <generator class="identity" /> id> <property name="title" type="java.lang.String" column="TITLE" length="100" not-null="true" /> <property name="startDate" type="java.sql.Date" column="STARTDATE" not-null="true" /> <property name="endDate" type="java.sql.Date" column="ENDDATE" not-null="true" /> <property name="fee" type="java.lang.Integer" column="FEE" not-null="true" /> class> hibernate-mapping>
這里首先配置了實體bean的所在位置,類信息還有數據庫中表對應的關系。之后創建主鍵信息id,使用了MySQL的自增主鍵特性,剩下就是對各個字段的描述了,都見名知意,易于理解。
準備好這些內容,就可以編寫測試程序了,在項目中引入Hibernate的相關依賴。這里說明一下,Maven默認倉庫是Apache的,其中的Hibernate版本還在3.3.2.GA(本文編寫時),而當前的Hibernate官方版本已經是3.6.0.Final了,我們想使用新版本,該怎么辦?很簡單,配置Maven倉庫的位置,讓其可以發現3.6.0.Final版的Hibernate并下載依賴。JBoss官方也提供一個Maven倉庫,其中就有最新版的Hibernate,那么我們在項目的POM中配置一下這個地址:
<repositories> <repository> <releases> <updatePolicy>alwaysupdatePolicy> releases> <snapshots> <updatePolicy>alwaysupdatePolicy> snapshots> <id>Jbossid> <name>Jboss Repositoryname> <url>https://repository.jboss.org/nexus/content/groups/publicurl> repository> repositories>
之后,為項目引入其它必要的依賴,使用Maven管理,我們不需自己再去尋找各種依賴了,非常簡單的管理,如圖所示:
下面來看示例程序:
package org.ourpioneer.course; import java.util.GregorianCalendar; import java.util.List; import org.ourpioneer.course.bean.Course; import org.ourpioneer.course.dao.CourseDAO; import org.ourpioneer.course.dao.CourseDAOImpl; public class Demo { public static void main(String[] args) { CourseDAO courseDAO = new CourseDAOImpl(); Course course = new Course(); course.setTitle("Spring ORM"); course.setStartDate(new GregorianCalendar(2011, 1, 1).getTime()); course.setEndDate(new GregorianCalendar(2011, 2, 1).getTime()); course.setFee(100); courseDAO.save(course); List courses = courseDAO.findAll(); Long courseId = courses.get(0).getId(); course = courseDAO.findById(courseId); System.out.println(course); courseDAO.delete(course); } }
首先創建的是Course對象,并設置其中的屬性,使用save方法將其持久化到數據庫中,之后通過findAll方法查詢數據庫中的全部記錄,當然現在只有一條。并拿到Id,在通過findById方法獲取出來,然后打印結果。最終刪除記錄。執行該程序,我們可以得到如下輸出信息:
我們之前并沒有在數據庫中建表,而Hibernate在執行插入之前會為我們自動建表,然后執行插入操作,兩次查詢操作,并打印出對象信息,最后執行了刪除操作,從SQL語句中可以看到Hibernate最終的執行結果是什么。而此時回到數據庫中,會發現一個建好的表。
Hibernate的簡單ORM映射操作就介紹完了,下面來看使用JPA注解和Hibernate的API來持久化對象,首先修改持久化類:
package org.ourpioneer.course.bean; import java.sql.Date; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; /** * 課程信息描述bean * * @author Nanlei * */ @Entity @Table(name = "course") public class Course { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "ID") private Long id; @Column(name = "TITLE", length = 100, nullable = false) private String title; @Column(name = "STARTDATE",nullable=false) private java.util.Date startDate; @Column(name = "ENDDATE",nullable=false) private java.util.Date endDate; @Column(name = "FEE",nullable=false) private int fee; // 其余內容不變,省略 }
使用JPA的注解,首先對類進行注解,使用@Entity,并關聯數據庫表,使用@Table。下面就是對字段進行主鍵了,標識符(主鍵)字段要使用@Id,還要指定生成策略和對應的列名,剩下的字段只需指定列信息即可?,F在告訴Hibernate我們使用JPA注解,而不使用映射文件了,如下配置:
<mapping class="org.ourpioneer.course.bean.Course"/>
修改DAO實現類的構造方法,使用注解配置方式創建SessionFactory,如下即可:
public CourseDAOImpl() { // Configuration cfg = new Configuration().configure(); Configuration cfg = new AnnotationConfiguration().configure(); sessionFactory = cfg.buildSessionFactory(); }
此時再次執行測試方法,反饋的信息沒有任何變化,但是我們就使用了JPA注解而并非Hibernate的映射信息了。下面來看看使用Hibernate作為JPA引擎的持久化步驟。先配置依賴,引入:
<dependency> <groupId>org.hibernategroupId> <artifactId>hibernate-entitymanagerartifactId> <version>3.6.0.Finalversion> <type>jartype> <scope>compilescope> dependency> <dependency> <groupId>jbossgroupId> <artifactId>jboss-archive-browsingartifactId> <version>5.0.0alpha-200607201-119version> <type>jartype> <scope>compilescope> dependency>
如果在Java EE容器中運行JPA,可以通過容器來配置JPA,如果是在Java SE中運行JPA,那么需要在類路徑的META-INF下配置persistence.xml來配置持久化單元,在本例中我們使用Hibernate作為JPA的引擎,就可以這么來寫:
<?xml version='1.0' encoding='UTF-8'?> <PERSISTENCE XMLNS=< span>"http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> <PERSISTENCE-UNIT NAME=< span>"course"> <PROPERTY NAME=< span>"hibernate.ejb.cfgfile" value="/hibernate.cfg.xml" />
加載配置文件仍然使用Hibernate的配置文件,或者也可以將其中的property寫在persistence.xml中,那么因為在這里JPA已經可以獲取持久化單元了,在Hibernate的配置中就需要配置持久化對象的映射了,去掉mapping信息即可。有了配置信息,還需要實現類,我們重寫一個JPA的DAO實現,如下:
Java代碼
package org.ourpioneer.course.dao; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; import javax.persistence.Query; import org.ourpioneer.course.bean.Course; public class CourseDAOImplJPA implements CourseDAO { private EntityManagerFactory entityManagerFactory; public CourseDAOImplJPA() { entityManagerFactory = Persistence.createEntityManagerFactory("course"); } public void delete(Course course) { EntityManager manager = entityManagerFactory.createEntityManager(); EntityTransaction tx = manager.getTransaction(); try { tx.begin(); manager.remove(manager.merge(course)); tx.commit(); } catch (RuntimeException e) { tx.rollback(); throw e; } finally { manager.close(); } } public List findAll() { EntityManager manager = entityManagerFactory.createEntityManager(); try { Query query = manager .createQuery("select course from Course course"); return query.getResultList(); } finally { manager.close(); } } public Course findById(Long courseId) { EntityManager manager = entityManagerFactory.createEntityManager(); try { return manager.find(Course.class, courseId); } finally { manager.close(); } } public void save(Course course) { EntityManager manager = entityManagerFactory.createEntityManager(); EntityTransaction tx = manager.getTransaction(); try { tx.begin(); manager.persist(course); tx.commit(); } catch (RuntimeException e) { tx.rollback(); throw e; } finally { manager.close(); } } public void update(Course course) { EntityManager manager = entityManagerFactory.createEntityManager(); EntityTransaction tx = manager.getTransaction(); try { tx.begin(); manager.merge(course); tx.commit(); } catch (RuntimeException e) { tx.rollback(); throw e; } finally { manager.close(); } } }
這里特別要注意的是delete方法,首先調用merge方法,否則當前對象是出于脫管態的,無法和Session進行關聯,也就無法刪除該對象。不加merge方法時候會拋出異常,大家可以測試一下,因為底層還是Hibernate進行的,Hibernate的持久化對象有三種狀態,那么就要注意狀態發生的變化。
現在我們來看如何在Spring中配置ORM資源工廠,也就是在Spring中使用ORM框架。仍然以Hibernate為例來說明,要引入spring-orm和spring-context模塊來做測試。首先我們可以修改一下DAO實現類的寫法,因為用了Spring,就不用顯式來new對象了,那么對于Hibernate的SessionFactory,使用注入的方式來進行配置,修改CourseDAOImpl類,如下設置:
private SessionFactory sessionFactory; public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; }
去掉構造方法,為sessionFactory提供get方法即可。之后就是配置Spring了,很簡單,要配置courseDao和sessionFactory:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml" /> bean> <bean id="courseDao" class="org.ourpioneer.course.dao.CourseDAOImpl"> <property name="sessionFactory" ref="sessionFactory">property> bean>
把Hibernate配置對象的映射文件加上,之后修改測試方法,從Spring的容器中獲取對象就可以了:
ApplicationContext ctx = new ClassPathXmlApplicationContext( "classpath:applicationContext.xml"); CourseDAO courseDAO = (CourseDAO) ctx.getBean("courseDao");
此時,我們還依賴Hibernate的配置文件,那么完全可以把Hibernate中的配置信息移入Spring之中,因為Spring的ORM模塊完全支持Hibernate,可以如下進行,我們使用C3P0作為連接池:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" scope="singleton" destroy-method="close"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql:///test" /> <property name="user" value="root" /> <property name="password" value="123" /> bean>
將數據庫的基本信息配置好后,數據源的配置就完成了。下面是配置Hibernate:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="mappingLocations" value="classpath:org/ourpioneer/course/hbm/*.hbm.xml" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialectprop> <prop key="hibernate.show_sql">trueprop> <prop key="hibernate.hbm2ddl.auto">updateprop> props> property> bean>
這里我們將實體映射一起配置進來,使用了*通配符,并配置了基本的Hibernate屬性,比如方言,顯示sql語句和自動建表。剩下的就是DAO的配置了,它不用做什么修改,仍然注入sessionFactory即可,然后執行測試:
從中可以看到啟動信息和Hibernate生成的SQL語句。除了使用Hibernate的實體映射文件外,我們還可以使用注解,之前已經在Course持久化類中添加了注解,那么我們就來配置使用注解的方式,很簡單,只需修改Spring中的Hibernate SessionFactory配置即可,如下:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="annotatedClasses"> <list> <value>org.ourpioneer.course.bean.Coursevalue> list> property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialectprop> <prop key="hibernate.show_sql">trueprop> <prop key="hibernate.hbm2ddl.auto">updateprop> props> property> bean>
這樣就使用在持久化類中的注解信息而不需要單獨編寫HBM映射文件了,執行測試,結果是一樣的。當然,在Spring中,還可以使用JPA的EntityManager來進行數據的持久化操作,那么又如何來進行呢?和前面介紹的類似,首先在JPA的DAO實現類中修改EntityManager的配置方式,使用注入來進行:
private EntityManagerFactory entityManagerFactory; public void setEntityManagerFactory( EntityManagerFactory entityManagerFactory) { this.entityManagerFactory = entityManagerFactory; }
同理,修改Spring的配置文件,配置EntityManagerFactory,如下:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="course" /> bean>
因為配置了persistenceUnitName,那么不要忘記了在META-INF目錄下的persistence.xml文件,其中是這么寫的:
<persistence-unit name="course"> <properties> <property name="hibernate.ejb.cfgfile" value="/hibernate.cfg.xml" /> properties> persistence-unit>
因為還用到了hibernate.cfg.xml,不過要將mapping的映射信息全部去掉,之后的courseDaoJPA配置就很簡單了:
<bean id="courseDaoJPA" class="org.ourpioneer.course.dao.CourseDAOImplJPA"> <property name="entityManagerFactory" ref="entityManagerFactory" /> bean>
在測試程序的ctx.getBean方法中換成courseDaoJPA就可以獲得JPA的DAO實現對象了,從而進行數據庫操作,這也非常簡單。如果不使用hibernate的配置文件,那么需要對JPA進行如下的配置:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="course" /> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" /> <property name="showSql" value="true" /> <property name="generateDdl" value="true" /> bean> property> bean>
將數據源注入進來,并配置一些數據庫方言,顯示sql和生成ddl的信息,最后精簡一下persistence.xml文件中的內容:
<persistence-unit name="course" />
已經不需要再使用Hibernate的配置文件了,這樣就可以了,再次執行測試程序,就可以得到如下輸出信息:
在JDBC模塊中,Spring的JDBC模板簡化了SQL的操作,使得使用SQL非常簡便,不需要很多的代碼就能完成數據庫操作,同樣,在ORM模塊中,Spring的模板技術也有應用,這里我們主要來看Hibernate模板和JPA模板技術。使用HibernateTemplate非常簡單,在DAO的實現類中進行注入即可,使用Hibernate模板為我們提供的方法來執行ORM操作,非常的簡便:
package org.ourpioneer.course.dao; import java.util.List; import org.ourpioneer.course.bean.Course; import org.springframework.orm.hibernate3.HibernateTemplate; import org.springframework.transaction.annotation.Transactional; public class CourseDAOImplHibernate implements CourseDAO { private HibernateTemplate hibernateTemplate; public void setHibernateTemplate(HibernateTemplate hibernateTemplate) { this.hibernateTemplate = hibernateTemplate; } @Transactional public void delete(Course course) { hibernateTemplate.delete(course); } @Transactional(readOnly = true) public List findAll() { return hibernateTemplate.find("from Course"); } @Transactional(readOnly = true) public Course findById(Long courseId) { return (Course) hibernateTemplate.get(Course.class, courseId); } @Transactional public void save(Course course) { hibernateTemplate.save(course); } @Transactional public void update(Course course) { hibernateTemplate.update(course); } }
其中使用了注解進行事務說明,就不用寫在配置文件中了,編寫好代碼,要讓Spring容器知道我們的做法,進行如下配置:
<tx:annotation-driven /> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> bean> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory" ref="sessionFactory" /> bean> <bean id="courseDaoHibernate" class="org.ourpioneer.course.dao.CourseDAOImplHibernate"> <property name="hibernateTemplate" ref="hibernateTemplate" /> bean>
使用tx前綴,只需加上相應的命名空間說明即可,這也很簡單。修改主程序:
package org.ourpioneer.course; import java.util.GregorianCalendar; import java.util.List; import org.ourpioneer.course.bean.Course; import org.ourpioneer.course.dao.CourseDAO; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Demo { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext( "classpath:applicationContext.xml"); CourseDAO courseDAO = (CourseDAO) ctx.getBean("courseDaoHibernate"); Course course = new Course(); course.setTitle("Spring ORM"); course.setStartDate(new GregorianCalendar(2011, 1, 1).getTime()); course.setEndDate(new GregorianCalendar(2011, 2, 1).getTime()); course.setFee(100); courseDAO.save(course); List courses = courseDAO.findAll(); Long courseId = courses.get(0).getId(); course = courseDAO.findById(courseId); System.out.println(course); courseDAO.delete(course); } }
運行主程序,就可以看到執行效果了:
相對于HibernateTemplate,JpaTemplate也可以實現相同功能,我們來看如下代碼:
package org.ourpioneer.course.dao; import java.util.List; import org.ourpioneer.course.bean.Course; import org.springframework.orm.jpa.JpaTemplate; import org.springframework.transaction.annotation.Transactional; public class CourseDAOImplJPA implements CourseDAO { private JpaTemplate jpaTemplate; public void setJpaTemplate(JpaTemplate jpaTemplate) { this.jpaTemplate = jpaTemplate; } @Transactional public void delete(Course course) { jpaTemplate.remove(jpaTemplate.merge(course)); } @Transactional(readOnly = true) public List findAll() { return jpaTemplate.find("from Course"); } @Transactional(readOnly = true) public Course findById(Long courseId) { return jpaTemplate.find(Course.class, courseId); } @Transactional public void save(Course course) { jpaTemplate.merge(course); } @Transactional public void update(Course course) { jpaTemplate.merge(course); } }
這里不能忘了delete方法需要首先將脫管態的對象變為持久態的才能進行操作,否則就會發生異常。同樣,對于配置文件,也要做響應的調整:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> bean> <bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate"> <property name="entityManagerFactory" ref="entityManagerFactory" /> bean> <bean id="courseDaoJPA" class="org.ourpioneer.course.dao.CourseDAOImplJPA"> <property name="jpaTemplate" ref="jpaTemplate" /> bean>
這樣,我們修改測試程序中getBean獲得的對象,就可以測試程序了,這都非常簡單了。這里我們擴展說一點,使用了HibernateTemplate或jpaTemplate后,如果想獲取Session或EntityManager,那么可以這么操作:hibernateTemplate.getSessionFactory().getCurrentSession(),對于JPA則是:jpaTemplate.getEntityManager(),除此之外,我們還可以使用他們的execute()方法來執行操作:
hibernateTemplate.execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException,SQLException { } };
JPA的則是:
jpaTemplate.execute(new JpaCallback() { public Object doInJpa(EntityManager em) throws PersistenceException { return null; } });
以上我們是在DAO實現類中直接注入模板來進行操作的,當然我們還可以讓實現類繼承各自的DaoSupport類來獲得模板進行操作,這很簡單,我們來看:
package org.ourpioneer.course.dao; import java.util.List; import org.ourpioneer.course.bean.Course; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.springframework.transaction.annotation.Transactional; public class CourseDAOImplHibernate extends HibernateDaoSupport implements CourseDAO { @Transactional public void delete(Course course) { getHibernateTemplate().delete(course); } @Transactional(readOnly = true) public List findAll() { return getHibernateTemplate().find("from Course"); } @Transactional(readOnly = true) public Course findById(Long courseId) { return (Course) getHibernateTemplate().get(Course.class, courseId); } @Transactional public void save(Course course) { getHibernateTemplate().save(course); } @Transactional public void update(Course course) { getHibernateTemplate().update(course); } }
同時修改配置文件:
<bean id="courseDaoHibernate" class="org.ourpioneer.course.dao.CourseDAOImplHibernate"> <property name="sessionFactory" ref="sessionFactory" /> bean>
當然,也可以給該類注入HibernateTemplate,看一下該類的源碼即可參照使用對應的實例進行注入了,這都很簡單,JPA的修改也是相似的:
package org.ourpioneer.course.dao; import java.util.List; import org.ourpioneer.course.bean.Course; import org.springframework.orm.jpa.support.JpaDaoSupport; import org.springframework.transaction.annotation.Transactional; public class CourseDAOImplJPA extends JpaDaoSupport implements CourseDAO { @Transactional public void delete(Course course) { getJpaTemplate().remove(getJpaTemplate().merge(course)); } @Transactional(readOnly = true) public List findAll() { return getJpaTemplate().find("from Course"); } @Transactional(readOnly = true) public Course findById(Long courseId) { return getJpaTemplate().find(Course.class, courseId); } @Transactional public void save(Course course) { getJpaTemplate().merge(course); } @Transactional public void update(Course course) { getJpaTemplate().merge(course); } }
同時,將配置文件修改為:
<bean id="courseDaoJPA" class="org.ourpioneer.course.dao.CourseDAOImplJPA"> <property name="entityManagerFactory" ref="entityManagerFactory" /> bean>
之前我們使用的是HibernateTemplate來進行對象的持久化的,其實在DAO實現類中我們還可以使用Hibernate的上下文Session來持久化對象。也就是通過SessionFactory對象的getCurrentSession()對象來獲得Session,然后通過Session來進行操作。
我們調整一下代碼:
package org.ourpioneer.course.dao; import java.util.List; import org.hibernate.Query; import org.hibernate.SessionFactory; import org.ourpioneer.course.bean.Course; import org.springframework.transaction.annotation.Transactional; public class CourseDAOImplHibernate implements CourseDAO { private SessionFactory sessionFactory; public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } @Transactional public void delete(Course course) { sessionFactory.getCurrentSession().delete(course); } @Transactional(readOnly = true) public List findAll() { Query query = sessionFactory.getCurrentSession().createQuery( "from Course"); return query.list(); } @Transactional(readOnly = true) public Course findById(Long courseId) { return (Course) sessionFactory.getCurrentSession().get(Course.class, courseId); } @Transactional public void save(Course course) { sessionFactory.getCurrentSession().saveOrUpdate(course); } @Transactional public void update(Course course) { sessionFactory.getCurrentSession().update(course); } }
這里要注意的是所有DAO的方法必須是支持事務的,這可以通過添加Transactional注解來完成,就很簡單了,之前也有過介紹。這樣就能保證DAO中所有方法都可以在同一個Session,同一個事務內來執行,達到使用事務的效果。
將代碼修改完成后,就要來修改配置文件了:
<tx:annotation-driven /> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> bean> <bean id="courseDaoHibernate" class="org.ourpioneer.course.dao.CourseDAOImplHibernate"> <property name="sessionFactory" ref="sessionFactory" /> bean>
這樣,基于上下文Session的持久化對象就配置完畢了,在示例程序中來執行,就會看到效果。修改測試程序如下:
package org.ourpioneer.course; import java.util.GregorianCalendar; import java.util.List; import org.ourpioneer.course.bean.Course; import org.ourpioneer.course.dao.CourseDAO; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Demo { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext( "classpath:applicationContext.xml"); CourseDAO courseDAO = (CourseDAO) ctx.getBean("courseDaoHibernate"); Course course = new Course(); course.setTitle("Spring ORM"); course.setStartDate(new GregorianCalendar(2011, 2, 1).getTime()); course.setEndDate(new GregorianCalendar(2011, 3, 1).getTime()); course.setFee(100); courseDAO.save(course); List courses = courseDAO.findAll(); Long courseId = courses.get(0).getId(); course = courseDAO.findById(courseId); System.out.println(course); course.setFee(200); courseDAO.update(course); System.out.println(course); courseDAO.delete(course); } }
在控制臺,我們可以看到如下輸出:
這種方式和使用HibernateTemplate有的不同是它們對異常的處理。HibernateTemplate會將異常統一翻譯成Spring的數據訪問異常體系中的某個異常,而我們使用上下文的Session時,拋出的就不是Spring的異常,而是HibernateException,如果我們還想看到Spring的異常體系,就需要做點設置,當然這也很簡單。
在DAO實現類上加@Respository注解,并且注冊一個PersistenceExceptionTranslationPostProcessor實例即可。在Spring的配置文件中,我們加入如下內容:
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor">bean>
這是使用Hibernate的情況,那么使用JPA的情況和這個類似,我們來修改JPA的DAO實現類:
package org.ourpioneer.course.dao; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import org.ourpioneer.course.bean.Course; import org.springframework.transaction.annotation.Transactional; public class CourseDAOImplJPA implements CourseDAO { @PersistenceContext private EntityManager entityManager; @Transactional public void delete(Course course) { entityManager.remove(entityManager.merge(course)); } @Transactional(readOnly = true) public List findAll() { Query query = entityManager.createQuery("from Course"); return query.getResultList(); } @Transactional(readOnly = true) public Course findById(Long courseId) { return entityManager.find(Course.class, courseId); } @Transactional public void save(Course course) { entityManager.merge(course); } @Transactional public void update(Course course) { entityManager.merge(course); } }
這里我們使用注解來聲明了EntityManager,那么需要在配置文件中在聲明一個PersistenceAnnotationBeanPostProcessor實例就好了。配置文件修改為:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> bean> <bean id="courseDaoJPA" class="org.ourpioneer.course.dao.CourseDAOImplJPA" /> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">bean>
之后,將測試程序中的getBean()換成courseDaoJPA即可。
和HibernateTemplate一樣,JpaTemplate也會將異常翻譯為Spring的數據訪問異常,而如果改成entityManagerFactory之后,異常就會變成Java SE的異常,比如非法參數,非法狀態等異常。若要繼續使用Spring的異常體系,那么要為JPA的DAO實現類加上@Repository注解,然后注冊PersistenceExceptionTranslationPostProcessor實例。
以上是“Spring數據庫訪問之ORM的示例分析”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。