Sping集成JPA

来源:互联网 发布:专业电子相册制作软件 编辑:程序博客网 时间:2024/06/07 15:20
      JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
       JPA 的目标之一是制定一个可以由很多供应商实现的API,并且开发人员可以编码来实现该API,而不是使用私有供应商特有的API。因此开发人员只需使用供应商特有的API来获得JPA规范没有解决但应用程序中需要的功能。尽可能地使用JPA API,但是当需要供应商公开但是规范中没有提供的功能时,则使用供应商特有的API。
1 Hibernate
  JPA是需要Provider来实现其功能的,Hibernate就是JPA Provider中很强的一个,目前来说应该无人能出其右。从功能上来说,JPA现在就是Hibernate功能的一个子集。Hibernate 从3.2开始,就开始兼容JPA。Hibernate3.2获得了Sun TCK的JPA(Java Persistence API) 兼容认证。   只要熟悉Hibernate或者其他ORM框架,在使用JPA时会发现其实非常容易上手。例如实体对象的状态,在Hibernate有自由、持久、游离三种,JPA里有new,managed,detached,removed,明眼人一看就知道,这些状态都是一一对应的。再如flush方法,都是对应的,而其他的再如说Query query = manager.createQuery(sql),它在Hibernate里写法上是session,而在JPA中变成了manager,所以从Hibernate到JPA的代价应该是非常小的   同样,JDO,也开始兼容JPA。在ORM的领域中,看来JPA已经是王道,规范就是规范。在各大厂商的支持下,JPA的使用开始变得广泛。
2 Spring
  Spring + Hibernate 常常被称为 Java Web 应用人气最旺的框架组合。而在 JCP 通过的 Web Beans JSR ,却欲将JSF + EJB + JPA 、来自 JBoss Seam(Spring 除外)的一些组件和EJB 3(目前能够提供有基本拦截和依赖注入功能的简化 Session Bean 框架)的一个 Web 组合进行标准化。如今的 Spring 2.0 为 JPA 提供了完整的 EJB 容器契约,允许 JPA在任何环境内可以在 Spring 管理的服务层使用(包括 Spring 的所有 AOP 和 DI 增强)。同时,关于下一个Web应用组合会是 EJB、Spring + Hibernate 还是 Spring + JPA 的论战,早已充斥于耳。   在Spring 2.0.1中,正式提供对JPA的支持,这也促成了JPA的发展,要知道JPA的好处在于可以分离于容器运行,变得更加的简洁。
3 OpenJPA
  OpenJPA 是 Apache 组织提供的开源项目,它实现了 EJB 3.0 中的 JPA 标准,为开发者提供功能强大、使用简单的持久化数据管理框架。OpenJPA 封装了和关系型数据库交互的操作,让开发者把注意力集中在编写业务逻辑上。OpenJPA 可以作为独立的持久层框架发挥作用,也可以轻松的与其它 Java EE 应用框架或者符合 EJB 3.0 标准的容器集成。
4 其它
  目前支持的实现包括Toplink、Hibernate Entitymanager等。TopLink以前需要收费,如今开源了。OpenJPA虽然免费,但功能、性能、普及性等方面更加需要加大力度。   对于EJB来说,实体Bean一直是被批评的对象,由于其太复杂和庞大。JPA的出现,很大程度的分离了复杂性。这让EJB的推广也变得容易。   总而言之,JPA规范主要关注的仅是API的行为方面,而由各种实现完成大多数性能有关的调优。尽管如此,所有可靠的实现都应该拥有某种数据缓存,以作为选择。但愿不久的将来,JPA能成为真正的标准。

下面是Spring集成JPA的一个例子。
实体类MyUser,使用JPA注解实现到数据库表myUser的映射,如下所示:

package org.shirdrn.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Transient;
@Entity
public class MyUser {
private Long id;
private String userName;
private String password;
private String gender;
private Integer age;
private Integer birthYear;
private String addr;
private String email;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) 
public Long getId() {
   return id;
}
public void setId(Long id) {
   this.id = id;
}
@Column(name="userName")
public String getUserName() {
   return userName;
}
public void setUserName(String userName) {
   this.userName = userName;
}
@Column(name="password")
public String getPassword() {
   return password;
}
public void setPassword(String password) {
   this.password = password;
}
@Column(name="gender")
public String getGender() {
   return gender;
}
public void setGender(String gender) {
   this.gender = gender;
}
@Column(name="age")
public Integer getAge() {
   return age;
}
public void setAge(Integer age) {
   this.age = age;
}
@Column(name="addr")
public String getAddr() {
   return addr;
}
public void setAddr(String addr) {
   this.addr = addr;
}
@Column(name="email")
public String getEmail() {
   return email;
}
public void setEmail(String email) {
   this.email = email;
}
@Transient
public Integer getBirthYear() {
   return new Integer(2008-age);
}
public void setBirthYear(Integer age) {
   this.birthYear = new Integer(2008-age);
}
}

其中,birthYear不是数据库中的字段,使用JPA的@Transient注解,在映射的时候,会忽略掉该成员。

持久层DAO接口如下:


package org.shirdrn.dao;
import java.util.List;
import org.shirdrn.entity.MyUser;
import org.springframework.transaction.annotation.Transactional;
@Transactional
public interface MyUserDAO {
public void createMyUser(MyUser myUser);
public void deleteMyUser(MyUser myUser);
public void updateMyUser(MyUser myUser);
public List<MyUser> queryMyUser(String queryString);
public List<MyUser> queryAll();
}

这里,使用了JPA注解,声明事务。
DAO实现类,如下所示:

