JPA-学习

JPA基本步骤:

关于课程实例:

1 数据表中 实体关系分析

image-20231230123142000

理清思路:

  • 作者 和 昵称之间 一对一 的关系 一个作者只有一个昵称
  • 作者 和 文章之间 一对多 的关系 一个作者可以有多个文章 作者也可以没有文章
  • 文章 和 专题之间 多对多 的关系 文章可以被多个专题收录 一个专题也可以收录多个文章
  • 文章 和 评论之间 一对多 的关系 文章可以有很多评论 也可以没有评论

包含 :

  • 作者更新、注册、删除
  • 文章新增、更新、删除
  • 评论文章
  • 专题新增、更新、删除
  • 专题收录

2 JPA使用步骤:

在springboot框架中使用JPA 的步骤

2.1、 SpringBoot 框架构建

2.2 、引入JPA 模块

2.3、 在springboot中配置JPA 也就是在 application.properties 或者 application.yaml 中配置

2.4、 定义实体类

2.5、 实现Repository 接口

开始:

2.1、 SpringBoot 框架构建

image-20231230124830173

2.2 、引入JPA 模块

image-20231230125116603

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.xxz</groupId>
    <artifactId>JPA-xxz</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>JPA-xxz</name>
    <description>JPA-xxz</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>3.2.1</version>
            </plugin>
        </plugins>
    </build>
</project>

image-20231230125723982

这个就包含了JPA 要使用的三个模块 引入这个模块我们在springboot中就可以使用JPA了

2.3、 在springboot中配置JPA

这只是表结构不用自己去创建 但是数据库 需要自己去创建。

也就是在 application.properties 或者 application.yaml 中配置

这里用 **application.yaml ** 基本用 update

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/spring-boot-jpa?useUnicode=ture&characterEncoding=utf-8
    username: root
    password: xxxx

  jpa:
    hibernate:
      ddl-auto: update      # 数据库操作表结构的方式  通常是 update
    show-sql: true       # 控制台输出sql语句  

image-20231230132532943

image-20231230132621889

jpa.hibernate.ddl-auto:

  • update : 第一次加载Hibernate 、 会根据我们的 model 类创建新,以后再加载 Hibernate 时,会根据model 类自动更新表结构。**注意:**即使model 类结构发生了变化,表结构不会删除以前的行或列 只会新增一个列。
  • create : 每次加载 Hibernate 时 会根据model 类创建新的表 注意:表数据的丢失。 慎用!!!!这个属性

​ 这玩意要是部署到真实环境中 你有可能将数据库搞丢!!!!

  • create-drop : 加载 Hibernate 时 会根据 model 类创建一个新的表 sessionFactory 销毁的时候,把对应表给删除掉,相当于临时表。
  • none : 不使用这个属性
  • validate : 加载 Hibernate 时根据 model 类 来验证我的表结构,不会创建新的表,或者更新表。
2.4、 定义实体类

以作者开始

image-20231230140112537

image-20231230134547591

类创建好后来添加一些属性

package com.xxz.domain;
import java.util.Date;
/**
 * @author xxz
 * @version 1.0
 * @Created on: 2023-12-30 13:44
 * @Description: 作者实体类
 */
public class Author {
    // 因为 这个实体类模型 是对应你数据库表的 所以我们需要一个主键
    private Long id;
    // 因为流程图上给作者这个实体类上规划了一个属性  昵称
    private String nickName;
    //自己可以添加其他自己想添加的属性
    private String phone;  //手机号
    private Date signDate;  // 创建时间
}

属性添加好后 这个实体类还不是 数据模型类 model类

还需增加

实体类标识注解 @Entity

主键标识注解 @Id

主键的生成规则注解 @GeneratedValue

@Entity @Id @GeneratedValue

package com.xxz.domain;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import java.util.Date;
@Entity   //这个注解是将 实体类 标记成 model数据模型类  不加不会创建表
public class Author {
    // 因为 这个实体类模型 是对应你数据库表的 所以我们需要一个主键
    @Id   // @id 标识 主键
    @GeneratedValue  //增加主键的生成规则注解
    private Long id;
    private String nickName;
    private String phone; 
    private Date signDate;  
}

然后必须增加空构造 和 get set方法

快捷键 Alt + Ins

增加空构造:

image-20231230135840079

