zoukankan      html  css  js  c++  java
  • 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
    
  • 相关阅读:
    什么是序列化
    命令执行漏洞
    sql注入总结
    npm包之merge-descriptors
    Koa路由中间件之koa-router
    TypeScript声明文件(.d.ts)的使用
    TypeScript使用的简单记录
    TypeScript的安装、使用及配置
    Node websocket简单封装
    使用docker-compose配置mysql服务
  • 原文地址:https://www.cnblogs.com/mozq/p/11283615.html
Copyright © 2011-2022 走看看