package org.shirdrn.dao.impl;
import java.util.List;
import org.shirdrn.dao.MyUserDAO;
import org.shirdrn.entity.MyUser;
import org.springframework.orm.jpa.support.JpaDaoSupport;
public class MyUserDAOImpl extends JpaDaoSupport implements MyUserDAO {
public void createMyUser(MyUser myUser) {
   getJpaTemplate().persist(myUser);
}
public void deleteMyUser(MyUser myUser) {
   MyUser dbMyUser = getJpaTemplate().find(MyUser.class, myUser.getId());
   getJpaTemplate().remove(dbMyUser);
}
public void updateMyUser(MyUser myUser) {
   MyUser dbMyUser = getJpaTemplate().find(MyUser.class, myUser.getId());
   if(myUser.getUserName() != null){
    dbMyUser.setUserName(myUser.getUserName());
   }
   if(myUser.getAddr() != null){
    dbMyUser.setAddr(myUser.getAddr());
   }  
   getJpaTemplate().merge(dbMyUser);
}
@SuppressWarnings("unchecked")
public List<MyUser> queryMyUser(String queryString) {
   return (List<MyUser>)getJpaTemplate().find(queryString);
}
@SuppressWarnings("unchecked")
public List<MyUser> queryAll() {
   return (List<MyUser>)getJpaTemplate().find("from MyUser");
}
}
因为继承了JpaDaoSupport,索引需要获取一个JpaTemplate来实现访问数据库,在Spring的配置文件中要注入一个org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean。
Spring的配置文件applicationContext.xml的内容如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.microsoft.jdbc.sqlserver.SQLServerDriver" />
        <property name="url" value="jdbc:microsoft:sqlserver://localhost:1433;databasename=shirdrn" />
        <property name="username" value="sa" />
        <property name="password" value="111111" />
    </bean> 
<bean id="myEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="myDataSource"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true" />
                <property name="generateDdl" value="true" />
            </bean>
        </property>
    </bean>
    <bean id="jpaTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="myEntityManagerFactory"/>
        <property name="dataSource" ref="myDataSource"/>
    </bean>
    <tx:annotation-driven transaction-manager="jpaTxManager"/>
<bean id="myUserDAOImpl" class="org.shirdrn.dao.impl.MyUserDAOImpl"
   abstract="false" lazy-init="default" autowire="default"
   dependency-check="default">
   <property name="entityManagerFactory">
    <ref bean="myEntityManagerFactory" />
   </property>
</bean>
</beans>

在META-INF目录下,还要加一个persistence.xml配置文件,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="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="HibernateJPAPU" transaction-type="RESOURCE_LOCAL">
   <provider>org.hibernate.ejb.HibernatePersistence</provider>
   <class>org.shirdrn.entity.MyUser</class>
</persistence-unit>
</persistence>

接着,对增删改查操作进行测试,如下所示:
插入记录:
package org.shirdrn.test;
import org.shirdrn.dao.MyUserDAO;
import org.shirdrn.entity.MyUser;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestCreateMyUser {
public static void main(String[] args) {
   ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
   MyUserDAO myUserDAO = (MyUserDAO)ctx.getBean("myUserDAOImpl");
   MyUser myUser = new MyUser();
   myUser.setUserName("JohnXa");
   myUser.setPassword("123456");
   myUser.setGender("男");
   myUser.setAge(new Integer(25));
   myUser.setAddr("New York");
   myUser.setEmail("john@hotmail.com");
   myUserDAO.createMyUser(myUser);
}
}

删除记录:
package org.shirdrn.test;
import org.shirdrn.dao.MyUserDAO;
import org.shirdrn.entity.MyUser;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestDeleteMyUser {
public static void main(String[] args) {
   ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
   MyUserDAO myUserDAO = (MyUserDAO)ctx.getBean("myUserDAOImpl");
   MyUser myUser = new MyUser();
   myUser.setId(new Long(29));
   myUserDAO.deleteMyUser(myUser);
}
}

修改记录:
package org.shirdrn.test;
import org.shirdrn.dao.MyUserDAO;
import org.shirdrn.entity.MyUser;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUpdateMyUser {
public static void main(String[] args) {
   ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
   MyUserDAO myUserDAO = (MyUserDAO)ctx.getBean("myUserDAOImpl");
   MyUser myUser = new MyUser();
   myUser.setId(new Long(28));
   myUser.setAddr("北京市");
   myUserDAO.updateMyUser(myUser);
}
}

查询记录:

package org.shirdrn.test;
import java.util.List;
import org.shirdrn.dao.MyUserDAO;
import org.shirdrn.entity.MyUser;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestQueryAllMyUser {
public static void main(String[] args) {
   ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
   MyUserDAO myUserDAO = (MyUserDAO)ctx.getBean("myUserDAOImpl");
   List<MyUser> list = myUserDAO.queryMyUser("from MyUser");
   for(MyUser user : list){
    System.out.println("ID:"+user.getId()+
      "|姓名:"+user.getUserName()+
      "|密码:"+user.getPassword()+
      "|性别:"+user.getGender()+
      "|年龄:"+user.getAge()+
      "|住址:"+user.getAddr()+
      "|邮箱:"+user.getEmail());
   }
}
}

心得总结
感觉自己对JPA的理解还是不怎么深刻。JpaTemplate提供的一些操作的方法,感觉不是很快就能理解的。不过对数据库的操作还是很方便的,这样就可以摆脱原来复杂的对数据库的操作。在Spring中使用JPA,感觉代价比较大,使用起来不容易,出错不容易调试。比较好的地方就是。如果数据库中的表很多,无需编写大量的XML文件去映射,而且只需要从POJO中就可以非常直观地看到各个表之间的关系。