package com.xxz.domain;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import java.util.Date;
/**
 * @author xxz
 * @version 1.0
 * @Created on: 2023-12-30 13:44
 * @Description: 作者实体类
 */

 注意    会将我们这里的驼峰命名的实体  自动装换为  下划线命名  存进数据表中的字段

@Entity   //这个注解是将 实体类 标记成 model数据模型类  不加不会创建表
public class Author {
    // 因为 这个实体类模型 是对应你数据库表的 所以我们需要一个主键
    @Id   // @id 标识 主键
    @GeneratedValue  //增加主键的生成规则注解
    private Long id;
    // 因为流程图上给作者这个实体类上规划了一个属性  昵称
    private String nickName;
    //自己可以添加
    private String phone;  //手机号
    private Date signDate;  // 创建时间

    public Author() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public Date getSignDate() {
        return signDate;
    }

    public void setSignDate(Date signDate) {
        this.signDate = signDate;
    }
}

到此 我们构建实体类模型 结束!!!

这样 实体类 就会在数据库中新建一个表 可我们如何操作这个表呢 就需要 实现 Repository 接口

2.5、 实现 Repository 接口

创建 AuthorRepostiory 接口后 需要继承 JpaRepository 这是最顶级也是功能最全的 接口 JpaRepository

并且需要传递两个参数

一 是泛型 这个接口对应那个实体类类型

二 是实体类 主键类型

这样就可以使用jpa 进行操作了

image-20231230163131586

package com.xxz.domain;
import org.springframework.data.jpa.repository.JpaRepository;

public interface AuthorRepostiory extends JpaRepository<Author,Long> {

}

开始测试

启动主启动类

image-20231230164041934

这个时候去数据库看 这个 表生成没有

发现表生成了:

image-20231230164211343

image-20231230164246670

测试保存信息:

构建保存信息的 实体对象:

package com.xxz;
import com.xxz.domain.Author;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Date;

@SpringBootTest
public class JpaXxzApplicationTests {
    // 测试保存信息
    //构建保存信息的 实体对象
   public void saveAuthorTest(){
       Author author = new Author();
       author.setNickName("xxz");
       author.setPhone("12312312312");
       author.setSignDate(new Date());
      // 到此 实体对象构建好了  下来使用 自定义的接口来调用这个实体对象
   }
}

image-20231230184153173

要使用 接口 先注入接口 也就是上面的 AuthorRepostiory

image-20231230184406235

发现 数据存入成功~~

image-20231230185225254

定义实体类:

通常在企业开发中有两个做法:

1 先创建数据库表,然后再根据表来创建实体类。这是传统的数据库建模思想。 也就是 mybatis形式

2 先编写实体类,然后再生成数据库表。这种采用领域建模思想,更加OOP。建议采用。

关于注解:

主要通过注解来定义实体类

1 @Entity

应用于实体类,表明该实体类被JPA管理,将映射到指定的数据库表。

2 @Table

应用于实体类,通过 **name**属性指定对应该实体类映射表的名字。就是用于自己指定表的名字

3 @Id

应用于实体类的属性或者属性对应的**getter**方法,表示该属性映射为数据库表的主键。

image-20231230193733286

4 @GerneratedValue

于@ld一同使用,表示主键的生成策略,通过**strategy**属性指定。不指定就是默认 auto

image-20231230193749661

JPA提供的生成策略有

  • AUTO 一一 JPA自动选择合适的策略,是默认选项。

  • IDENTITY一一 采用数据库ID自增长的方式来生成主键值,Oracle不支持这种方式。

  • SEQUENCE 一一 通过序列生主键,通过**@SequenceGenerator**注解指定序列名,MySql不支持这种方式。

  • TABLE 一一 采用表生成方式来生成主键值,这种方式比较通用,但是效率低。

5 @ Basic

应用于属性,表示该属性映射到数据库表,

@Entity 标注的实体类的所有属性,默认即为

@Basic 有两个属性:

​ 1、 fetch : 属性的读取策略,有 EAGERLAZY 两种取, 分表标识主动抓取和延迟抓取【懒加载】默认为

EAGER

​ 2、 optonal: 表示该属性是否允许为 null, 默认值为 true

@Basic(fetch =FetchType.LAZY)标注某属性时,表示只有调用Hibernate对象的该属性的 get 方法时,才会从数据库表中查找对应该属性的字段值

image-20231230193804613

6 @Lob

