JPA快速入门,包括ORM的概述以及对JPA和hibernate的简介,搭建JPA的入门案例、增删查改、复杂查询等操作。

1,315 阅读12分钟

@[toc]

ORM的概述

ORM(Object-Relational Mapping)表示对象关系映射。基于面向对象的思想,将对象与关系型数据库进行映射。简单而言,ORM就是建立实体类和数据库表之间的关系,从而达到操作实体类就相当于操作数据库表的目的。

主要目的:操作实体类就相当于操作数据库表

建立两个映射关系:

  • 实体类和表的映射关系
  • 实体类中属性和表中字段的映射关系 不再重点关注:sql语句

JAP的概述

常见的ORM框架有Mybatis(半自动),Hibernate(全自动),JPA。

JAP(Java Persistence API),即Java持久化API,由SUN公司退出的一套基于ORM的规范,内部由一系列的接口和抽象类组成。

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(Java Persistence Query Language),JPQL是EJB QL的一种扩展,它是针对实体的一种查询语言,操作对象是实体,而不是关系数据库的表,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。

5. 高级特性

JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,这样的支持能够让开发者最大限度的使用面向对象的模型设计企业应用,而不需要自行处理这些特性在关系数据库的持久化。

JAP与hibernate的关系

hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。

总之,hibernate的目的在于程序员忽略SQL语句,以执行对象的形式达到操作数据库表。

JPA与hibernate的关系

JPA和Hibernate的关系就像JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现。JPA怎么取代Hibernate呢?JDBC规范可以驱动底层数据库吗?答案是否定的,也就是说,如果使用JPA规范进行数据库操作,底层需要hibernate作为其实现类完成数据持久化工作。(可以类比JDBC规范和各个数据库厂商来具体实现这两者的关系)

JPA入门案例的搭建

基于工程:Maven工程

坐标:文章结尾处

