JPA 的API

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ilikejj0/article/details/82180698

JPA和Hibernate的关系

JPA 是 hibernate 的一个抽象(就像JDBC和JDBC驱动的关系):
JPA 是规范:JPA 本质上就是一种 ORM 规范,不是ORM 框架 —— 因为 JPA 并未提供 ORM 实现,它只是制订了一些规范,提供了一些编程的 API 接口,但具体实现则由 ORM 厂商提供实现
Hibernate 是实现:Hibernate 除了作为 ORM 框架之外,它也是一种 JPA 实现
从功能上来说, JPA 是 Hibernate 功能的一个子集

使用JPA持久化对象的步骤

A、创建 persistence.xml, 在这个文件中配置持久化单元,JPA 规范要求在类路径的 META-INF 目录下放置persistence.xml,文件的名称是固定的
1、需要指定跟哪个数据库进行交互;
2、需要指定 JPA 使用哪个持久化的框架以及配置该框架的基本属性
3、在里面配置需要持久化的类

B、创建实体类, 使用 annotation 来描述实体类跟数据库表之间的映射关系.

C、使用 JPA API 完成数据增加、删除、修改和查询操作
1、创建 EntityManagerFactory (对应 Hibernate 中的 SessionFactory);
2、创建 EntityManager (对应 Hibernate 中的Session);

<?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="jpa" transaction-type="RESOURCE_LOCAL">

        <!-- 
           配置用什么ORM框架
        1. 实际上配置的是 javax.persistence.spi.PersistenceProvider 接口的实现类
        2. 如果JPA项目中只有一个JPA的实现产品,则可以不配置该节点
         -->
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <!-- 添加持久化类 -->
        <class>com.atguigu.jpa.bean.User</class>
        <properties>
            <!-- 配置数据源信息 -->
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql:///hibernate1"/>
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value="root"/>

            <!-- 配置JPA实现产品的属性,即hibernate的属性 -->
            <property name="hibernate.format_sql" value="true"/><!-- 是否格式化sql语句 -->
            <property name="hibernate.show_sql" value="true"/> <!-- 是否在控制台打印sql语句 -->
            <!-- 生成数据表的策略,有就更新,没有就创建 -->
            <property name="hibernate.hbm2ddl.auto" value="update"/>
        </properties>
    </persistence-unit>
</persistence>

创建第一个JPA项目,并且创建持久化类,以及相关操作链接

EntityManager

在 JPA 规范中, EntityManager 是完成持久化操作的核心对象。实体作为普通 Java 对象,只有在调用 EntityManager 将其持久化后才会变成持久化对象。EntityManager 对象在一组实体类与底层数据源之间进行 O/R 映射的管理。它可以用来管理和更新 Entity Bean, 根椐主键查找 Entity Bean, 还可以通过JPQL语句查询实体。
实体的状态:
新建状态: 新创建的对象,尚未拥有持久性主键。
持久化状态:已经拥有持久性主键并和持久化建立了上下文环境
游离状态:拥有持久化主键,但是没有与持久化建立上下文环境
删除状态: 拥有持久化主键,已经和持久化建立上下文环境,但是从数据库中删除。

EntityManager的方法

find():类似于hibernate的 get()方法
getReference():相当于hibernate的 load()

persist():类似于hibernate的save()使对象由临时状态变为持久化状态。
但是有区别:主键设置了自增,persist()如果再设置主键值,会报错。
remove():类似于hibernate的delete()方法,把对应的记录从数据库删除,该方法只能移除持久化对象,而hibernate还可以移除游离对象。
jpa

User user1 = entityManager.find(User.class, 2);
        entityManager.remove(user1);

hibernate

User user = new User();
        user.setuId(5);
        session.delete(user);

