JPA是什么?

用于对象持久化的API,是一种ORM规范,是Hibernate功能的一个子集

主要包括三个方面的技术:
  • ORM映射元数据,支持XML和JDK注解两种元数据的形式
  • JPA的API
  • 查询语言:JPQL

JPA的HelloWorld

创建JPA工程。

连接数据库不要忘记添加MySQL 驱动

src的META-INF目录下自动生成一个persistence.xml
<?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="jpa" transaction-type="RESOURCE_LOCAL">
 
          <!-- 使用什么 ORM 产品作为 JPA 的实现 -->
          <provider>org.hibernate.ejb.HibernatePersistence</provider>
          <!--添加持久化类-->
          <class>com.software.jpa.helloworld.Customer
 
        <properties>
             <!-- 数据库连接的基本信息 -->
             <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
             <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa2" />
             <property name="javax.persistence.jdbc.user" value="root" />
             <property name="javax.persistence.jdbc.password" value="qiqingqing" />
            <!-- 配置 JPA 实现产品的基本属性,即 Hibernate 的基本属性 -->
             <property name="hibernate.show_sql" value="true" />
             <property name="hibernate.format_sql" value="true" />
             <property name="hibernate.hbm2ddl.auto" value="update" />
         </properties>
 
     </persistence-unit>
 </persistence>

创建bean类,并添加JPA注解:
package com.software.jpa.helloworld;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.Table;
 
 @Table(name="JPA_CUSTOMERS")
 @Entity
 public class Customer {     
     private Integer id;
     
     private String lastName;
     
     private String email;
     
     private Integer age;
 
     @GeneratedValue(strategy=GenerationType.AUTO)
     @Id
     public Integer getId() {
         return id;
     }
 
     public void setId(Integer id) {
         this.id = id;
     }
 
     @Column(name="LAST_NAME")
     public String getLastName() {
         return lastName;
     }
 
     public void setLastName(String lastName) {
         this.lastName = lastName;
     }
 
     public String getEmail() {
         return email;
     }
 
     public void setEmail(String email) {
         this.email = email;
     }
 
     public Integer getAge() {
         return age;
     }
 
     public void setAge(Integer age) {
         this.age = age;
     }
 
     @Override
     public String toString() {
         return "Customer [id=" + id + ", lastName=" + lastName + ", email=" + email + ", age=" + age + "]";
     }
     
 }

创建一个测试类:
package com.software.jpa.helloworld;

 import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
 import javax.persistence.EntityTransaction;
 import javax.persistence.Persistence;
 
 public class Main {
     
     public static void main(String[] args) {
         
         //1.创建 EntityManagerFactory
         String persistenceUnitName = "jpa";      //persistence.xml中指定的一致          EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
         
         //2.创建 EntityManager
         EntityManager entityManager = entityManagerFactory.createEntityManager();
         
         //4.开启事务
         EntityTransaction transaction = entityManager.getTransaction();
         transaction.begin();
         
         //5.进行持久化操作
         Customer customer = new Customer();
         customer.setLastName("AA");
         customer.setEmail("aa@163.com");
         customer.setAge(20);
         
         entityManager.persist(customer);
         
         //6.提交事务
         transaction.commit();
         
         //7.关闭 EntityManager
         entityManager.close();
         
         //8.关闭 EntityManagerFactory
         entityManagerFactory.close();
         
     }
     
 }

JPA的基本注解:

1. @Entity :修饰实体类,指明该类将映射到指定的数据表,例如:Customer 类默认的数据表名为 customer

