JPA01
关于jpa总共写了三篇内容,下面附上链接:
JPA01:https://www.cnblogs.com/buwei/p/9979794.html
JPA02:https://www.cnblogs.com/buwei/p/9985287.html
JPA03:https://www.cnblogs.com/buwei/p/9985941.html
一、ORM概述
ORM表示对象关系映射。在面向对象的软件开发中,通过ORM,就可以把对象映射到关系型数据库中。只要有一套程序能够做到建立对象与数据库的关联,操作对象就可以直接操作数据库数据,就可以说这套程序实现了ORM对象关系映射。
简单的说:ORM就是建立了实体类和数据库表之间的关系,从而达到操作实体类就可以操作数据库表的目的。
1.1 为什么使用ORM
当实现了一个应用程序时(不使用O/R Mapping),我们可能会写特别多数据访问层的代码,从数据库保存数据、修改数据、删除数据,而这些代码都是重复的。而是用ORM则会大大减少重复性代码。对象关系映射,主要实现程序对象到关系数据库数据的映射。
1.2 常见ORM框架
常见的ORM框架:Mybatis(ibatis)、Hibernate、Jpa
二、 Hibernate与JPA概述
2.1 Hibernate概述
Hibernate是一个开放源代码的对象关系映射框架,他对Jdbc进行了非常轻量级的对象封装,他将POJO与数据库表建立映射关系,是一个全自动的ORM框架,Hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
2.2 JPA概述
JPA的全称是Java Persistence API,即Java持久化API,是Sun公司推出的一套基于ORM的规范,内部是由一系列的接口和抽象内构成。
JPA通过JDK5.0注解描述对象 -- 关系表的映射关系,并将运行期的实体对象持久化到数据库中。
2.3 JPA的优势
1.标准化
JPA是JCP组织发布的Java EE 标准之一,因此任何声称符合JPA标准的框架都遵循同样的架构,提供相同的访问API,这保证了基于JPA开发的企业应用能够经过商量的修改就能够在不同的JPA框架下运行。
2.容器特性的支持
JPA框架中支持大数据集、事务、并发等容器级事务,这使得JPA超越了简单持久化框架的局限,在企业应用发挥更大的作用。
3.简单方便
JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实体和创建Java类一样简单,没有任何的约束和限制,只需要使用javax.persistence.Entity进行注释,JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发者可以很容易的掌握。JPA基于非侵入式原则设计,因此可以很容易的和其他框架或容器集成。
4.查询能力
JPA的查询语言是面向对象而非面向数据库的,它以面向对象的自然语法构造查询语句,可以看成是Hibernate HQL的等价物。JPA定义了独特的JPQL,JPQL是EJB QL的一种扩展,它是针对实体的一种查询语言,操作对象时实体,而不是关系数据库的表,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING等通常只有SQL草能够提供的高级查询特性,甚至还鞥狗支持子查询。
5.高级特性
JPA中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,这样的支持能够让开发者最大限度的使用面向对象的模型设计企业应用,而不需要自行处理这些特性在关系数据库的持久化。
2.4 JPA与Hibernate的关系
JPA规范本质上市一种ORM规范,注意不是ORM框架——因为JPA并未提供ORM实现,他只是制定了一些规范,提供了一些编程的API接口,但是具体实现则有服务厂商来提供实现。
JPA和Hibernate的关系就像是JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现。如果使用JPA规范进行数据库操作,底层需要Hibernate作为其实现类完成数据持久化工作。
三、JPA的入门案例
3.1 需求介绍
案例:实现保存一个客户到数据库的客户表中。
3.2 开发包介绍
由于JPA是sun公司制定的API规范,所以我们不需要导入额外的JPA的jar包,只需要导入JPA的提供商的jar包,我们选择使用Hibernate作为JPA的提供商,所以需要导入Hibernate的相关jar包。
3.3 搭建开发环境
1.maven工程导入坐标
1 <dependencies> 2 <!-- junit --> 3 <dependency> 4 <groupId>junit</groupId> 5 <artifactId>junit</artifactId> 6 <version>4.12</version> 7 <scope>test</scope> 8 </dependency> 9 10 <!-- hibernate对jpa的支持包 --> 11 <dependency> 12 <groupId>org.hibernate</groupId> 13 <artifactId>hibernate-entitymanager</artifactId> 14 <version>${project.hibernate.version}</version> 15 </dependency> 16 17 <!-- c3p0 --> 18 <dependency> 19 <groupId>org.hibernate</groupId> 20 <artifactId>hibernate-c3p0</artifactId> 21 <version>${project.hibernate.version}</version> 22 </dependency> 23 24 <!-- log日志 --> 25 <dependency> 26 <groupId>log4j</groupId> 27 <artifactId>log4j</artifactId> 28 <version>1.2.17</version> 29 </dependency> 30 31 <!-- Mysql and MariaDB --> 32 <dependency> 33 <groupId>mysql</groupId> 34 <artifactId>mysql-connector-java</artifactId> 35 <version>5.1.6</version> 36 </dependency> 37 </dependencies>
2.创建客户的数据库表和客户的实体类
/*创建客户的数据库表*/
1 /*创建客户表*/ 2 CREATE TABLE cst_customer ( 3 cust_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)', 4 cust_name varchar(32) NOT NULL COMMENT '客户名称(公司名称)', 5 cust_source varchar(32) DEFAULT NULL COMMENT '客户信息来源', 6 cust_industry varchar(32) DEFAULT NULL COMMENT '客户所属行业', 7 cust_level varchar(32) DEFAULT NULL COMMENT '客户级别', 8 cust_address varchar(128) DEFAULT NULL COMMENT '客户联系地址', 9 cust_phone varchar(64) DEFAULT NULL COMMENT '客户联系电话', 10 PRIMARY KEY (`cust_id`) 11 ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
/*创建客户的实体类*/
1 public class Customer implements Serializable { 2 private Long custId; 3 private String custName; 4 private String custSource; 5 private String custIndustry; 6 private String custLevel; 7 private String custAddress; 8 private String custPhone; 9 10 public Long getCustId() { 11 return custId; 12 } 13 14 public void setCustId(Long custId) { 15 this.custId = custId; 16 } 17 18 public String getCustName() { 19 return custName; 20 } 21 22 public void setCustName(String custName) { 23 this.custName = custName; 24 } 25 26 public String getCustSource() { 27 return custSource; 28 } 29 30 public void setCustSource(String custSource) { 31 this.custSource = custSource; 32 } 33 34 public String getCustIndustry() { 35 return custIndustry; 36 } 37 38 public void setCustIndustry(String custIndustry) { 39 this.custIndustry = custIndustry; 40 } 41 42 public String getCustLevel() { 43 return custLevel; 44 } 45 46 public void setCustLevel(String custLevel) { 47 this.custLevel = custLevel; 48 } 49 50 public String getCustAddress() { 51 return custAddress; 52 } 53 54 public void setCustAddress(String custAddress) { 55 this.custAddress = custAddress; 56 } 57 58 public String getCustPhone() { 59 return custPhone; 60 } 61 62 public void setCustPhone(String custPhone) { 63 this.custPhone = custPhone; 64 } 65 }
3.编写实体类和数据库表的映射配置
在实体类上使用JPA注解的形式配置映射关系
1 @Entity //声明实体类 2 @Table(name="cst_customer") //建立实体类和表的映射关系 3 public class Customer implements Serializable { 4 @Id//声明当前私有属性为主键 5 @GeneratedValue(strategy=GenerationType.IDENTITY) //配置主键的生成策略 6 @Column(name="cust_id") //指定和表中cust_id字段的映射关系 7 private Long custId; 8 9 @Column(name="cust_name") //指定和表中cust_name字段的映射关系 10 private String custName; 11 12 @Column(name="cust_source")//指定和表中cust_source字段的映射关系 13 private String custSource; 14 15 @Column(name="cust_industry")//指定和表中cust_industry字段的映射关系 16 private String custIndustry; 17 18 @Column(name="cust_level")//指定和表中cust_level字段的映射关系 19 private String custLevel; 20 21 @Column(name="cust_address")//指定和表中cust_address字段的映射关系 22 private String custAddress; 23 24 @Column(name="cust_phone")//指定和表中cust_phone字段的映射关系 25 private String custPhone; 26 27 //省略getter和setter方法 28 }
常用注解的说明
1 @Entity 2 作用:指定当前类是实体类。 3 @Table 4 作用:指定实体类和表之间的对应关系。 5 属性: 6 name:指定数据库表的名称 7 @Id 8 作用:指定当前字段是主键。 9 @GeneratedValue 10 作用:指定主键的生成方式。。 11 属性: 12 strategy :指定主键生成策略。 13 @Column 14 作用:指定实体类属性和数据库表之间的对应关系 15 属性: 16 name:指定数据库表的列名称。 17 unique:是否唯一 18 nullable:是否可以为空 19 inserttable:是否可以插入 20 updateable:是否可以更新 21 columnDefinition: 定义建表时创建此列的DDL 22 secondaryTable: 从表名。如果此列不建在主表上(默认建在主表),该属性定义该列所在从表的名字搭建开发环境[重点]
4.配置JPA的核心配置文件
在Java工程的src路径小创建一个名为META-INF的文件夹,在此文件夹下创建一个名为persistence.xml的配置文件。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <persistence xmlns="http://java.sun.com/xml/ns/persistence" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 5 http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" 6 version="2.0"> 7 <!--配置持久化单元 8 name:持久化单元名称 9 transaction-type:事务类型 10 RESOURCE_LOCAL:本地事务管理 11 JTA:分布式事务管理 --> 12 <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL"> 13 <!--配置JPA规范的服务提供商 --> 14 <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> 15 <properties> 16 <!-- 数据库驱动 --> 17 <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" /> 18 <!-- 数据库地址 --> 19 <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/ssh" /> 20 <!-- 数据库用户名 --> 21 <property name="javax.persistence.jdbc.user" value="root" /> 22 <!-- 数据库密码 --> 23 <property name="javax.persistence.jdbc.password" value="root" /> 24 25 <!--jpa提供者的可选配置:我们的JPA规范的提供者为hibernate,所以jpa的核心配置中兼容hibernate的配 --> 26 <property name="hibernate.show_sql" value="true" /> 27 <property name="hibernate.format_sql" value="true" /> 28 <property name="hibernate.hbm2ddl.auto" value="create" /> 29 </properties> 30 </persistence-unit> 31 </persistence>
3.4 实现保存操作
1 public class JPATest { 2 /** 3 * 创建实体管理类工厂,借助Persistence的静态方法获取 4 * 其中传递的参数为持久化单元名称,需要jpa配置文件中指定 5 */ 6 EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa"); 7 //创建实体管理类 8 EntityManager em = factory.createEntityManager(); 9 //获取事务对象 10 EntityTransaction tx = em.getTransaction(); 11 //开启事务 12 tx.begin(); 13 Customer c = new Customer(); 14 c.setCustName("不为"); 15 //保存操作 16 em.persist(c); 17 //提交事务 18 tx.commit(); 19 //释放资源 20 em.close(); 21 factory.close(); 22 }
四、JPA中的主键生成策略
通过annotation(注解)来映射Hibernate实体,基于annotation的Hibernate主键标识为@Id,其生成规则由@GeneratedValue设定,这里的@Id和@GeneratedValue都是JPA的标准用法。
JPA提供的四种标准用法为TABLE,SEQUENCE,IDENTITY,AUTO。
具体说明如下:
1 在注解@GeneratedValue(strategy = GenerationType.IDENTITY)中可以配置不同的生成策略 2 GenerationType.IDENTITY :自增,mysql 3 * 底层数据库必须支持自动增长(底层数据库支持的自动增长方式,对id自增) 4 GenerationType.SEQUENCE : 序列,oracle 5 * 底层数据库必须支持序列 6 GenerationType.TABLE : jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增 7 GenerationType.AUTO : 由程序自动的帮助我们选择主键生成策略 8 9 常用的就IDENTITY和SEQUENCE 10 11 也可以配置用uuid作为主键,配置如下 12 @GenericGenerator(name="myuuid",strategy="uuid") 13 @GeneratedValue(generator="myuuid") 14 注意uuid名称要为小写
五、JPA的API介绍
5.1 Persistence对象
Persistence对象主要作用是用于获取EntityManagerFactory对象的。通过调用该类的createEntityManagerFactory静态方法,根据配置文件中持久化单元名称创建EntityManagerFactory。
1 // 创建 EntitymanagerFactory 2 @Test 3 String unitName = "myJpa"; 4 EntityManagerFactory factory = Persistence.createEntityManagerFactory(unitName);
5.2 EntityManagerFactory
EntityMangerFactory接口主要用来创建EntityManger实例。
1 // 创建实体管理类 2 EntityManager em = factory.createEntityManager();
由于EntityMangerFactory是一个线程安全的对象,并且EntityMangerFactory的创建机器浪费资源,所以在使用JPA编程时,我们可以对EntityMangerFactory的创建进行优化,只需要做到一个工程只存在一个EntityMangerFactory即可。
5.3 EntityManger
在JPA规范中,EntityManger是完成持久化操作的核心对象,实体类作为普通Java对象,只有在调用EntityManger将其持久化之后才能够编程持久化对象。EntityManger对象在一组实体类与底层数据源之间进行O/R映射的管理。它可以用来管理和更新Entity Bean,根据抓紧查找Entity Bean,还可以通过JPQL语句查询实体。
可以通过调用EntityManager的方法完成获取事务,以及持久化数据库的操作。
方法说明:
1 getTransaction : 获取事务对象 2 persist : 保存操作 3 merge : 更新操作 4 remove : 删除操作 5 find/getReference : 根据id查询
5.4 EntityTransaction
在JPA规范中,EntityTransaction是完成事务操作的核心对象,对于EntityTransaction在我们的Java代码中承接的功能比较简单。
1 begin:开启事务 2 commit:提交事务 3 rollback:回滚事务
六、抽取JPAUtil工具类
1 public final class JPAUtil { 2 // JPA的实体管理器工厂:相当于Hibernate的SessionFactory 3 private static EntityManagerFactory em; 4 // 使用静态代码块赋值 5 static { 6 // 注意:该方法参数必须和persistence.xml中persistence-unit标签name属性取值一致 7 em = Persistence.createEntityManagerFactory("myPersistUnit"); 8 } 9 /** 10 * 使用管理器工厂生产一个管理器对象 11 * @return 12 */ 13 public static EntityManager getEntityManager() { 14 return em.createEntityManager(); 15 } 16 }
JPA中的复杂查询 -- 使用JPQL语句
其特征与原生SQL语句类似,并且完全面向对象,通过类名和属性访问,而不是表名和表的属性。
1.查询全部
1 .... 2 // 创建query对象 3 String jpql = "from Customer"; 4 Query query = em.createQuery(jpql); 5 // 查询并得到返回结果 6 List list = query.getResultList(); // 得到集合返回类型 7 for (Object object : list) { 8 System.out.println(object); 9 } 10 ....
2.分页查询
1 .... 2 //创建query对象 3 String jpql = "from Customer"; 4 Query query = em.createQuery(jpql); 5 //起始索引 6 query.setFirstResult(0); 7 //每页显示条数 8 query.setMaxResults(2); 9 //查询并得到返回结果 10 List list = query.getResultList(); //得到集合返回类型 11 for (Object object : list) { 12 System.out.println(object); 13 } 14 ....
3.条件查询
.... //创建query对象 String jpql = "from Customer where custName like ? "; Query query = em.createQuery(jpql); //对占位符赋值,从1开始 query.setParameter(1, "不为%"); //查询并得到返回结果 Object object = query.getSingleResult(); //得到唯一的结果集对象 System.out.println(object); ....
4.排序查询
1 .... 2 // 创建query对象 3 String jpql = "from Customer order by custId desc"; 4 Query query = em.createQuery(jpql); 5 // 查询并得到返回结果 6 List list = query.getResultList(); // 得到集合返回类型 7 for (Object object : list) { 8 System.out.println(object); 9 } 10 ....
5.统计查询
1 .... 2 // 查询全部客户 3 // 1.创建query对象 4 String jpql = "select count(custId) from Customer"; 5 Query query = em.createQuery(jpql); 6 // 2.查询并得到返回结果 7 Object count = query.getSingleResult(); // 得到集合返回类型 8 System.out.println(count); 9 ....