zoukankan      html  css  js  c++  java
  • JPA学习

    JPA是什么

    JPA (Java Persistence API)Java持久化API。是一套Sun公司Java官方制定的ORM 方案,是规范,是标准 ,sun公司自己并没有实现

     

    关注点:ORM  ,标准 概念 (关键字)

     

    ORM是什么

    ORM(Object Relational Mapping)对象关系映射。

    问:ORM有什么用?

    在操作数据库之前,先把数据表与实体类关联起来。然后通过实体类的对象操作(增删改查)数据库表,这个就是ORM的行为! 

    所以:ORM是一个实现使用对象操作数据库的设计思想!!! 

    通过这句话,我们知道JPA的作用就是通过对象操作数据库的,不用编写sql语句。

    JPA的实现者

    既然我们说JPA是一套标准,意味着,它只是一套实现ORM理论的接口。没有实现的代码。 

    那么我们必须要有具体的实现者才可以完成ORM操作功能的实现! 

    市场上的主流的JPA框架(实现者)有: 

    Hibernate (JBoos)、EclipseTop(Eclipse社区)、OpenJPA (Apache基金会)。 

    其中Hibernate是众多实现者之中,性能最好的。所以,我们本次教学也是选用Hibernate框架作为JPA的主讲框架。 

    提醒:学习一个JPA框架,其他的框架都是一样使用

    JPA的作用是什么(问题)

    JPA是ORM的一套标准,既然JPA为ORM而生,那么JPA的作用就是实现使用对象操作数据库,不用写SQL!!!. 

    问题:数据库是用sql操作的,那用对象操作,由谁来产生SQL? 

    答:JPA实现框架 

    入门示例

    任何框架的学习,都建议从配置流程图开始。所以我们来一起理解JPA的配置流程图。 

    配置流程图

    1. 我们需要一个总配置文件persistence.xml存储框架需要的信息 (注意,文件名不要写错,而且必须放在classpath/META-INF文件夹里面) 

    2. 我们需要一个Persistence持久类对象来读取总配置文件,创建实体管理工厂对象 

    3. 我们需要实体管理工厂获得数据库的操作对象实体管理对象EntityManager。 

    4. 我们通过EntityManager操作数据库之前,必须要先配置表与实体类的映射关系,从而实现使用对象操作数据库!!!

    配置步骤说明 

    第一步:导入包 (不管什么框架,首先要做的事情) 

    第二步:创建一个总配置文件 

    第三步:创建一个JPAUtils获得操作对象EntityManager 

    第四步:创建一个实体类,并且配置好映射注解 

    第五步:在总配置文件加载实体类 

    第六步:测试代码(需求:插入数据到用户表) 

    配置步骤 

     需求:编写一个JPA的项目,插入一条数据到学生信息表。 

    第一步:创建Maven项目

    说明:我们这里是基于hibernate实现的,所以要导入Hibernate的JPA规范包

    --使用maven构建的配置-- 

    <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>cn.zj</groupId>

      <artifactId>jpa-demo01-start</artifactId>

      <version>0.0.1-SNAPSHOT</version>

      <dependencies>

        <!-- hibernate框架 实现JPA 依赖 -->

    <dependency>

        <groupId>org.hibernate</groupId>

        <artifactId>hibernate-entitymanager</artifactId>

        <version>4.3.6.Final</version>

    </dependency>

    -->

    <dependency>

    <groupId>mysql</groupId>

    <artifactId>mysql-connector-java</artifactId>

    <version>5.1.40</version>

    </dependency>

      </dependencies>

    </project>

    第二步创建一个总配置文件

    注意:文件必须放在classpath:/META-INF/persistence.xml 

     

    说明:Eclipse已经支持了JPA框架,所有不需要配置xsd文件,直接使用

    配置信息如下:

    <?xml version="1.0" encoding="UTF-8"?>

    <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd ">

      <persistence-unit name="mysql-jpa">

    <properties> 

    <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" /> 

    <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpa" /> 

    <property name="hibernate.connection.username" value="root" /> 

    <property name="hibernate.connection.password" value="root" /> 

    <!--可选配置--> 

    <!--控制台打印sql语句--> 

    <property name="hibernate.show_sql" value="true" /> 

    <property name="hibernate.format_sql" value="true" /> 

    </properties> 

      </persistence-unit>

    </persistence>

    第三步:封装JPAUtils工具类

    创建一个工具类JPAUtils,获得操作对象(EntityManager) 

    package cn.zj.jpa.util;

    import javax.persistence.EntityManager;

    import javax.persistence.EntityManagerFactory;

    import javax.persistence.Persistence;

    public class JPAUtils {

    //同一个应用中,应该保证只有一个实例工厂。

    public static EntityManagerFactory emf = createEntityManagerFactory();

    //1.获得实体管理工厂

    private static EntityManagerFactory createEntityManagerFactory(){

    EntityManagerFactory emf = Persistence.createEntityManagerFactory("mysql-jpa");

    return emf;

    }

        //2.获得实体管理类对象

    public static EntityManager getEntityManger(){

    EntityManager entityManager = emf.createEntityManager();

    return entityManager;

    }

    }

    第四步创建映射实体类

    创建一个映射的实体类,将JPA的映射注解写在实体类里面。 

    package cn.zj.jpa.entity;

    import javax.persistence.Column;

    import javax.persistence.Entity;

    import javax.persistence.GeneratedValue;

    import javax.persistence.GenerationType;

    import javax.persistence.Id;

    import javax.persistence.Table;

    //1.指定实体类与表名的关系

    //@Entity注解,指定该实体类是一个基于JPA规范的实体类

    @Entity 

    //@Table注解,指定当前实体类关联的表

    @Table(name="tb_student")

    public class Student {

    //@Id注解:声明属性为一个OID属性

    @Id 

    //@GeneratedValue注解,指定主键生成策略

    @GeneratedValue(strategy=GenerationType.IDENTITY)

    //@Column注解,设置属性与数据库字段的关系,如果属性名和表的字段名相同,可以不设置

    @Column(name="stu_id")

    private Long stuId;//BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '学生编号',

    @Column(name="stu_name")

    private String stuName;//VARCHAR(50) NULL DEFAULT NULL COMMENT '学生名字',

    @Column(name="stu_age")

    private Integer stuAge;//INT(11) NULL DEFAULT NULL COMMENT '学生年龄',

    @Column(name="stu_password")

    private String stuPassword;//VARCHAR(50) NULL DEFAULT NULL COMMENT '登录密码',

    public Student() {

    super();

    }

    //补全get、set方法

    }

    第五步:在总配置文件中加载映射实体类

    <?xml version="1.0" encoding="UTF-8"?>

    <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd ">

      <persistence-unit name="mysql-jpa">

      -->

       基于hibernate框架的JPA已经实现了自动载入映射实体类 ,所以不配置也是可以的。建议还是加上配置。如果不写容易忽略加载的实体类有哪些

         -->

        <class>cn.zj.jpa.entity.Student</class>

    <properties> 

    <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" /> 

    <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpa" /> 

    <property name="hibernate.connection.username" value="root" /> 

    <property name="hibernate.connection.password" value="zj" /> 

    <!--可选配置--> 

    <!--控制台打印sql语句--> 

    <property name="hibernate.show_sql" value="true" /> 

    <property name="hibernate.format_sql" value="true" /> 

    </properties> 

      </persistence-unit>

    </persistence>

    第六步:操作实体类保存数据

    创建一个StudentDAOTest类,测试保存一个学生。

    package cn.zj.jpa;

    import javax.persistence.EntityManager;

    import javax.persistence.EntityTransaction;

    import org.junit.Test;

    import cn.zj.jpa.entity.Student;

    import cn.zj.jpa.util.JPAUtils;

    public class StudentDAOTest {

    @Test

    public void persist(){

    //1.获得实体管理类

    EntityManager manager = JPAUtils.getEntityManger();

    //2、获取事物管理器

    EntityTransaction transaction = manager.getTransaction();

    transaction.begin();

    //3、创建实体对象

    Student s=new Student();

    s.setStuName("张三");

    s.setStuAge(18);

    s.setStuPassword("zj");

    //4、保存到数据库

    manager.persist(s);

    //5、提交事物

    transaction.commit();

    //6、关闭资源

    manager.close();

    }

    }

    通过操作实体对象保存数据成功!!!

    使用JPA的好处

    使用JPA,可以直接使用对象操作数据库,由框架根据映射的关系生成SQL。不用开发人员编写。这样做,开发人员就不用编写SQL语句了

    问题:这样有什么好处呢? 

    答:不同的数据库的SQL语法是有差异,如果不需要编写SQL语句。就屏蔽各种数据库SQL的差异。那么,编写的代码就可以一套代码兼容多种数据库!!!! 

    JPA实现CRUD

    修改StudentDAOTest类,测试crud操作

    //通过OID删除

    @Test

    public void remove(){

    //1.获得实体管理类对象

    EntityManager entityManager = JPAUtils.getEntityManger();

    //2.打开事务

    EntityTransaction transaction = entityManager.getTransaction();

    //3.启动事务

    transaction.begin();

    //4.创建数据,删除数据必须使用持久化对象

    Student s=entityManager.find(Student.class, 2L);

    //5.插入

    entityManager.remove(s);;

    //6。提交

    transaction.commit();

    //7.关闭

    entityManager.close();

    }

    //更新

    @Test

    public void merge(){

    //1.获得实体管理类对象

    EntityManager entityManager = JPAUtils.getEntityManger();

    //2.打开事务

    EntityTransaction transaction = entityManager.getTransaction();

    //3.启动事务

    transaction.begin();

    //4.创建数据

    Student s=new Student();

    s.setStuName("李四");

    //更新必须要有一个OID

    s.setStuId(3L);

    //5.更新

    entityManager.merge(s);

    //6。提交

    transaction.commit();

    //7.关闭

    entityManager.close();

    }

    //通过OID获得数据

    @Test

    public void find(){

    //1.获得实体管理类对象

    EntityManager entityManager = JPAUtils.getEntityManger();

    //通过OID查询数据

    Student student = entityManager.find(Student.class, 1L);

    System.out.println(student.getStuName());

    entityManager.close();

    }

    //通过OID获得数据

    @Test

    public void getReference(){

    //1.获得实体管理类对象

    EntityManager entityManager = JPAUtils.getEntityManger();

    /**

    * getReference()和find()方法的区别:

    * getReference基于懒加载机制,即需要使用对象的时候,才执行查询。

     */

    Student student = entityManager.getReference(Student.class, 1L);

    System.out.println(student.getStuName());

    entityManager.close();

    }

    JPA常用 API说明

    映射注解说明

    注解说明

    @Entity声明该实体类是一个JPA标准的实体类

    @Table指定实体类关联的表,注意如果不写表名,默认使用类名对应表名。

    @Column指定实体类属性对应的表字段,如果属性和字段一致,可以不写

    @Id声明属性是一个OID,对应的一定是数据库的主键字段

    @GenerateValue声明属性(Object ID)的主键生成策略

    @SequenceGenerate使用SEQUENCE策略时,用于设置策略的参数

    @TableGenerate使用TABLE主键策略时,用于设置策略的参数

    @JoinTable关联查询时,表与表是多对多的关系时,指定多对多关联表中间表的参数。

    @JoinColumn关联查询时,表与表是一对一、一对多、多对一以及多对多的关系时,声明表关联的外键字段作为连接表的条件。必须配合关联表的注解一起使用 <key>

    @OneToMany关联表注解,表示对应的实体和本类是一对多的关系

    @ManyToOne关联表注解,表示对应的实体和本类是多对一的关系

    @ManyToMany关联表注解,表示对应的实体和本类是多对多的关系

    @OneToOne关联表注解,表示对应的实体和本类是一对一的关系

    JPA常用API说明

    API说明

    Persistence用于读取配置文件,获得实体管理工厂

    EntityManagerFactory用于管理数据库的连接,获得操作对象实体管理类

    EntityManager实体管理类,用于操作数据库表,操作对象

    EntityTransaction用于管理事务。开始,提交,回滚

    TypeQuery用于操作JPQL的查询的

    Query用于操作JPQL的查询接口,执行没有返回数据的JPQL(增删改)

    CriteriaBuilder用户使用标准查询接口 Criteria查询接口

    JPA多表关联查询 

    多个关联查询作用(导航查询):就是实现使用一个实体类对象查询多个表的数据。 

      配置多表联系查询必须有两个步骤; 

    (1)、在实体类里面建立表与表之间的关系。 

    (2)、在实体类配置关联关系,JPA使用注解配置 

     

    多表关联的E-R图如下:

    根据ER图,创建数据库表!!!

    一对多实现(单向)

    需求:通过ID查询一条学生表的记录,同时查询该学生的对应的成绩的信息!

    说明

    如图所示:一个学生可以有多条成绩的记录,一条成绩的记录只属于一个学生,所以学生表与成绩表的关系是一对多的关系。

    所以,通过JPA配置一对多的关系,可以通过学生表对应的实体类对象同时获得两个表的数据。

    配置步骤

    第一步创建项目

    说明:复制入门示例的项目即可。

    第二步:创建单表实体类

    (1)创建Student类

    @Entity 

    @Table(name="tb_student")

    public class Student {

    @Id 

    @GeneratedValue(strategy=GenerationType.IDENTITY)

    @Column(name="stu_id")

    private Long stuId;

    @Column(name="stu_name")

    private String stuName;

    @Column(name="stu_age")

    private Integer stuAge; 

    @Column(name="stu_password")

    private String stuPassword;

    public Student() {

    super();

    }

    //补全get、set方法

    }

    (2)创建Score类

    @Entity

    @Table(name="tb_score")

    public class Score{

    @Id

    @GeneratedValue(strategy=GenerationType.IDENTITY)

    @Column(name="sco_id")

    private Long scoId;  

    @Column(name="sco_subject")

    private String scoSubject;

    @Column(name="sco_score")

    private Float scoScore;

    @Column(name="stu_id")

    private Long stuId;

    public Score() {

    super();

    }

    // 补全getset方法

    }

    第三步:配置一对多关联关系

    说明:通过@OneToMany注解配置。

    修改Student类,配置一对多关系。

    /**

     * 单向一对对,应该有学生来维护关系

     *

     * 一个学生对应多个成绩,一对多关系

     * 多个成绩我们使用list封装起来

     *

     * JPA 使用 @OneToMany 映射一对多

     * fetch : 抓取策略

     * FetchType.LAZY 懒加载,默认 (只有关联对象在用到的时候才会去发送新的sql,默认关联对象不会查询)

     * 会多生成sql语句 :N+1

     * FetchType.EAGER 迫切查询 (多表连接查询,只会发送一条sql语句)

     * @JoinColumn 设置两张表之间外键列

     */

    @OneToMany(fetch=FetchType.EAGER)

    @JoinColumn(name="stu_id")

    private List<Score> scores;

    public void setScores(List<Score> scores) {

    this.scores = scores;

    }

    第四步:测试一对多查询

    @Test

    public void testOne2Many(){

    //1.获得实体管理类

    EntityManager manager = JPAUtils.getEntityManger();

    Student student = manager.find(Student.class, 1L);

    System.out.println("学生id:"+student.getStuId()+",学生姓名:"+student.getStuName());

    List<Score> scores = student.getScores();

    for (Score score : scores) {

    System.out.println("科目:"+score.getScoSubject()+",分数:"+score.getScoScore());

    }

    //6、关闭资源

    manager.close();

    }

    查询结果:

    一对多关联查询成功!!!

    多对一实现(单向)

    说明

    需求:通过ID查询一条成绩表的记录,同时查询该成绩的对应的学生的信息! 

    如图所示:成绩表里面,每一条记录只能对应一个学生,但是学生编号不是唯一的。所以成绩表里面的多条数据可以对应一个学生,所以我们称多对一的关系。

    配置步骤

    第一步创建项目

    复制一对多示例项目即可。

    第二步:创建单表实体类

    修改Student类,去掉一对多配置即可。

    第三步:配置多对一关联关系

    修改Score类,配置多对一关系

    @Entity

    @Table(name="tb_score")

    public class Score{

    @Id

    @GeneratedValue(strategy=GenerationType.IDENTITY)

    @Column(name="sco_id")

    private Long scoId;  

    @Column(name="sco_subject")

    private String scoSubject;

    @Column(name="sco_score")

    private Float scoScore;

    /**

     * jpa的多对一,关联关系中指定的外键  和 关联表的属性有冲突  

    *解决的方案:去掉关联表中外键对应的属性

    /*@Column(name="stu_id")

    private Long stuId;

    public Long getStuId() {

    return stuId;

    }

    public void setStuId(Long stuId) {

    this.stuId = stuId;

    }

    */

    /**

    * 1、分数和学生信息是多对一的关系

    * 2、只需要一个学生的实体来引用学生的信息

     */

    @ManyToOne

    @JoinColumn(name="stu_id")

    private Student student;

    public Student getStudent() {

    return student;

    }

    public void setStudent(Student student) {

    this.student = student;

    }

    //补全get、set方法

    }

    第四步:测试

    @Test

    public void testMany2One(){

    //1.获得实体管理类

    EntityManager manager = JPAUtils.getEntityManger();

    Score score = manager.find(Score.class, 1L);

    System.out.println("科目:"+score.getScoSubject()+",分数:"+score.getScoScore());

    Student student = score.getStudent();

    System.out.println("学生id:"+student.getStuId()+",学生姓名:"+student.getStuName());

    //6、关闭资源

    manager.close();

    }



    作者:深拥_66e2
    链接:https://www.jianshu.com/p/6d38a6c561f8
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    iOS使用Charles(青花瓷)抓包并篡改返回数据图文详解(转)
    iOS 9 添加白名单
    iOS 中字体的应用(转)
    iOS 后台操作的开发(转)
    iOS 知识点大总结(转)
    在Xcode中找中文字符串(正则表达式)
    block 使用时的注意点(转)
    xcode armv6 armv7 armv7s arm64 (转)
    使用Android studio过程中发现的几个解决R变红的办法
    折腾了一晚上的“equals”和“==”
  • 原文地址:https://www.cnblogs.com/shuai7boy/p/12035529.html
Copyright © 2011-2022 走看看