JPA 基础

JPA 基础

数据库驱动 ==> JDBC 规范 ==> ORM 框架 ==> JPA 规范 ==> spring-data-jpa

ORM 思想

JPA 的使用步骤

jpa 依赖

<properties>
    <project.hibernate.version>5.4.2.Final</project.hibernate.version>
</properties>

<!-- 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>

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

jpa 的持久化配置

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
    <!-- 持久化单元 -->
    <persistence-unit name="myJPA" transaction-type="RESOURCE_LOCAL">
        <!-- JPA 的实现者 -->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

        <properties>
            <!-- 数据库信息
                    驱动        javax.persistence.jdbc.driver
                    数据库地址   javax.persistence.jdbc.url
                    用户名    javax.persistence.jdbc.user
                    密码     javax.persistence.jdbc.password
             -->
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa_db" />
            <property name="javax.persistence.jdbc.user" value="root" />
            <property name="javax.persistence.jdbc.password" value="root" />

            <!-- jpa 实现者的配置
                    显示 sql :   hibernate.show_sql
                    格式化 sql : hibernate.format_sql
                    创建表: hibernate.hbm2ddl.auto 库必须存在,hibernate 不会自动创建库
                        create: 运行时创建,有则先删除再创建
                        update: 运行时创建,有则不创建
                        none:   不创建
            -->
            <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>

实体类

package com.mozq.jpa.domain;

import org.hibernate.annotations.GeneratorType;

import javax.persistence.*;

@Entity
@Table
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long custId;
    @Column
    private String custName;
    @Column
    private String custSource;
    @Column
    private String custLevel;
    @Column
    private String custIndustry;
    @Column
    private String custPhone;
    @Column
    private String custAddress;
    //省略构造器和 get/set
}

使用 jpa 的 API 进行操作

JPA实体的四种状态 https://www.jianshu.com/p/636954880af8

JPA中的实体对象拥有四种状态:

  • 瞬时状态(transient)
  • 持久状态(persistent)
  • 游离状态(detached)
  • 删除状态 (deleted)

瞬时状态

瞬时状态的实体就是一个普通的java对象,和持久化上下文无关联,数据库中也没有数据与之对应。

托管状态

使用 EntityManager 进行 find 或者 persist 操作返回的对象即处于托管状态,此时该对象已经处于持久化上下文中,因此任何对于该实体的更新都会同步到数据库中。

游离状态

当事务提交后,处于托管状态的对象就转变为了游离状态。此时该对象已经不处于持久化上下文中,因此任何对于该对象的修改都不会同步到数据库中。但是数据库中有这个对象对应的记录。

删除状态

当调用EntityManger对实体进行delete后,该实体对象就处于删除状态。其本质也就是一个瞬时状态的对象。

持久:处于持久的对象被 EntityManager 管理,当事务被提交时,则对持久对象的任何修改都将同步到数据库中。

public interface EntityManager {
    /* 
        瞬时对象 
        游离对象将报异常 
    */
    void persist(Object var1); // 对象持久化,交给 EntityManager 管理。数据库中必须不存在。瞬时 ==> 持久
    <T> T merge(T var1);// 根据 id 是否存在,插入新对象或更新现有对象。瞬时 ==> 持久 / 游离 ==> 持久
    
    void remove(Object var1);
    <T> T find(Class<T> entityClass, Object id);// 立即加载,返回真实对象
    <T> T getReference(Class<T> entityClass, Object id);// 延迟加载,返回代理对象
    
    void flush();
    /* obj 必须是受管对象,用于将数据库数据同步到受管对象,如果是其他状态的对象将抛异常。*/
    void refresh(Object var1); 
    void clear();
    void detach(Object var1);
    
    void close();//关闭
    EntityTransaction getTransaction();// 获取事务对象
}
# void refresh(Object var1);
java.lang.IllegalArgumentException: Entity not managed
# persist 方法异常
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.mozq.jpa.domain.Customer

