JPA学习笔记

1、ORM思想

概述:ORM(Object Relational Mapping),对象关系映射。

主要目的操作实体类对象就等同于操作数据库表。

需要建立两个关系:

  • 建立实体类和数据库表之间的映射
  • 建立实体类属性和数据库表字段之间的映射

不再关注

​ sql语句(自动创建)

实现了ORM思想的框架:mybatis、hibernate

2、JPA规范

概述:Java Persistence API,Java的持久化API。

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kORFSYiJ-1602554400084)(E:\学习啊\学习路线\第七阶段\笔记\截图\Jpa流程.png)]

那么,为什么会有“规范”的出现呢?拿JDBC规范来说,在出现它之前,我们都是跟数据库面对面打交道,但是,市面上有非常多的数据库厂商,每个数据库厂商提供的操作数据库的方式是不同的,对于开发者而言,学习一个新的数据库需要消耗极大的学习成本,那么这个时候,JDBC规范就来了,它要求所有的数据库厂商都去实现这个规范(数据库驱动),而我们开发者只需要知道如何使用这个规范进行编程,并且在项目中导入数据库驱动,就可以达到操作不同数据库的目的。而我们的JPA规范也是如此,起初市面上有很多的ORM框架,但是各个框架的实现方式有很大不同,这给我们学习框架造成了很大的困扰,后来SUN公司就提出了JPA规范,让我们的ORM框架厂商都去实现这套规范,而我们只需要掌握这套规范即可。其实就是面向接口编程,我们不需要知道它的具体实现,只需要调用接口或者抽象类的方法即可。

3、案例说明

创建数据库表

 /*创建客户表*/
    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;

创建maven工程并导入坐标

<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>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.12.1</version>
        </dependency>


        <!-- Mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>

        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

编写Jpa的核心配置文件,需要注意两个点:

1、位置:需要放置在类路径下的META-INF文件夹下

2、命名:必须是persistence.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">
        <!--Jpa的实现方式-->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <properties>
            <!--
            数据库信息:
                用户名: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="123456"/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa"/>
            <!--
            可选配置:配置Jpa实现方(hibernate)的配置信息
                显示sql:false|true
                自动创建数据库表:
                    create: 程序运行时,自动创建表(如果有表,先删除表再创建表)
                    update: 程序运行时,自动创建表(如果有表,则不会创建表)
                    none:   不会创建表
            -->
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="create"/>
        </properties>
    </persistence-unit>
</persistence>

创建实体类

package com.hzp.entity;

import javax.persistence.*;

/**
 * 客户的实体类
 * 配置映射关系:
 *  1、配置实体类和数据库表的映射关系
 * @Entity:声明实体类
 * @Table:配置实体类和表的映射关系
 *  name:数据库表的名称
 *  2、配置实体类属性和数据库表字段的映射关系
 * @Id:声明主键
 * @GeneratedValue:配置主键的生成策略
 *  GenerationType.IDENTITY 自增
 * @Column:配置属性和字段的映射关系
 *  name:字段名称
 */
@Entity
@Table(name = "cst_customer")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "cust_id")
    private Integer 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;//客户联系方式

    public Customer(Integer custId, String custName, String custSource, String custIndustry, String custLevel, String custAddress, String custPhone) {
        this.custId = custId;
        this.custName = custName;
        this.custSource = custSource;
        this.custIndustry = custIndustry;
        this.custLevel = custLevel;
        this.custAddress = custAddress;
        this.custPhone = custPhone;
    }

    public Customer() {
    }

    public Integer getCustId() {
        return custId;
    }

    public void setCustId(Integer custId) {
        this.custId = custId;
    }

    public String getCustName() {
        return custName;
    }

    public void setCustName(String custName) {
        this.custName = custName;
    }

    public String getCustSource() {
        return custSource;
    }

    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }

    public String getCustIndustry() {
        return custIndustry;
    }

    public void setCustIndustry(String custIndustry) {
        this.custIndustry = custIndustry;
    }

    public String getCustLevel() {
        return custLevel;
    }

    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }

    public String getCustAddress() {
        return custAddress;
    }

    public void setCustAddress(String custAddress) {
        this.custAddress = custAddress;
    }

    public String getCustPhone() {
        return custPhone;
    }

    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "custId=" + custId +
                ", custName='" + custName + '\'' +
                ", custSource='" + custSource + '\'' +
                ", custIndustry='" + custIndustry + '\'' +
                ", custLevel='" + custLevel + '\'' +
                ", custAddress='" + custAddress + '\'' +
                ", custPhone='" + custPhone + '\'' +
                '}';
    }
}

