原文发布于:http://www.gufeng.tech/ 谷风的我的主页java
JPA全称Java Persistence API即Java持久化API,是一种经过注解或者XML配置描述映射关系来实现将实体持久化到数据库的一种java持久化实现方案。JPA和JDBC同样,都是jdk提供的API,各厂商提供实现,目前的实现有Apache的OpenJPA以及应用普遍的Hibernate,固然还有其它的实现,这里就不一一列出了。JAP做为一种标准,已经得到了JavaEES容器的支持,同时也仍然能够在JavaSE环境中使用,这就奠基了它可被普遍应用的前提。mysql
JPA在随着SpringBoot的默认支持,再次被普遍说起、应用。做为一种ORM的技术,除了拥有ORM的特色以外,还有一些它本身的特色:程序员
1 标准化web
JPA是java标准化组织JCP提出的一项持久化标准,因此其任何实现都提供了相同的API,即使更换了实现方案,兼容性也是很是好的。sql
2 更面向对象数据库
JPA支持面向对象中的继承、多态及多个类间的关联关系,所以使得程序员在使用JPA开发时能够方便的使用面向对象的思惟,过渡性比较好。并发
3 功能全面框架
JPA支持事务、并发等特性,而不只仅是一个简单的持久化框架,于是能够在实际使用中发挥更大的做用。ide
4 卓越的查询能力工具
JPA是面向对象的,定义了JPQL(Java Persistence Query Language),JPQL是一种针对实体的查询语句,操做对象是实体,能够以面向对象的方式构造查询语句,在这点上相似Hibernate的HQL。JPQL可以支持批量操做(如更新和修改)、join、group by、having等子句,同时还支持子查询,所以其查询能力可见一斑。
5 集成方便
这一点从SpringBoot选择了JPA就可以看出来。在JPA框架下建立实体只须要使用javax.persistence.Entity注解便可,其接口使用也很是简单容易上手,尤为重要的一点是JPA被设计成非***式的,自然注定了它可以被很是容易的集成。
JPA涉及的技术
1 元数据
关于映射关系,JPA同时支持注解和XML。
2 API
操做简单,将程序员从繁琐的SQL中解放出来。
3 查询语言
经过面向对象的方式进行数据查询,避免程序与SQL语句的的耦合。
上面说起了JPA的各类好处,那么做为一种技术方案(或者叫规范),JPA有没有缺点呢?答案是确定的,JPA将数据库关系以实体及实体间关系表示,必然存在一种将数据库的复杂概念(如一对1、一对多、多对多等关系)转移到程序中。这会带来如下一些问题:
1 程序可读性差,若是遇到特别复杂的业务逻辑,那么对于实体的定义也会很是困难,这须要设计者具备很是高的抽象、规范、设计能力。
2 数据关系发生变化时,实体必然也会发生变化。
3 将关系型数据库映射到面向对象程序上,自己就有着深度的复杂性,二者关注点不一样,当关联到一块儿的时候必然会来带冲突。数据库关心的是数据以及数据的完整性;面向对象关心的是对象的成员及行为。
接下来介绍下JPA的一些核心类:
1 EntityManagerFactory
EntityManagerFactory 是 EntityManager 的工厂类,负责建立 EntityManager 对象。
2 EntityManager
EntityManager 是 JPA 应用中使用的基本对象,经过它提供的相应方法能够管理持久化对象,也能够新建或者删除持久化对象。EntityManager 还负责建立 Query 实例。在容器外使用时,EntityManagerFactory 和 EntityManager 之间是一对一的关系。
3 EntityTransaction
EntityTransaction 提供 Entity 操做时须要的事务管理,和 EntityManager 是一对一的关系。在查询操做时不须要使用 EntityTransaction,而在对象持久化、状态更新、对象删除等状况下则必须使用显式的使用 EntityTransaction 的相关方法管理事务。
4 Query
Query 是查询实体的接口,Query 对象能够从 EntityManager 中得到。根据 EJB 3.0 规范中的描述,Query 接口须要同时支持 JPQL 和原生态 SQL 两种语法。
5 Persistence
Persistence 是一个工具类,负责根据配置文件提供的参数建立 EntityManagerFactory 对象。
最后看一段JPA的示例代码:
import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "user") public class User { @Id @Column(name = "id") private String id; @Column(name = "name") private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import java.util.List; public class Main { static EntityManagerFactory emf = Persistence.createEntityManagerFactory("gufengJPA"); static EntityManager em = emf.createEntityManager(); public static void main(String[] args) { User person = new User(); person.setId(123456l); person.setName("张无忌"); em.persist(person); add(person); System.out.println("user id:" + person.getId()); User user = find(person.getId()); System.out.println(user); List<User> all = findAll(); for (User u : all) { System.out.println(u); } em.close(); emf.close(); } public static void add(User user) { em.getTransaction().begin(); em.persist(user); em.getTransaction().commit(); } public static User find(Object id) { User user = em.find(User.class, id); return user; } public static List<User> findAll() { List<User> users = em.createQuery("select u from User u") .getResultList(); return users; } }
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" 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_2_0.xsd"> <!-- 持久化单元 --> <persistence-unit name="gufengJPA" transaction-type="RESOURCE_LOCAL"> <!--能够指定,若是不指定则从META-INF/services加载--> <!--<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>--> <!-- <class>com.micmiu.hibernate.jpa.UserInfo</class> --> <!--<provider>com.tongweb.openjpa.persistence.PersistenceProviderImpl</provider>--> <!--<jta-data-source>MyDataSource</jta-data-source>--> <!-- class 定义指定持久化的实体类 注意配置属性hibernate.archive.autodetection=false --> <!--<class>jpa.User</class>--> <properties> <property name="hibernate.archive.autodetection" value="class,hbm"/> <!--Hibernate 方言 --> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/> <!--数据库url --> <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/test"/> <!--数据库驱动 --> <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/> <!--配置数据库用户名 --> <property name="hibernate.connection.username" value="root"/> <!--配置数据库密码 --> <property name="hibernate.connection.password" value="123456"/> <!--设置外链接抓取树的最大深度 --> <!--<property name="hibernate.max_fetch_depth" value="3"/>--> <!--自动输出schema建立DDL语句 --> <!--<property name="hibernate.hbm2ddl.auto" value="update"/>--> <property name="hibernate.show_sql" value="true"/> </properties> </persistence-unit> </persistence>
这里须要注意的是JPA配置文件persistence.xml 必需放到类路径的根路径的META-INF文件夹下。
Persistence.createEntityManagerFactory("gufengJPA");
上面这行代码是经过Java的SPI机制得到具体实现的。在hibernate的jar包里有个META-INF/services/javax.persistence.spi.PersistenceProvider 文件,这里指定的实现为 org.hibernate.jpa.HibernatePersistenceProvider。再有多个的时候,Persistence只会使用第一个。