290 likes | 468 Views
Java Persistence API(1.0). 徐克平 2010/4. 概述. Java Persistence API 作为 JavaEE5.0 平台标准的 ORM 规范,将得到所有 JavaEE 服务器的支持。 JPA 由 EJB3.0 软件开发组开发,作为 JSR-220 实现的一部分。 目前 Hibernate3.2 、 TopLink10.1.3 以及 OpenJPA 都提供了 JPA 的支持。. 什么是 JPA. JPA 包括以下三个方面技术
E N D
Java Persistence API(1.0) 徐克平 2010/4
概述 • Java Persistence API作为JavaEE5.0平台标准的ORM规范,将得到所有JavaEE服务器的支持。 • JPA由EJB3.0软件开发组开发,作为JSR-220实现的一部分。 • 目前Hibernate3.2、TopLink10.1.3以及OpenJPA都提供了JPA的支持。
什么是JPA JPA包括以下三个方面技术 • ORM映射元数据,JPA支持xml和jdk5.0注释,元数据描述对象与表之间的映射关系,框架据此将实体对象持久化到数据库当中。 • Java持久化API,用来操作实体对象,执行CURD操作,框架在后台替我们完成所有的事情开发者可以从JDBC和SQL代码中解脱出来。 • 查询语言,这是持久化操作很重要的一个方面,通过面向对象而非面向数据库的查询数据,避免程序与SQL的紧密耦合。
环境构建 • Ide采用MyEclipse6.0,数据库采用Mysql,持久层框架JPA1.0。 • Hibernate 从3.2开始,就开始兼容JPA。Hibernate3.2获得了Sun TCK的JPA(Java Persistence API) 兼容认证。 • 下载地址http://www.hibernate.org/当中的3.2版本。
开发JPA依赖的jar包开发JPA依赖的jar包 Hiberante核心包(8个文件) hibernate-distribution.GA --------------------------------------------- hibernate3.jar lib\bytecode\cglib\hibernate-cglib-repack.jar lib\required\*.jar Hiberante注解包(3个文件):hibernate-annotationsGA ------------------------------------------------------------------------------------ hibernate-annotations.jar lib\ejb3-persistence.jar、hibernate-commons-annotations.jar Hibernate针对JPA的实现包(3个文件):hibernate-entitymanagerGA ------------------------------------------------------------------------------------------------------ hibernate-entitymanager.jar lib\test\log4j.jar、slf4j-log4j12.jar
JPA配置文件 JPA规范要求在类路径的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/persistencehttp://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"version="1.0"> <persistence-unit name="jpaPU" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.connection.driver_class"value="com.mysql.jdbc.Driver" /> <property name="hibernate.connection.url“ value="jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8" /> <property name="hibernate.connection.username" value="root" /> <property name="hibernate.connection.password" value="root" /> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.show_sql" value="true" /> </properties> </persistence-unit> </persistence>
实体对象 • 访问数据库之前,我们总是要设计在应用层承载数据数据的领域对象,ORM框架将它们持久化到数据库当中。 • 按照JPA规范实体必须具备以下要求: 必须使用javax.persistence.Entity注解或者在XML映射文件中有对应的元素。 必须具有一个不带参的构造函数,类不能声明final,方法和持久化的属性也不能声明成final。并且持久化的属性修饰符不能为public。 如果游离状的实体需要以值的方式进行传递,如Session bean,则必须实现Serializable接口
使用基本注解元数据 • @Entity:将领域对象标注为一个实体,默认情况下类名为表名,通过name可以重新指定。 • @Id:属性对应的表的主键。 • @Column:属性对应的表字段。 • @GeneratedValue:主键产生策略,通过startage属性指定。
主键生成策略 • IDENTITY:主键由数据库自动生成。 • AUTO:JPA自动选择合适的策略,是默认选项。 • SEQUENCE:通过序列产生主键,条件是数据库需要支持序列。 • TABLE:通过表产生主键,使用该策略更易于数据库移植。
实体关系 • 实体之间的关系有:一对一,一对多,多一对,多对多。关系是多态的。 • 双向关系的反向端必须通过OnToOne,OnToMany或ManyToMany注解的MappedBy元素指向它的持久端。MappedBy表示主控端的属性/字段。 • 一对多/多对一双向关系中的多端必须是持久端,因此不能再ManyToOne中使用MappedBy元素。 • 对于一对一双向关系,包括对应的外键(foreign for)的那一端是持久端。 • 对于多对多双向关系,任何一端都是持久端。
双向OnToOne关系 @Entity public class Employee { private Cubicle cubicle; @OneToOne public Cubicle getCubicle() { return cubicle; } } @Entity public class Cubicle { private Employee employee; @OneToOne(mappedBy = "cubicle") public Employee getEmployee( ) { return employee; } }
双向ManyToOne/OnToMany! • @Entity • public class Employee { • private Department department; • @ManyToOne • public Department getDepartment() { • return department; • } • public void setDepartment(Department department) { • this.department = department; • } • ... • } 非常简单
双向ManyToOne/OnToMany! • @ • Entity • public class Department { • private Collection<Employee> employees = new HashSet(); • @OneToMany(mappedBy="department") • public Collection<Employee> getEmployees() { • return employees; • } • public void setEmployees(Collection<Employee> employees) { • this.employees = employees; • } • ... • }在这个例子中: • 实体Employee引用实体Department的单个实例。 • 实体Department引用一个实体Employee的集合
单向一对一! • @Entity • public class Employee { • private TravelProfile profile; • @OneToOne • public TravelProfile getProfile() { • return profile; • } • public void setProfile(TravelProfile profile) { • this.profile = profile; • } • ... • }
单向一对一! • @Entity • public class TravelProfile { • ... • }
单向多对一! • @Entity • public class Employee { • private Address address; • @ManyToOne • public Address getAddress() { • return address; • } • public void setAddress(Address address) { • this.address = address; • } • ... • } • @ • Entity • public class Address { • ... • }
双向多对多关系! • @Entity • public class Project { • private Collection<Employee> employees; • @ManyToMany • public Collection<Employee> getEmployees() { • return employees; • } • public void setEmployees(Collection<Employee> employees) { • this.employees = employees; • } • ... • }
@Entity • public class Employee { • private Collection<Project> projects; • @ManyToMany(mappedBy="employees") • public Collection<Project> getProjects() { • return projects; • } • public void setProjects(Collection<Project> projects) { • this.projects = projects; • } • ... • }
延迟加载 • # FetchType.EAGER:代表立即加载 • # FetchType.LAZY:代表延迟加载
多级级联 • 级联方式 • ---REFRESH:指定当在你访问期间,如果数据库数据发生变动时,你的数据是否更新 • ---PERSIST:指定在保存1的数据时是否会同时保存级联的n数据。 • ---MERGE:指定当1处于游离状态被修改了,n的数据也有修改,MERGE可以在对1进行更新的同时也对n方进行更新 • ---REMOVE:指定在删除1时是否删除与之级联的n方 • ---ALL:指定包含所有级联的n方
如何新建实例 • 打开MyEclipse新建立一个WEB项目 • 添加开发JPA依赖的jar包。 • 在类路径的META-INF目录下添加persistence.xml配置文件
@Entity • publicclass User { • private Long id;private String userName; • private Collection<UserRole> userRoles = new HashSet<UserRole>(); • @Id • @GeneratedValue(strategy = GenerationType.IDENTITY) • public Long getId() {return id;} • publicvoid setId(Long id) { • this.id = id; • } • public String getUserName() { • return userName; • } • publicvoid setUserName(String userName) { • this.userName = userName; • } • @OneToMany(mappedBy = "user") • public Collection<UserRole> getUserRoles() { • return userRoles; • } • publicvoid setUserRoles(Collection<UserRole> userRoles) { • this.userRoles = userRoles; • } • }
角色 • @Entity • public class Role { • private Long id; • private String roleName;// 角色名称 • private Collection<UserRole> userRoles = new HashSet<UserRole>(); • @Id • @GeneratedValue(strategy = GenerationType.IDENTITY) • public Long getId() { • return id; • } • public void setId(Long id) { • this.id = id; • } • public String getRoleName() { • return roleName; • } • public void setRoleName(String roleName) { • this.roleName = roleName; • } • @OneToMany(mappedBy = "role") • public Collection<UserRole> getUserRoles() { • return userRoles; • } • public void setUserRoles(Collection<UserRole> userRoles) { • this.userRoles = userRoles; • } • }
用户角色 • @Entity • public class UserRole { • private Long id; • private Role role; • private User user; • @Id • @GeneratedValue(strategy = GenerationType.IDENTITY) • public Long getId() { • return id; • } • public void setId(Long id) { • this.id = id; • } • @ManyToOne(cascade = CascadeType.ALL) • public Role getRole() { • return role; • } • public void setRole(Role role) { • this.role = role; • } • /** • * 延迟加载EAGER表示查询的时候已经全部加载lazy表示使用的时候才开始加载 • * • * @return • */ • @ManyToOne(fetch = FetchType.LAZY) • public User getUser() { • return user; • } • public void setUser(User user) { • this.user = user; • } • }
增加数据测试用例 public class UserTest { • /** • * • */ • EntityManagerFactory factory = Persistence • .createEntityManagerFactory("jpaPU"); • EntityManager em = factory.createEntityManager(); • @Test • public void testSava() { • try { • em.getTransaction().begin(); • User user = new User(); • user.setUserName("xukeping2"); • user.setPasswrod("xukeping2"); • user.setDescription("travelProfile"); • em.persist(user); • em.flush(); • em.getTransaction().commit(); • em.close(); • factory.close(); • } catch (Exception e) { • e.printStackTrace(); • } • } }
查询单表测试用例 public class UserTest { • /** • * • */ • EntityManagerFactory factory = Persistence • .createEntityManagerFactory("jpaPU"); • EntityManager em = factory.createEntityManager(); • @Test • @SuppressWarnings("unchecked") • public void testQuery() { • try { • em.getTransaction().begin(); • List<User> users = (List<User>) em.createQuery("from User") • .getResultList(); • for (Iterator iterator = users.iterator(); iterator.hasNext();) { • User role = (User) iterator.next(); • System.out.println(role.getId() + " " + role.getUserName()); • } • em.close(); • factory.close(); • } catch (Exception e) { • e.printStackTrace(); • } • }}
延迟加载测试用例 • @Test • @SuppressWarnings("unchecked") • public void testFetchType() { • try { • em.getTransaction().begin(); • List<UserRole> userRoles = (List<UserRole>) em.createQuery( • "from UserRole").getResultList(); • UserRole userRole = (UserRole) userRoles.get(1); • System.out.println("开始......."); • System.out.println("userRole" + userRole.getUser().getUserName()); • System.out.println("结束......."); • em.close(); • factory.close(); • } catch (Exception e) { • e.printStackTrace(); • } • } • @ManyToOne(fetch = FetchType.LAZY) • 注意:当程序运行到userRole.getUser().getUserName())时,JPA会自动查询JPQLselect user0_.id as id9_0_, user0_.description as descript2_9_0_, user0_.passwrod as passwrod9_0_, user0_.userName as userName9_0_ from User user0_ where user0_.id=?;这就是延迟加载的作用;
多级级联测试用例 • /** • * 多级级联 • * • * ---REFRESH:指定当在你访问期间,如果数据库数据发生变动时,你的数据是否更新 • * • * ---PERSIST:指定在保存1的数据时是否会同时保存级联的n数据。 • * • * ---MERGE:指定当1处于游离状态被修改了,n的数据也有修改,MERGE可以在对1进行更新的同时也对n方进行更新 • * • * ---REMOVE:指定在删除1时是否删除与之级联的n方 • */ • @Test • @SuppressWarnings("unchecked") • public void testCascade() { • try { • em.getTransaction().begin(); • UserRole userRole = (UserRole) em.find(UserRole.class, 2l); • System.out.println("结束......." + userRole.getId()); • System.out.println("查询开始......."); • Role role = userRole.getRole(); • role.setRoleName("系统管理员2"); • userRole.setRole(role); • userRole = (UserRole) em.find(UserRole.class, 2l); • System.out.println("结束......." + userRole.getRole().getRoleName()); • em.persist(userRole); • em.getTransaction().commit(); • em.close(); • factory.close(); • } catch (Exception e) { • e.printStackTrace(); • } • }
多表查询测试用例 • /** • * 多表查询 • */ • @Test • @SuppressWarnings("unchecked") • public void testObjectQuery() { • try { • System.out.println("查询开始......."); • List<Object[]> objs = (List<Object[]>) em.createQuery( • "from UserRole,User,Role ").getResultList(); • for (Object[] objects : objs) { • System.out.println(((UserRole) objects[0]).getId()); • } • em.close(); • factory.close(); • } catch (Exception e) { • e.printStackTrace(); • } • }