测试添加操作

    /**
     * Jpa的操作步骤:
     * 1、加载配置文件,获取实体管理器工厂对象
     * 2、通过实体管理器工厂获取实体管理器
     * 3、获取事务对象,开启事务
     * 4、增删查改
     * 5、提交事务(回滚事务)
     * 6、释放资源
     */
    @Test
    public void testSave(){
        //1、加载配置文件,获取实体管理器工厂对象(参数是持久化单元的名称)
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
        //2、通过实体管理器工厂获取实体管理器
        EntityManager em = factory.createEntityManager();
        //3、获取事务对象,开启事务
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        //4、增删查改
        Customer customer=new Customer();
        customer.setCustName("吴航");
        customer.setCustAddress("江西");
        em.persist(customer);
        //5、提交事务(回滚事务)
        tx.commit();
        //6、释放资源
        em.close();
        factory.close();
    }

控制台输出的sql语句:

Hibernate: drop table if exists cst_customer
Hibernate: create table cst_customer (cust_id integer not null auto_increment, cust_address varchar(255), cust_industry varchar(255), cust_level varchar(255), cust_name varchar(255), cust_phone varchar(255), cust_source varchar(255), primary key (cust_id))
Hibernate: insert into cst_customer (cust_address, cust_industry, cust_level, cust_name, cust_phone, cust_source) values (?, ?, ?, ?, ?, ?)

可以看到,在进行插入之前,会先删除并重新创建表,因为我们前面在配置文件中配置了如下:

<property name="hibernate.hbm2ddl.auto" value="create"/>

4、主键生成策略

我们前面在实体类的custId属性上配置了一个@GeneratedValue注解,该注解用于配置主键的生成策略。该注解有一个strategy属性,这个属性有如下的可选值:

  • GenerationType.IDENTITY:自增,要求数据库底层必须支持自增,比如mysql
  • GenerationType.SEQUENCE:序列,要求数据库底层必须支持序列,如oracle
  • GenerationType.TABLE:jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增
  • GenerationType.AUTO:由程序自动的帮助我们选择主键生成策略

现在我们将strategy修改为GenerationType.TABLE,来测试一下:

控制台输出:

Hibernate: drop table if exists cst_customer
Hibernate: drop table if exists hibernate_sequences
Hibernate: create table cst_customer (cust_id integer not null, cust_address varchar(255), cust_industry varchar(255), cust_level varchar(255), cust_name varchar(255), cust_phone varchar(255), cust_source varchar(255), primary key (cust_id))
Hibernate: create table hibernate_sequences (sequence_name varchar(255) not null, next_val bigint, primary key (sequence_name))

Hibernate: select tbl.next_val from hibernate_sequences tbl where tbl.sequence_name=? for update
Hibernate: insert into hibernate_sequences (sequence_name, next_val) values (?,?)
Hibernate: update hibernate_sequences set next_val=? where next_val=? and sequence_name=?
Hibernate: insert into cst_customer (cust_address, cust_industry, cust_level, cust_name, cust_phone, cust_source, cust_id) values (?, ?, ?, ?, ?, ?, ?)