merge()方法:类似于hibernate的save或者update方法、
若传入的是一个临时对象:会创建一个新的对象,把临时对象的值都复制到新的对象中,然后对新的对象进行持久化操作,所以说新的对象有id,而之前的对象没有id。

        User user = new User();
        user.setUserName("源稚生大家长");
        user.setPassword("123456");
        user.setEmail("[email protected]");
        user.setCreateTime(new Date());
        user.setBirth(new Date());
        //进行保存
        User user1 =entityManager.merge(user);
        System.out.println("之前的user:---"+user.getUserId());
        System.out.println("新的user1:---"+user1.getUserId());

之前的user:---null
新的user1:---4

若传入的对象是一个游离对象,即传入的对象有id值。若在EntityManager缓存中没有该对象,若在数据库中也没有对应的记录,那么JPA会创建一个新的对象,然后把当前游离对象的属性复制到新创建的对象中,然后对新创建的对象尽心insert即持久化操作。

        User user = new User();
        user.setUserName("源稚女");
        user.setPassword("123456");
        user.setEmail("[email protected]");
        user.setCreateTime(new Date());
        user.setBirth(new Date());
        user.setUserId(100);
        //进行保存
        User user1 =entityManager.merge(user);
        System.out.println("之前的user:---"+user.getUserId());
        System.out.println("新的user1:---"+user1.getUserId());
之前的user:---null
新的user1:---5

若传入的对象是一个游离对象,即传入的对象有id值。若在EntityManager缓存中没有该对象,在数据库中有对应的记录,那么JPA会查询对应的记录,然后返回对应该记录的一个对象,然后再把游离对象的属性复制到查询出的对象中,最后对查询到的对象进行update操作。

        User user = new User();
        user.setUserName("乌鸦");
        user.setPassword("123456");
        user.setEmail("[email protected]");
        user.setCreateTime(new Date());
        user.setBirth(new Date());
        user.setUserId(5);

        User user1 =entityManager.merge(user);
        System.out.println(user == user1);//false

若传入的对象是一个游离对象,即传入的对象有id值。若在EntityManager缓存中有该对象,那么JPA会把游离对象的属性复制到EntityManager缓存的记录(手工查出来)中,然后EntityManager缓存中的对象进行update操作。但是hibernate中不行,因为hibernate中的session不能同时关联两个id相同的对象。

User user = new User();
        user.setUserName("诺诺");
        user.setPassword("123456");
        user.setEmail("[email protected]");
        user.setCreateTime(new Date());
        user.setBirth(new Date());
        user.setUserId(4);
        User user1 = entityManager.find(User.class, 4);
        entityManager.merge(user);
        System.out.println(user == user1);

映射单项多对一的映射关系:JPA规范规定多的一段维护外键关系

@ManyToOne来映射多对一的映射关系,可以使用其的fetch属性来修改关联属性的加载策略。
@JoinColumn 来映射外键

//orders表中有一列名为user_id,并且类型为int
    @JoinColumn(name="user_id")
    @ManyToOne(fetch=FetchType.LAZY)
    public User getUser() {
        return user;
    }

值为int
外键

默认情况下不是懒加载,默认情况下使用左外连接的方式来获取n的一端的对象和关联的1的一端的对象

//先保存1的一方,后保存n的一方,减少对数据库的操作
        entityManager.persist(user);
        entityManager.persist(order1);
        entityManager.persist(order2);

不能直接删除1的一方,因为有外键关联

映射单项一对多的映射关系

无论如何都会多出update语句,以为在多的一方不会同时插入外键列

    @JoinColumn(name="user_id")
    @OneToMany(fetch=FetchType.EAGER,cascade={CascadeType.REMOVE})
    public Set<Orders> getOrders() {
        return orders;
    }

这样配置,最终还是在多的一方的表中多出一列user_id,并且出现外键关联。

双向一对多

就是在user和orders都进行配置,配置如上所示。
但是默认情况下,如果都配置的话,就是双向维护外键关系,
这种情况下:如果先保存多的一方,再保存1的一方,会多出2条update,因为双方都要维护外键,先保存1的一方,会多出一条update语句。

