JPA 基本使用

ORM简介

对象关系映射(Object Relational Mapping,简称ORM),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。

实现ORM思想的框架:Mybatis Hibernate

ORM优点

ORM框架自动实现Entity实体的属性与关系型数据库字段的映射。CRUD的工作则可以交给ORM来自动生成代码方式实现。隐藏了数据访问细节,“封闭”的通用数据库交互,他使得我们的通用数据库交互变得简单易行,并且完全不用考虑SQL语句。大大提高我们开发效率, 这样一来也减少我们维护一个复杂 缺乏灵活性数据访问层的成本。

JPA简介

JPA是Java Persistence API的简称,中文名Java持久层API,内部是由一系列接口和抽象类构成。JDK通过注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。Sun引入新的JPA规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。

依赖配置

        <!-- 集成c3p0连接池到Hibernate ORM -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>5.4.2.Final</version>
        </dependency>

        <!-- hibernate对jpa的支持包 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.0.7.Final</version>
        </dependency>

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

JPA核心配置文件

1. 位置:META-INF 的文件夹下(resources目录下)
2. 命名:persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">  <!-- 导入约束 -->

    <!-- transaction-type:
        JPA:分布式事务管理
        RESOURCE_LOCAL:本地事务管理 -->
    <persistence-unit name="myjpa" transaction-type="RESOURCE_LOCAL">
        <!--jpa实现-->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <!--数据库信息-->
        <properties>
            <property name="javax.persistence.jdbc.user" value="root"></property>
            <property name="javax.persistence.jdbc.password" value="root"></property>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"></property>
            <property name="javax.persistence.jdbc.url"
                      value="jdbc:mysql://localhost:3306/littledonkey?serverTimezone=GMT%2B8&useSSL=false"></property>
                      
            <!--jpa实现方的配置-->
            <!--显示sql,打印到控制台-->
            <property name="hibernate.show_sql" value="true"></property>
            <!--自动创建数据库表-->
            <!--配置jpa实现方(hibernate)的配置信息
                显示sql              :   false|true
                自动创建数据库表      :  hibernate.hbm2ddl.auto
                    create      : 程序运行时创建数据库表(如果有表,先删除表再创建)
                    update      :程序运行时创建表(如果有表,不会创建表)
                    none        :不会创建表-->
            <property name="hibernate.hbm2ddl.auto" value="update"></property>
        </properties>
    </persistence-unit>
</persistence>

主从表

一对多:一是主表
多对多:关系维护方是主表

实体类对象(配置对象和表的映射关系)(一对多)

/**
 * 老板
 */
@Entity
@Table(name = "boss")   //对应表名
public class Boss {

    /**
     * @Id:声明主键的配置
     * @GeneratedValue:配置主键的生成策略 strategy
     *      GenerationType.IDENTITY :自增(底层数据库需支持自动增长,对id自增)
     *
     *      JPA提供的四种标准用法为TABLE,SEQUENCE,IDENTITY,AUTO. 
     *          TABLE:jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增。 
     *          SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。 (oracle)
     *          IDENTITY:主键由数据库自动生成(主要是自动增长型) (mysql)
     *          AUTO:由程序自动的帮助我们选择主键生成策略。
     *
     * @Column:配置属性和字段的映射关系 
     *      name:数据库表中字段的名称
     */

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "boss_id")
    private Long bossId;
    @Column(name = "boss_name")
    private String bossName;

    /**
     * 配置外键(外键引用的那个列在主表中必须是主键列或者唯一列。外键设在从表('多'的一方))
     * 
     * 使用注解的形式配置多表关系
     *            1.声明关系
     *                @OneToMany : 配置一对多关系
     *                    targetEntity :对方对象的字节码对象
     *            2.配置外键
     *                @JoinColumn : 配置外键
     *                    name:从表(多的一方)外键字段名称(不设置name的值,则在默认情况下,name=从表名称+“_”+从表主键的字段名)
     *                    referencedColumnName:主表的主键字段名称
     *                    unique:是否唯一。默认值不唯一
     *                    nullable:是否允许为空。默认值允许。
     *                    insertable:是否允许插入。默认值允许。
     *                    updatable:是否允许更新。默认值允许。
     *                    columnDefinition:列的定义信息。
     *
     * 在一的一方添加了外键了配置,所以对于boss而言,也具备了维护外键的作用
     *
     *
     * @OneToMany:
     *     作用:建立一对多的关系映射
     *     属性:
     *     	targetEntityClass:指定多的多方的类的字节码
     *     	mappedBy:指定从表实体类中配置外键(多表关系)的属性名称。(用于放弃维护权)
     *     	cascade:指定要使用的级联操作
     *     	fetch:指定是否采用延迟加载
     *              EAGER   :立即加载
     *              LAZY    :延迟加载
     *     	orphanRemoval:是否使用孤儿删除
     */

    //@OneToMany(targetEntity = Customer.class,cascade = CascadeType.ALL)
    //@JoinColumn(name = "cus_boss_id",referencedColumnName ="boss_id" )
    @OneToMany(mappedBy = "myBoss",cascade = CascadeType.ALL)     //放弃维护权
    private Set<Customer> customers=new HashSet<>();
}


/**
 * 顾客
 */
@Entity
@Table(name = "customer")
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "cus_id")
    private Long cusId;     //(主键)
    @Column(name = "cus_name")
    private String cusName;

    /**
     * 配置顾客到老板的多对一关系
     *     使用注解的形式配置多对一关系
     *      1.配置表关系
     *          @ManyToOne : 配置多对一关系
     *              targetEntity:对方的实体类字节码
     *      2.配置外键
     *
     * 配置外键的过程,配置到了多的一方,就会在多的一方维护外键
     *
     */
    @ManyToOne(targetEntity = Boss.class,fetch = FetchType.LAZY)
    @JoinColumn(name = "cus_boss_id",referencedColumnName = "boss_id")
    private Boss myBoss;
}