也就是 大字段 类型都会使用 同时使用@Basic 且为懒加载

应用到实体类属性上,表示将属性映射成数据库支持的大对象类型,Clob 或者 Blog。其中:

  • Clob (Character Large Ojects) 类型是长字符串类型,

    java.sql.ClobCharacter[ ]char[ ]string 将被映射为 Clob 类型

  • Blog (Binary Large Objects) 类型是字节类型java.sql.BlobByte[ ]byte[ ]

实现了 Serializable 接口的类型将被映射为 Blob 类型。

因为这两种类型的数据一般占用的内存空间比较大,所以通常使用 延迟加载 的方式,与 @Basic 标注同时使用,

设置加载方式为 FetchType.LAZY。

7 @Column

应用于实体类的属性,可以指定数据库表字段的名字和其他属性。其属性包括:

  • name : 表示数据库表中该字段的名称,默认情形属性名称一致.

  • nullable : 表示该字段是否允许为 null ,默认为 true

  • unique : 表示该字段是否是唯一标识,默认为 false

  • length : 表示该字段的大小,仅对 string 类型的字段有效

  • insertable : ** 表示在ORM框架执行插入操作时,该字段是否应出现INSETRT语句中**,默认为 true

  • updateable: 表示在ORM框架执行更新操作时,该字段是否应该出现在UPDATE语句中默认为 true 。对于一经创建就

    不能更改的字段,该属性非常有用,比如 email 属性。

  • columnDefinition
    表示该字段在数据库中的实际类型。通常ORM框架可以根据属性类型自动判断数据库中字段的类型,但是依然有些

    例外:

    • Date 类型 无法确定数据库中字段类型究竟是 DATE TIME 还是 TIMESTAMP

    • String 的默认映射类型为 VARCHAR 如果希望将 String 类型映射到特定的数据库的 BLOB 或 TEXT 字段类型

      则需要进行设置

8 @Transient

​ 表示不会持久化到数据库中

​ 应用在实体类属性上,表示该属性不映射到数据库表,JPA会忽略该属性.

9 @Temporal

应用到实体类属性上,表明该属性映射到数据库是一个时间类型,具体定义:

  • @Temporal(TemporalType.DATE) 映射为日期 // date (只有日期)

    • @Temporal(TemporalType.TIME) 映射为日期 // time (是有时间)

      • @Temporal(TemporalType.TIMESTAMP) 映射为日期 // date time

        (日期+时间)

image-20231230200211136

package com.xxz.pojo;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
//   使用jpa 就是省去了手动创建表的  是通过反向创建表   遵从驼峰命名规则 所有的字段名要和 页面的name属性保持一致
@Entity   //  数据库对应
@Table(name = "t_blog")   //自己指定生成表的名字
public class Blog {
    @Id
    @GeneratedValue  //id生成策略 默认自动生成
    private Long id;  //主键
    private String title; //标题
    @Basic(fetch = FetchType.LAZY)  //LAZY 懒加载  就是当你使用的时候才会加载这个值不使用的时候不加载  因为值比较大 没事就加载会耗资源
    @Lob   //因为String是默认最大的varchar类型 最大255  可实际的数据内容是远大于255的所以可以数据库级别设置longtext 或者这样修改 二选一即可
    private String content;  // 内容
    private String firstPicture; // 首图
    private String flag;   // 标记
    private Integer views; //  浏览次数  去blogserviceimpl初始化浏览量为 0
    private boolean appreciation;  //  赞赏开启
    private boolean shareStatement;   // 版权开启 即转载说明
    private boolean commentabled;   // 评论开启
    private boolean published;  //   发布   为1 发布 0
    private boolean recommend;    // 是否推荐
    @Temporal(TemporalType.TIMESTAMP)  // 对应生成时间格式 包括 日期和时间 这个比较全
    private Date createTime;    // 创建时间
    @Temporal(TemporalType.TIMESTAMP)
    private Date updateTime;   //    更新时间
    @ManyToOne  // 多对一 几个博客对应一个类型
    private Type type;
    @ManyToMany(cascade = {CascadeType.PERSIST})  // 多对多
    private List<Tag> tags = new ArrayList<>();
    @ManyToOne   // 多对一
    private User user;

    @OneToMany(mappedBy = "blog")  // 一对多
    private List<Comment> comments = new ArrayList<>();