可以看到,会创建两张表cst_customerhibernate_sequences,可以看到,我们cst_customer的主键不再是自增的了,它的主键id值来源于我们这里的hibernate_sequences表,使用这个表为我们进行主键自增。

然后我们再将strategy修改为GenerationType.AUTO来测试:

控制台输出:

Hibernate: drop table if exists cst_customer
Hibernate: drop table if exists hibernate_sequence
Hibernate: create table cst_customer (cust_id integer not null, cust_address varchar(255), cust_industry varchar(255), cust_level varchar(255), cust_name varchar(255), cust_phone varchar(255), cust_source varchar(255), primary key (cust_id))
Hibernate: create table hibernate_sequence (next_val bigint)
Hibernate: insert into hibernate_sequence values ( 1 )

Hibernate: select next_val as id_val from hibernate_sequence for update
Hibernate: update hibernate_sequence set next_val= ? where next_val=?
Hibernate: insert into cst_customer (cust_address, cust_industry, cust_level, cust_name, cust_phone, cust_source, cust_id) values (?, ?, ?, ?, ?, ?, ?)

可以看到,它也会为我们生成两张表。

5、抽取工具类

/**
 * Jpa工具类
 * 用于解决创建实体管理器工厂对象浪费资源的问题
 */
public class JpaUtil {
    private static EntityManagerFactory factory;
    
    static {
        factory= Persistence.createEntityManagerFactory("myJpa");
    }

    /**
     * 获取实体管理器
     */
    public EntityManager getEntityManager(){
        return factory.createEntityManager();
    }
}

测试工具类

@Test
    public void testSave(){
        //1、加载配置文件,获取实体管理器工厂对象(参数是持久化单元的名称)
//        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
        //2、通过实体管理器工厂获取实体管理器
//        EntityManager em = factory.createEntityManager();
        EntityManager em = JpaUtil.getEntityManager();
        //3、获取事务对象,开启事务
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        //4、增删查改
        Customer customer=new Customer();
        customer.setCustName("吴航");
        customer.setCustAddress("江西");
        em.persist(customer);
        //5、提交事务(回滚事务)
        tx.commit();
        //6、释放资源
        em.close();
//        factory.close();
    }

6、CRUD

根据id查询客户,查询前先将hibernate.hbm2ddl.auto的值修改为update

 @Test
    public void testFind(){
        //1.通过工具类获取实体管理器
        EntityManager em = JpaUtil.getEntityManager();
        //2.创建事务对象,开启事务
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        //3.根据id查询客户
        Customer customer = em.find(Customer.class, 1);
        System.out.println(customer);
        //4.提交事务
        tx.commit();
        //5.释放资源
        em.close();
    }

控制台输出:

Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_address as cust_add2_0_0_, customer0_.cust_industry as cust_ind3_0_0_, customer0_.cust_level as cust_lev4_0_0_, customer0_.cust_name as cust_nam5_0_0_, customer0_.cust_phone as cust_pho6_0_0_, customer0_.cust_source as cust_sou7_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
Customer{custId=1, custName=‘吴航’, custSource=‘null’, custIndustry=‘null’, custLevel=‘null’, custAddress=‘江西’, custPhone=‘null’}

sql语句看起来好像很复杂,其实就是起了俩别名,去掉等价于:select * from cst_customer where cust_id=1

除了通过find查询外,也可以通过getReference方法进行查询

@Test
    public void testReference(){
        //1.通过工具类获取实体管理器
        EntityManager em = JpaUtil.getEntityManager();
        //2.创建事务对象,开启事务
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        //3.根据id查询客户
        Customer customer = em.getReference(Customer.class, 1);
//        System.out.println(customer);
        //4.提交事务
        tx.commit();
        //5.释放资源
        em.close();
    }

find()getReference()在使用和功能上是一样的,区别在于:

  • find()获取的是实体类对象,而getReference()获得的是代理对象。我们可以打断点进行调试。

在这里插入图片描述