实体类对象(配置对象和表的映射关系)(多对多)

/**
 * 多对多
 */
public class User {

    @ManyToMany(targetEntity = Role.class)
    @JoinTable(name = "user_role",     //中间表名称
               joinColumns ={ @JoinColumn(name = "sys_user_id",referencedColumnName="user_id") },     //当前对象在中间表的外键
               inverseJoinColumns = { @JoinColumn(name = "sys_role_id",referencedColumnName="role_id") } )     //对方对象在中间表的外键
    1、关系维护端,负责多对多关系的绑定和解除
    2、@JoinTable注解的name属性指定关联表的名字
    3、joinColumns指定外键的名字,关联到关系维护端(User)
    4、inverseJoinColumns指定外键的名字,要关联的关系被维护端(role)
    5、其实可以不使用@JoinTable注解,默认生成的关联表名称为主表表名+下划线+从表表名,
        即表名为user_role
        关联到主表的外键名:主表名+下划线+主表中的主键列名,即user_user_id
        关联到从表的外键名:从表名+下划线+从表的主键列名,即role_role_id
        主表就是关系维护端(User)对应的表,从表就是关系被维护端对应的表
    private Set<Role> myRoles;
}

/**
 * 放弃维护权:@ManyToMany(mappedBy = "myRole",cascade = CascadeType.ALL)
 * 注:添加在放弃维护权的一方,mappedBy引用维护权方配置外键(多对多关系)的属性名称。
 */
class test {
    public void test(){
        User user = new User();
        Role role = new Role();
        /**
         * 配置用户到角色的关系,可以对中间表的数据进行维护
         *
         * 不能两个表都对中间表进行维护,否则会主键重复,需要一方放弃维护权
         */
        user.getRoles().add(role);

        //先保存主表,再保存从表
        userDao.save(user);
        roleDao.save(role);
    }
}

/**
 * 级联操作:cascade = CascadeType.ALL(在操作主体的实体类(user)上配置)
 */
class test {
    public void test(){
        User user = new User();
        Role role = new Role();
        user.getRoles().add(role);

        userDao.save(user);
    }
}

使用步骤

    public void test() {

        /**
         * Persistence:用于加载配置文件,创建实体管理器工厂
         *
         * EntityManagerFactory:用于创建实体管理器(创建过程比较浪费资源)
         *      特点:线程安全的对象
         *      解决创建过程耗时问题:静态代码块创建公共对象 
         *
         * EntityManager:获取事务,以及持久化数据库的操作
         *
         * 方法说明:
         * 	getTransaction : 获取事务对象
         * 	persist : 保存操作
         * 	merge : 更新操作
         * 	remove : 删除操作
         * 	find/getReference : 根据id查询
         */
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("myjpa");
        EntityManager entityManager = emf.createEntityManager();
        EntityTransaction et = entityManager.getTransaction();
        et.begin();
        Customer customer = new Customer();
        customer.setCustName("小红");
        customer.setCustAddress("北京");
        entityManager.persist(customer);
        et.commit();
        entityManager.close();
        emf.close();
    }

基本语法

    简单查询

    /**
     * find : 根据id查询数据
     *       class:查询数据的结果需要包装的实体类类型的字节码
     *       id:查询的主键的取值
     *       entityManager.find(Customer.class, 1l)
     *
     *
     * getReference方法(延迟加载(懒加载))
     *        1.获取的对象是一个动态代理对象
     *        2.调用getReference方法不会立即发送sql语句查询数据库
     *          当调用查询结果对象的时候,才会发送查询的sql语句:什么时候用,什么时候发送sql语句查询数据库

     * 调用remove方法完成删除操作
     *         entityManager.remove(customer);
     *
     * 更新操作
     *         merge(customer);
     *
     * 保存操作 : persist
     */


    复杂查询(jpql:查询语句写实体类与实体类属性)(sql:写表与表的字段)

    /**查询全部
     *          创建query对象
     * 			String jpql = "from Customer";
     * 			Query query = em.createQuery(jpql);
     * 			查询并得到返回结果,得到集合返回类型
     * 			List list = query.getResultList();
     *
     * 分页查询
     *          创建query对象
     * 			String jpql = "from Customer";
     * 			Query query = em.createQuery(jpql);
     * 			//起始索引
     * 			query.setFirstResult(0);
     * 			//每页显示条数
     * 			query.setMaxResults(2);
     * 			//查询并得到返回结果,得到集合返回类型
     * 			List list = query.getResultList();
     *
     * 条件查询
     *          创建query对象
     * 			String jpql = "from Customer where custName like ? ";
     * 			Query query = em.createQuery(jpql);
     * 			//对占位符赋值,从1开始
     * 			query.setParameter(1, "传智播客%");   //以传智播客开头
     * 			//查询并得到返回结果
     * 			Object object = query.getSingleResult();
     *
     * 排序查询: 倒序查询全部客户(根据id倒序)
     *          sql:SELECT * FROM customer ORDER BY cust_id DESC
     *          jpql:from Customer order by custId desc
     *
     * 统计查询
     *          String jpql = "select count(custId) from Customer";
     * 			Query query = em.createQuery(jpql);
     * 			// 2.查询并得到返回结果
     * 			Object count = query.getSingleResult();
     */
原文地址:https://www.cnblogs.com/loveer/p/11379473.html