    @Transient  // 不会进行数据库的操作 这个不会保存进数据库 只是一个正常的属性值 只会正常映射
    private String tagIds;    // 查询tag 使用集合的时候需要

    private String description;
//  空的无参构造函数
    public Blog() {
    }
// 省略 get  set  tostring 方法
}

关于构造函数

也就是 创建实体类对象的时候 必须有那个 空的无参构造函数

JPA中对象是由Hibernate为我们创建的,当我们通过ID来获取某个实体的时候,这个实体给我们返回了这个对象的创建是

由Hibernate内部通过反射技术来创建的,反射的时候用到了默认的构造函数,所以这时候必须给它提供一个public的无参

构造函数。

Repository 接口

1 接口层次于方法

Spring Data JPA简化了持久层的操作,开发者只需声明持久层接口,而不需要实现该接口。SpringData JPA内部会根据

不同的接口方法,采用不同的策略自动生成实现。

​ 而开发者声明持久层接口,需要直接或者间接的方式继承Repository接口,从而使自定义的持久层拥有了持久层的操作

能力。

Repository 接口:

  • Repository 是Spring Data的核心接口,最顶层接口,不包括任何方法,他的目的是为了统所有Repository的类型,且

    让组件扫描的时候自动识别。

扩展的Repository接口

  • CrudRepository 继承了Repository,提供了曾删改查方法, 可以直接调用。

  • PagingAndSortingRepository 继承了CrudRepository,提供了分页和排序两个方法。

  • JpaRepository 继承了PagingAndSortingRepository,针对于JPA技术的接口,提供了

    flush(),saveFlush(0),deletelnBatch()等方法。

1 CrudRepository

完整定义:

public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
    
    <S extends T> S save(S var1); //将一个对象持久化到数据库中
    
    <S extends T> Iterable<S> save(Iterable<S> var1); ///将一组对象持久化到数据库中
    
    T findOne(ID var1); //根据id查找并返回一个对象
    
    boolean exists(ID var1); // 判断某个id是否存在
    
    Iterable<T> findAll(); //返回所有对象
    
    Iterable<T> findAll(Iterable<ID> var1); //根据一组id 返回对应的对象
    
    long count(); //返回共有多少条数据
    
    void delete(ID var1); //根据id删除某个对象
    
    void delete(T var1); //删除某个对象
    
    void delete(Iterable<? extends T> var1); //删除某一组对象
    
    void deleteAll(); //删除所有对象
}

2 PagingAndSortingRepository

public interface PagingAndSortingRepository<T, ID extends Serializable>extends CrudRepository<T, ID> {
 Iterable<T> findAll(Sort var1); //根据某个排序获取所有数据
 Page<T> findAll(Pageable var1); //根据分页信息获取某一页的数据
}

3 JpaRepository

public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
    
 List<T> findAll(); //឴获取所有数据,以List的方式返回
  
 List<T> findAll(Sort var1); //根据某个排序获取所有数据,以List的方式返回
 
 List<T> findAll(Iterable<ID> var1); //根据一组id返回对应的对象,以List的方式返回

 <S extends T> List<S> save(Iterable<S> var1); //将一组对象持久化到数据库中以List的方式返回

 void flush(); //将修改更新到数据库
    
 <S extends T> S saveAndFlush(S var1); //保存数据并将修改更新到数据库
    
 void deleteInBatch(Iterable<T> var1); //批量删除数据
    
 void deleteAllInBatch(); //批量删除所有数据
    
 T getOne(ID var1); //根据id查找并返回一个对象
    
}

2 使用步骤:

pository**

public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
    
 List<T> findAll(); //឴获取所有数据,以List的方式返回
  
 List<T> findAll(Sort var1); //根据某个排序获取所有数据,以List的方式返回
 
 List<T> findAll(Iterable<ID> var1); //根据一组id返回对应的对象,以List的方式返回

 <S extends T> List<S> save(Iterable<S> var1); //将一组对象持久化到数据库中以List的方式返回

 void flush(); //将修改更新到数据库
    
 <S extends T> S saveAndFlush(S var1); //保存数据并将修改更新到数据库
    
 void deleteInBatch(Iterable<T> var1); //批量删除数据
    
 void deleteAllInBatch(); //批量删除所有数据
    
 T getOne(ID var1); //根据id查找并返回一个对象
    
}

慢慢更新 !!!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值