实际应用中,设置多的一方维护外键,1的一方放弃外键的维护
即在1的一方,设置mappedBy,值为多的一方所设置的对应的属性名称。如果设置了mappedBy,那么这一方就不能使用@JoinColumn。

    @JoinColumn(name="user_id")
    @OneToMany(mappedBy="user")
    public Set<Orders> getOrders() {
        return orders;
    }

    @JoinColumn(name="user_id")
    @ManyToOne(fetch=FetchType.LAZY)
    public User getUser() {
        return user;
    }

一对一关联映射

//在manager方创建外键,unique设置的是唯一约束

    @JoinColumn(name="dept_id",unique=true)
    @OneToOne(fetch=FetchType.LAZY)
    public Department getDept(){
        return dept;
    }

    @OneToOne(mappedBy="dept")
    public Manager getMgr(){
        return mgr;
    }

多对多的关系映射

//这个是Category表
private Set<Item> items = new HashSet<>();
@ManyToMany(mappedBy="categorys")
    public Set<Item> getItems() {
        return items;
    }
//Item表
private Set<Category> categorys = new HashSet<>();
//@JoinTable映射中间表的名字
    //name指向中间表的名字
    //joinColumns映射当前表在中间表的外键,
    //@JoinColumn中name指定当前类在中间表的外键的名字,
    //referencedColumnName指定这个外键列关联哪一列
    //inverseJoinColumns另一个表在中间表的外键的名字,即放弃外键维护的那一个表

    @JoinTable(name="item_category",
            joinColumns={@JoinColumn(name="item_id",referencedColumnName="id")},
            inverseJoinColumns={@JoinColumn(name="cate_id",referencedColumnName="cId")}
            )
    @ManyToMany 
    public Set<Category> getCategorys() {
        return categorys;
    }

JPQL——HelloWorld

JPQL 是一种和 SQL 非常类似的中间性和对象化查询语言,它最终会被编译成针对不同底层数据库的 SQL 查询,从而屏蔽不同数据库的差异。

JPQL语言的语句可以是 select 语句、update 语句或delete语句,它们都通过 Query 接口封装执行

Query接口封装了执行数据库查询的相关方法。调用 EntityManager 的 createQuery、create NamedQuery 及 createNativeQuery 方法可以获得查询对象,进而可调用 Query 接口的相关方法来执行查询操作。

createQuery:使用jqpl语句进行查询
即是直接使用实体类是名字和属性的名字,而不是使用表的名字,和hibernate的使用相同。

String jpql = "FROM User where userId=?";
Query query = entityManager.createQuery(jpql).setParameter(1, 1);
User user = (User) query.getSingleResult();

createNamedQuery:在实体类上加注解方式,进行查询
@NamedQuery(name="testNameQuery",query="FROM User where userId=?")

@NamedQuery(name="testNameQuery",query="FROM User where userId=?")
@Table(name="tb_user")   //为数据库表命名,如果不加,自动为类名
@Entity   //将类标记为实体类,对应数据库的表
public class User {
    }
Query query = entityManager.createNamedQuery("testNameQuery").setParameter(1, 1);
User user = (User) query.getSingleResult();
System.out.println(user);

createNativeQuery :使用sql语句进行查询
但是查询所有的时候,不能使用*,使用的时候,不会强转成我们需要的类型,如果强转会报类转换异常。

String sql = "SELECT user_name FROM tb_user where userId=?";
Query query = entityManager.createNativeQuery(sql).setParameter(1, 1);
Object b = query.getSingleResult();
System.out.println(b);

使用JPQL还可以实现关联查询,分组查询,子查询,以及使用它的内建函数。

实现修改操作

String jpql = "update User set userName=? where userId=?";
Query query = entityManager.createQuery(jpql).setParameter(1,"李嘉图").setParameter(2, 1);
query.executeUpdate();

实现删除操作

String jpql = "delete User where userId=?";
Query query = entityManager.createQuery(jpql).setParameter(1, 12);
query.executeUpdate();

猜你喜欢

转载自blog.csdn.net/ilikejj0/article/details/82180698
JPA