2. @Table :实体类与映射的数据库表名不同名时需要使用 @Table 注解,该注解与 @Entity 注解并列使用,使用其 name 属性指明数据库的表名

 @Table(name = "JPA_CUSTOMER")
 @Entity
  public class Customer {

3. @Id :标识该属性为主键一般标注在该属性的 getter 方法上

4. @GeneratedValue :标注主键的生成策略,通过其 strategy 属性。通常与 @Id 注解一起使用。默认情况下 JPA 会自动选择一个最适合底层数据库的主键生成策略,MySQL 默认为 AUTO,常用策略有:

–IDENTITY:采用数据库 ID自增长的方式来自增主键字段,Oracle 不支持这种方式;

AUTO: JPA自动选择合适的策略,是默认选项

–SEQUENCE:通过序列产生主键,通过 @SequenceGenerator 注解指定序列名,MySql 不支持这种方式

–TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植

5. @Basic :用于没有任何标注的 getXxx() 方法,默认即为 @Basic,所以若一个 getter 方法无任何注解,可以使用 @Basic 注解,也可以不使用

6. @Column :当实体的属性与其映射的数据表的列不同名时使用,一般用于 getter 方法上。其name 属性用来指明此属性在数据表中对应的列名unique 属性指明是否为唯一约束nullable 属性用来指明是否可以为空,false 为不能为空length 属性指明此列的长度
@Column(name="LAST_NAME",LENGTH=50,nullable=false)
public String getLastName(){
    return lastName;
}
7. @Transient :标注此注解后在创建数据表的时候将会忽略该属性  Customer 类并没有 info 这个属性,所以数据库中也不应该有 info 这个字段
Birth 属性应该使用 DATE 类型(生日只具体到日即可,如:2015-10-22),而 CreateTime 应该使用 TIMESTAMP 类型(创建时间应该具体到秒,如:2017-10-11 22:39:13)
@Temporal(TemporalType.DATE)
public Date getBirth(){
    return birth;
}
public void setBirth(Date birth){
    this.birth=birth;
}
@Temporal(TemporalType.TIMESTAMP)
public Date getCreateTime(){
    return createTime;
}

JPA的API

1.Persistence :用于获取 EntiryManagerFactory 的实例
    Persistence.createEntityManagerFactory(persistenceUnitName)
2.EntiryManagerFactory 
    find()获取的意思 entityManager.find(Customer.class,1)
    getReference()若不是用查询对象则返回ige代理对象,到真正使用的时候才发送Sql语句查      询
3.persistence()   保存持久化到数据库
4.merge()  类似于Hibernate的saveOrUpdate()
5.EntityTransactionJPA 中的事务操作
   begin()      commit()     rollback()

JPA 中映射关联关系

1. 映射单向多对一的关联关系:
   @ManyToOne 映射多对一的关联关系,使用 @JoinColumn 来标注外键
2.单向多对一的保存(persist)保存多对一时,建议先保存 1 的一端,后保存 n 的一端,这样不会多出额外的 UPDATE 语句
3.获取操作(find)默认情况下使用左外连接的方式来获取 n 的一端的对象和其关联的 1 的一端的对象,可以使用 @ManyToOne 的 fetch 属性修改默认的关联属性的加载策略
4.删除操作(remove):不能直接删除 1 的一端,因为有外键约束

JPA 的二级缓存

<!-- 二级缓存相关 -->
    <!-- 配置二级缓存的策略 
                ALL:所有的实体类都被缓存
                NONE:所有的实体类都不被缓存. 
                ENABLE_SELECTIVE:标识 @Cacheable(true) 注解的实体类将被缓存 
                DISABLE_SELECTIVE:缓存除标识 @Cacheable(false) 以外的所有实体类
                UNSPECIFIED:默认值,JPA 产品默认值将被使用 
     -->
            <property name="hibernate.cache.use_second_level_cache"
                value="true" />
            <property name="hibernate.cache.region.factory_class"
                value="org.hibernate.cache.ehcache.EhCacheRegionFactory" />
            <property name="hibernate.cache.use_query_cache" value="true" />

配置文件:对二级缓存参数的配置
<ehcache>

    <!-- Sets the path to the directory where cache .data files are created.

         If the path is a Java System Property it is replaced by
         its value in the running VM.

         The following properties are translated:
         user.home - User's home directory
         user.dir - User's current working directory
         java.io.tmpdir - Default temp file path -->
    <diskStore path="java.io.tmpdir"/>


    <!--Default Cache configuration. These will applied to caches programmatically created through
        the CacheManager.

        The following attributes are required for defaultCache:

        maxInMemory       - Sets the maximum number of objects that will be created in memory
        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
                            is never expired.
        timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
                            if the element is not eternal. Idle time is now - last accessed time
        timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
                            if the element is not eternal. TTL is now - creation time
        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
                            has reached the maxInMemory limit.

        -->
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />

    <!--Predefined caches.  Add your cache configuration settings here.
        If you do not have a configuration for your cache a WARNING will be issued when the
        CacheManager starts

        The following attributes are required for defaultCache:

        name              - Sets the name of the cache. This is used to identify the cache. It must be unique.
        maxInMemory       - Sets the maximum number of objects that will be created in memory
        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
                            is never expired.
        timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
                            if the element is not eternal. Idle time is now - last accessed time
        timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
                            if the element is not eternal. TTL is now - creation time
        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
                            has reached the maxInMemory limit.

        -->

    <!-- Sample cache named sampleCache1
        This cache contains a maximum in memory of 10000 elements, and will expire
        an element if it is idle for more than 5 minutes and lives for more than
        10 minutes.

        If there are more than 10000 elements it will overflow to the
        disk cache, which in this configuration will go to wherever java.io.tmp is
        defined on your system. On a standard Linux system this will be /tmp"
        -->
    <cache name="sampleCache1"
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />

    <!-- Sample cache named sampleCache2
        This cache contains 1000 elements. Elements will always be held in memory.
        They are not expired. -->
    <cache name="sampleCache2"
        maxElementsInMemory="1000"
        eternal="true"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        /> -->

    <!-- Place configuration for your caches following -->

</ehcache>
给需要缓存的类添加 @Cacheable(true) 注解
@Cacheable(true)
@Table(name="JPA_CUSTOMER")
@Entity
public class Customer{}

JPQL  java持久化查询语言。

@Test
public void testHelloJPQL{
    String jpql="FROM Customer c WHERE c.age>?"
    Query query=entityManager.createQuery(jpql);
    
    query.setParameter(1,21);  //占位符的索引从1开始
    List<Customer> lists=query.getResultList();
    System.out.println(lists.size());
}

Spring 整合 JPA

1.新建 JPA 工程,导入所需的 jar包(Hibernate、JPA、c3p0、Spring、MySQL 驱动)

2.类路径下创建 db.properties 数据库配置文件,配置数据库的链接信息(LZ 在这只配置了必须属性)

1 jdbc.user=root 2 jdbc.password=qiqingqing 3 jdbc.driverClass=com.mysql.jdbc.Driver 4 jdbc.jdbcUrl=jdbc:mysql://localhost:3306/jpa
3.类路径下创建 Spring 的配置文件 applicationContext.xml,配置自动扫描的包,将 db.propertiest 文件导入,并配置 c3p0 数据源
类路径下创建 Spring 的配置文件 applicationContext.xml,配置自动扫描的包,将 db.propertiest 文件导入,并配置 c3p0 数据源
 <!-- 配置自动扫描的包 -->
     <context:component-scan base-package="com.software.jpa"></context:component-scan>
 
     <!-- 配置数据源 -->
     <context:property-placeholder location="classpath:db.properties"/>
     
     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
         <property name="user" value="${jdbc.user}"></property>
         <property name="password" value="${jdbc.password}"></property>
         <property name="driverClass" value="${jdbc.driverClass}"></property>
         <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
     </bean>
 <!-- 配置 EntityManagerFactory -->
     <bean id="entityManagerFactory"
                  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
         <!-- 配置数据源 -->
         <property name="dataSource" ref="dataSource"></property>
         <!-- 配置 JPA 提供商的适配器,可以通过内部 bean 的方式来配置 -->
         <property name="jpaVendorAdapter">
             <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean>
         </property>
         <!-- 配置实体类所在的包 -->
         <property name="packagesToScan" value="com.software.jpa.spring.entities"></property>
         <!-- 配置 JPA 的基本属性,比如,JPA 实现产品的属性 -->
         <property name="jpaProperties">
             <props>
                 <prop key="hibernate.show_sql">true</prop>
                 <prop key="hibernate.format_sql">true</prop>
                 <prop key="hibernate.hbm2ddl.auto">update</prop>
             </props>
         </property>
     </bean>
<!-- 配置  JPA 使用的事务管理器 -->
     <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
         <property name="entityManagerFactory" ref="entityManagerFactory"></property>
     </bean>
     
     <!-- 配置支持基于注解的事务配置 -->
     <tx:annotation-driven transaction-manager="transactionManager"/>