在这里插入图片描述

  • find()是立即加载,而getReference()是延迟加载(懒加载),所谓的立即加载是在调用find的时候就会发出sql语句,而懒加载则是在使用结果对象的时候才会发出sql语句,我们可以将输出结果对象的语句注释掉,看看是否会打印sql。

在这里插入图片描述

在这里插入图片描述

删除客户

 /**
     * 删除客户
     */
    @Test
    public void testDelete(){
        //1.获取实体管理器
        EntityManager em = JpaUtil.getEntityManager();
        //2.创建事务对象,开启事务
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        //3.删除操作
        //需要先查询是否存在,然后才删除
        Customer customer = em.find(Customer.class, 1);
        em.remove(customer);
        //4.提交事务
        tx.commit();
        //5.释放资源
        em.close();
}

更新客户

/**
     * 更新客户
     */
    @Test
    public void testUpdate(){
        //1.获取实体管理器
        EntityManager em = JpaUtil.getEntityManager();
        //2.创建事务对象,开启事务
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        //3.删除操作
        //需要先查询是否存在,然后才删除
        Customer customer = em.find(Customer.class, 1);
        em.merge(customer).setCustName("天行者");//修改客户姓名
        //4.提交事务
        tx.commit();
        //5.释放资源
        em.close();
    }

7、JPQL

查询全部

/**
     * 查询全部
     * sql:select * from cst_customer
     * jpql:from com.hzp.entity.Customer
     */
    @Test
    public void testQuery(){
        EntityManager em = JpaUtil.getEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        String jpql="from com.hzp.entity.Customer";//构建jpql语句
        Query query = em.createQuery(jpql);//创建Query对象
        List list = query.getResultList();
        for (Object obj : list) {
            System.out.println(obj);
        }

        tx.commit();
        em.close();
    }

倒序查询

/**
     * 倒序查询:
     * sql:select * from cst_customer order by cust_id desc
     * jpql: from Customer order by custId desc  包名可以省略
     */
    @Test
    public void testOrder(){
        EntityManager em = JpaUtil.getEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        String jpql="from Customer order by custId desc";//构建jpql语句
        Query query = em.createQuery(jpql);//创建Query对象
        List list = query.getResultList();
        for (Object obj : list) {
            System.out.println(obj);
        }

        tx.commit();
        em.close();
    }

统计查询

    /**
     * 统计查询
     * sql:select count(cust_id) from cst_customer
     * jpql:select count(custId) from Customer
     */
    @Test
    public void testCount(){
        EntityManager em = JpaUtil.getEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        String jpql="select count(custId) from Customer";//构建jpql语句
        Query query = em.createQuery(jpql);//创建Query对象
        Object result = query.getSingleResult();
        System.out.println(result);
        tx.commit();
        em.close();
    }

分页查询

/**
     * 分页查询:
     * sql:select * from cst_customer limit ?,?
     * jpql:from Customer
     */
    @Test
    public void testPage(){
        EntityManager em = JpaUtil.getEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        String jpql="from Customer";//构建jpql语句
        Query query = em.createQuery(jpql);//创建Query对象
        query.setFirstResult(0);//设置起始索引
        query.setMaxResults(2);//设置最大结果条数

        List list = query.getResultList();
        for (Object obj : list) {
            System.out.println(obj);
        }

        tx.commit();
        em.close();
    }

条件查询

    /**
     * 条件查询
     * sql:select * from cst_customer where cust_name=?
     * spql:from Customer where custName=?
     */
    @Test
    public void testCondition(){
        EntityManager em = JpaUtil.getEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        String jpql="from Customer where custName like ?";//构建jpql语句
        Query query = em.createQuery(jpql);//创建Query对象
        query.setParameter(1, "天行者%");

        List list = query.getResultList();
        for (Object obj : list) {
            System.out.println(obj);
        }

        tx.commit();
        em.close();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值