Customer customer = new Customer();
customer.setCustId(1L);
customer.setCustName("刘备");
em.persist(customer);//此时数据库中存在 1L 记录,报错。
@Test
public void testSave(){
    // Persistence 创建实体类管理器工厂
    EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJPA");
    // 实体类管理器
    EntityManager em = factory.createEntityManager();
    // 事务对象
    EntityTransaction tx = em.getTransaction();
    tx.begin();

    // CRUD
    Customer customer = new Customer();
    customer.setCustName("刘备");

    em.persist(customer); // 保存

    tx.commit();
    // 释放资源
    em.close();
    factory.close();
}

JPQL 查询

// 查询全部
Query query = em.createQuery("from Customer");
List resultList = query.getResultList();
System.out.println(resultList);
// 排序
Query query = em.createQuery("from Customer order by custAddress desc ,custName asc, custId");
List resultList = query.getResultList();
/*
    order by
        customer0_.custAddress desc,
        customer0_.custName asc,
        customer0_.custId
*/
// 分页
Query query = em.createQuery("from Customer order by custId");
query.setFirstResult(2);
query.setMaxResults(3);
/*
  order by
        customer0_.custId limit ?, ?
*/

Hibernate 主键生成策略和创建表策略

public enum GenerationType {
    TABLE,
    SEQUENCE,
    IDENTITY,
    AUTO;

    private GenerationType() {
    }
}
hibernate.hbm2ddl.auto create/update/none
# <property name="hibernate.hbm2ddl.auto" value="create" /> # 先删除表,再创建表
# @GeneratedValue(strategy = GenerationType.IDENTITY)
drop table if exists Customer
create table Customer (
    custId bigint not null auto_increment, # 使用自增主键,生成的 sql 不会有主键字段。需要数据库支持自增。
    custAddress varchar(255),
    custIndustry varchar(255),
    custLevel varchar(255),
    custName varchar(255),
    custPhone varchar(255),
    custSource varchar(255),
    primary key (custId)
) engine=InnoDB
insert 
into
    Customer
    (custAddress, custIndustry, custLevel, custName, custPhone, custSource) 
values
    (?, ?, ?, ?, ?, ?)
# <property name="hibernate.hbm2ddl.auto" value="update" />
# @GeneratedValue(strategy = GenerationType.IDENTITY) # 使用自增主键,生成的 sql 不会有主键字段。需要数据库支持自增。
    create table Customer ( # 如果表不存在则会发送创建表的语句。
        custId bigint not null auto_increment,
        custAddress varchar(255),
        custIndustry varchar(255),
        custLevel varchar(255),
        custName varchar(255),
        custPhone varchar(255),
        custSource varchar(255),
        primary key (custId)
    ) engine=InnoDB
    insert 
    into
        Customer
        (custAddress, custIndustry, custLevel, custName, custPhone, custSource) 
    values
        (?, ?, ?, ?, ?, ?)

GenerationType.AUTO + create

drop table if exists Customer
drop table if exists hibernate_sequence

create table Customer (
    custId bigint not null,
    custAddress varchar(255),
    custIndustry varchar(255),
    custLevel varchar(255),
    custName varchar(255),
    custPhone varchar(255),
    custSource varchar(255),
    primary key (custId)
) engine=InnoDB

create table hibernate_sequence (
    next_val bigint
) engine=InnoDB

insert into hibernate_sequence values ( 1 )

select
        next_val as id_val 
    from
        hibernate_sequence for update 锁
        
update
    hibernate_sequence 
set
    next_val= ? 
where
   next_val=?

insert into
    Customer
        (custAddress, custIndustry, custLevel, custName, custPhone, custSource, custId) 
    values
        (?, ?, ?, ?, ?, ?, ?)

JPA

Caused by: org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.mozq.jpa.domain.Customer
上一篇:MySQL一一sql的视图、索引、约束


下一篇:PHP审计之in_array函数缺陷绕过