数据库表:

 /*创建客户表*/
    CREATE TABLE cst_customer (
      cust_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
      cust_name varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
      cust_source varchar(32) DEFAULT NULL COMMENT '客户信息来源',
      cust_industry varchar(32) DEFAULT NULL COMMENT '客户所属行业',
      cust_level varchar(32) DEFAULT NULL COMMENT '客户级别',
      cust_address varchar(128) DEFAULT NULL COMMENT '客户联系地址',
      cust_phone varchar(64) DEFAULT NULL COMMENT '客户联系电话',
      PRIMARY KEY (`cust_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

实体类POJO:

public class Customer implements Serializable {
    
	private Long custId;
	private String custName;
	private String custSource;
	private String custIndustry;
	private String custLevel;
	private String custAddress;
	private String custPhone;
	...get/set方法(略)

项目目录:

项目目录

案例:对数据库中的客户表(增删查改)

  1. 创建maven工程,导入坐标

  2. 配置JPA的核心配置文件

    • 位置:配置到类路径下的一个叫做META-INF的文件夹下
    • 命名:persistent.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
        <!--
        持久化单元
            name:持久化单元名称  可以自定义
            transaction-type:事务管理的方式
                            JTA:分布式事务管理(针对:不同的表分布在不同的数据库中)
                            RESOURCE_LOCAL:本地事务管理
        -->
        <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
            <!--1.jpa的实现方式-->
            <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
            <properties>
                <!-- 2.配置数据库信息
                      用户名,javax.persistence.jdbc.user
                      密码,  javax.persistence.jdbc.password
                      驱动,  javax.persistence.jdbc.driver
                      数据库地址   javax.persistence.jdbc.url
                  -->
                <property name="javax.persistence.jdbc.user" value="root"/>
                <property name="javax.persistence.jdbc.password" value="root"/>
                <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
                <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/>
                <!--3.配置jpa实现(hibernate)的配置信息
                    显示sql:hibernate.show_sql   false/true
                    自动创建数据库表:hibernate.hbm2ddl.auto
                            create:程序运行时创建数据库表(如果表已存在,先删除再创建)
                            update:程序运行时创建(如果有表,不会创建表)
                            none:不会创建表
                -->
                <property name="hibernate.show_sql" value="true"/>
                <property name="hibernate.hbm2ddl.auto" value="update"/>
            </properties>
        </persistence-unit>
    </persistence>
    
  3. 配置实体类与数据库表的映射关系

    我们需要配置: 1).实体类与表的映射关系(此pojo与数据库中的那一张表关系映射) @ Entity @ Table(name="cst_customer")name表示数据库中表的名称 2).实体类中属性与表中字段的映射关系 @ Id声明主键的设置 @ GeneratedValue配置主键是生成策略(自动增长) strategy= GenerationType.IDENTITY:自增 Mysql(底层数据库支持的自增长方式对id自增) GenerationType.SEQUENCE:序列 Oracle(底层数据库必须支持序列) GenerationType.TABLE:jpa提供的一种机制,通过一张数据库表的形式帮助我们完成自增 GenerationType.AUTO:有程序自动的帮助我们选择主键生成策略 @ Column(name = "cust_id")数据库中表中字段的名字

   package ctgu.pojo;
   import javax.persistence.*;
   @Entity
   @Table(name="cst_customer")
   public class Customer {
       /**
        * @ Id声明主键的设置
        * @ GeneratedValue配置主键是生成策略(自动增长)
        *              GenerationType.IDENTITY
        * @ Column(name = "cust_id")数据库中表中字段的名字
        */
       @Id
       @GeneratedValue(strategy = GenerationType.IDENTITY)
       @Column(name = "cust_id")
       private Long custId;
       @Column(name = "cust_name")
       private String custName;
       @Column(name = "cust_source")
       private String custSource;
       @Column(name = "cust_industry")
       private String custIndustry;
       @Column(name = "cust_level")
       private String custLevel;
       @Column(name = "cust_address")
       private String custAddress;
       @Column(name = "cust_phone")
       private String custPhone;
   	...set/get方法(略)
   }
   
  1. 测试

    操作:向数据库中添加一个用户。

    Jpa的操作步骤:

    • 1.加载配置文件创建工厂(实体管理器工厂)对象
  • 2.通过实体管理类工厂获取实体管理器

    • 3.获取事务对象,开启事务(重要!)
    • 4.完成增删改查
    • 5.提交事务(如果抛出异常,回滚事务)
    • 6.释放资源
     @Test
        public void saveCustomer(){
           // 1.加载配置文件创建工厂(实体管理器工厂)对象   输入参数:持久化单元名称,在下xml中
            EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
            //2.通过实体管理类工厂获取实体管理器
            EntityManager manager = factory.createEntityManager();
            //3.获取事务对象,开启事务(重要!)
            EntityTransaction transaction = manager.getTransaction();
             //开启事务
            transaction.begin();
            //4.创建对象,完成保存操作
            Customer customer = new Customer();
            customer.setCustName("三峡大学");
            customer.setCustIndustry("大学");
            manager.persist(customer);
        // 5.提交事务
            transaction.commit();
            //6.释放资源
            manager.close();
            //factory.close();
        }
    

    我们发现上述步骤中获取实体管理器是可以简化成工具类的。

    JpaUtils:

    • 解决实体管理器工厂的浪费资源和耗时的问题
    • 通过静态代码块的形式,当程序第一次访问此类时,创建一个公共管理器工厂对象
    • 第一次访问getEntityManager()方法时,首先会执行静态代码块创建一个factory对象,再创建一个EntityManager对象;
    • 第二次访问时,由于静态代码块只会在创建时执行一次,直接返回EntityManager对象
    package ctgu.utils;
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    public class JpaUtils {
        private static EntityManagerFactory factory;
        static {
             factory = Persistence.createEntityManagerFactory("myJpa");
        }
        /**
         * 获取EntityManager对象
         */
        public static EntityManager getEntityManager(){
            return factory.createEntityManager();
        }
    }
    

JPA中的API介绍

上述已经实现了一个基本的保存用户的案例,下面对于JPA中的一些API进行简单的介绍:

  1. Persistence

     EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
    

    主要是用于获取EntityManageFactory对象,通过调用该类的静态方法,形参为配置文件中持久化单元的名称。

  2. EntityManageFactory

     EntityManager manager = factory.createEntityManager();
    

    EntityManageFactory接口主要用于创建EntityManage实例。

  3. EntityManage

     manager.persist(customer);//增
     manager.find(Customer.class, 1L);//查(立即加载)
     manager.getReference(Customer.class, 1L);//查(延迟加载)
     manager.remove(customer);//删
     manager.merge(customer);//改
    

    EntityManager是完成持久化操作的核心对象。实体类作为普通 java对象,只有在调用 EntityManager将其持久化后才会变成持久化对象。EntityManager对象在一组实体类与底层数据源之间进行 O/R 映射的管理。它可以用来管理和更新 Entity Bean, 根椐主键查找 Entity Bean, 还可以通过JPQL语句查询实体。

  4. EntityTransaction

    EntityTransaction是完成事务操作的核心对象,对于EntityTransaction在我们的java代码中承接的功能比较简单

    begin:开启事务 commit:提交事务 rollback:回滚事务

JPA中的增删查改

上述我们已经介绍了向数据库中添加数据,下面介绍JPA中的删除,修改,查询:

查询: 根据id查修客户 find()方法:

  • 参数一:class,查询数据的结果需要包装的实体类型的字节码

  • 参数二:查询的主键的取值 getRefrence() 参数同上

区别:

使用find查询:(立即加载) 1.查询的对象就是当前对象本身 2.在调用find方法的时候,就会发送sql语句查询数据库 使用getReference查询:(延迟加载) 1.获取的对象是一个动态代理对象 2.调用getReference方法不会立即发送sql语句查询数据库当需要调用查询结果对象的时候,才会发送查询的sql语句。什么时候调用,什么时候发送

@Test
    public void findCustomer(){
        //1.获取实体器工厂,获取实体器管理对象
        EntityManager manager = JpaUtils.getEntityManager();
        //2.获取事务对象
        EntityTransaction transaction = manager.getTransaction();
        //开启事务
        transaction.begin();
        //3.执行查询
        Customer customer = manager.find(Customer.class, 1L);//记住添加L,id是Long类型的
        //Customer customer = manager.getReference(Customer.class, 1L);
        System.out.println(customer);
        //4.提交事务
        transaction.commit();
        manager.close();
    }


​ 删除:

​ 删除操作:注意:删除不是直接传入一个id去删除,而是传入一个对象去完成删除操作。remove(Object)

​ 先find该用户,再执行查询。

@Test
    public void deleteCustomer(){
        EntityManager manager = JpaUtils.getEntityManager();
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        Customer customer = manager.find(Customer.class, 1L);
        manager.remove(customer);
        transaction.commit();
        manager.close();
    }

更改: 先将对象查询出来,再调用merge(Object)方法。

@Test
    public void updateCustomer(){
        EntityManager manager = JpaUtils.getEntityManager();
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        Customer customer = manager.find(Customer.class, 2L);
        customer.setCustPhone("123456789");
        manager.merge(customer);
        transaction.commit();
        manager.close();
    }

JPA中的复杂查询

JPQL(Java Persistence Query Language).

SQL:查询的是数据库中的表和表的字段。

JPQL:查询的是实体类和类中的属性。

基于首次在EJB2.0中引入的EJB查询语言(EJB QL),Java持久化查询语言(JPQL)是一种可移植的查询语言,旨在以面向对象表达式语言的表达式,将SQL语法和简单查询语义绑定在一起·使用这种语言编写的查询是可移植的,可以被编译成所有主流数据库服务器上的SQL。其特征与原生SQL语句类似,并且完全面向对象,通过类名和属性访问,而不是表名和表的属性。

  1. 查询所有用户

查询所有对象:SQL:select * from cst_customer

​ JPQL:from ctgu.pojo.Customer from Customer省略包路径也行

注意:JPQL中不能写select * (可以写select count(id))

 @Test
    public void findAllCustomer(){
        //1.获取EntityManager对象
        EntityManager manager = JpaUtils.getEntityManager();
        //2.开启事务
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        //3.查询全部
        String jpql="from Customer";
        //创建Query查询对象,query对象才是执行jpql的对象
        Query query = manager.createQuery(jpql);
        List list = query.getResultList();
        for(Object customer:list){
            System.out.println(customer);
        }
        //4.提交事务
        transaction.commit();
        //5.释放资源
        manager.close();
    }
  1. 排序查询

SQL:SELECT * FROM cst_customer ORDER BY cust_id DESC

JPQL:from Customer ORDER BY custId DESC

 @Test
    public void OrderAllCustomer(){
        //1.获取EntityManager对象
        EntityManager manager = JpaUtils.getEntityManager();
        //2.开启事务
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        //3.查询全部
        String jpql="from Customer ORDER BY custId DESC";
        //创建Query查询对象,query对象才是执行jpql的对象
        Query query = manager.createQuery(jpql);
        List list = query.getResultList();
        for(Object customer:list){
            System.out.println(customer);
        }
        //4.提交事务
        transaction.commit();
        //5.释放资源
        manager.close();
    }
  1. 统计查询总数

    SQL:SELECT COUNT(cust_id) FROM cst_customer

    JPQL:select count(custId) from Customer

     @Test
        public void countCustomer(){
            //1.获取EntityManager对象
            EntityManager manager = JpaUtils.getEntityManager();
            //2.开启事务
            EntityTransaction transaction = manager.getTransaction();
            transaction.begin();
            //3.查询全部
            String jpql="select count(custId) from Customer ";
            //创建Query查询对象,query对象才是执行jpql的对象
            Query query = manager.createQuery(jpql);
            /**
             *  由于返回的是单个值
             *   getSingleResult()得到唯一的结果
             *   getResultList()直接将查询的结果封装在list集合中
             */
            Object result = query.getSingleResult();
            System.out.println("返回的用户总数为:"+result);
            //4.提交事务
            transaction.commit();
            //5.释放资源
            manager.close();
        }
    
  2. 分页查询

    SQL:SELECT * FROM cst_customer LIMIT ?,?

    JPQL:from Customer 再设置分页的参数

     @Test
        public void PageCustomer(){
            //1.获取EntityManager对象
            EntityManager manager = JpaUtils.getEntityManager();
            //2.开启事务
            EntityTransaction transaction = manager.getTransaction();
            transaction.begin();
            //3.查询全部
            String jpql="from Customer ";
            //创建Query查询对象,query对象才是执行jpql的对象
            Query query = manager.createQuery(jpql);
            /**
             * 设置分页参数
             */
            query.setFirstResult(1);
            query.setMaxResults(3);
            List list = query.getResultList();
            for (Object customer:list) {
                System.out.println(customer);
            }
            //4.提交事务
            transaction.commit();
            //5.释放资源
            manager.close();
        }
    
  3. 模糊查询

    SQL:SELECT * FROM cst_customer where cust_name LIKE '%大学%'

    JPQL:FORM Customer where custName like ?

    @Test
        public void chooseCustomer(){
            //1.获取EntityManager对象
            EntityManager manager = JpaUtils.getEntityManager();
            //2.开启事务
            EntityTransaction transaction = manager.getTransaction();
            transaction.begin();
            //3.查询全部
            String jpql=" from Customer where custName like ? ";
            //创建Query查询对象,query对象才是执行jpql的对象
            Query query = manager.createQuery(jpql);
            /**
             * 设置查询条件
             * 第一个参数:占位符的索引位置
             * 第二个参数:取值
             */
            query.setParameter(1,"%大学%");
            List list = query.getResultList();
            for (Object customer:list) {
                System.out.println(customer);
            }
            //4.提交事务
            transaction.commit();
            //5.释放资源
            manager.close();
        }
    

maven坐标

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>ctgu.rxz</groupId>
    <artifactId>jpa-01</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.hibernate.version>5.0.7.Final</project.hibernate.version>
    </properties>

    <dependencies>
        <!-- junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- hibernate对jpa的支持包 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${project.hibernate.version}</version>
        </dependency>

        <!-- c3p0 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>${project.hibernate.version}</version>
        </dependency>

        <!-- log日志 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!-- Mysql and MariaDB -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
    </dependencies>
</project>