Spring Boot интегрирует JPA

Spring Boot

@[toc]

Предисловие: Mybatis используется постоянно.В последнее время по рабочим причинам мне приходится использовать JPA, поэтому я организую учебные заметки, чтобы не забыть, и надеюсь помочь тем, кому необходимо использовать эту технологию.

1. Концепции Spring Data JPA

  • JPA (Java Persistence API, Java Persistence API) — это набор спецификаций ORM, который позволяет приложениям получать доступ к уровню сохраняемости унифицированным способом.
  • JPA этоHibernateАбстракция , которая функционально является подмножеством Hibernate.
  • Spring Data JPA — это подпроект Spring для упрощения доступа к базе данных, поддерживающийnosql(redis,mongoDB)и реляционные базы данных (jdbc,jpa)место хранения

2. Используйте

2.1 Знакомство с зависимостями JPA

  • Создайте проект SpringBoot и введитеJPA,MySQL,WebЗависимость и зависимость от пула соединений с базой данных
  • Поскольку версия моей локальной базы данных 5.7, я отмечаю номер версии при введении зависимости mysql.
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
    <version>5.1.28</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

2.2 Настройка параметров базы данных подключения и параметров jpa

  • в каталоге ресурсовapplication.propertiesв файле
# 配置数据库连接池及数据库驱动
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 配置mysql的链接信息
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/jpaDemo?useUnicode=true&characterEncoding=utf-8

#jpa
spring.jpa.database=mysql
spring.jpa.database-platform=mysql
#是否自动生成dd
spring.jpa.generate-ddl=true
# 生成方式 update 运行时在数据库生成表,若有更新则去更新数据
spring.jpa.hibernate.ddl-auto=update
# 格式化sql语句
spring.jpa.properties.hibernate-format_sql=true
# 控制台展示 JPA 框架生成的sql语句
spring.jpa.show-sql=true
# 解决 hibernate multiple merge 问题
spring.jpa.properties.hibernate.event.merge.entity_copy_observer = allow  
# 使用JPA 创建表时,默认使用的存储引擎是MyISAM,通过指定数据库版本,可以使用InnoDB
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect

2.3 Основное использование

2.3.1 Создание класса сущностей

package com.bisnow.demo.pojo;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String bookname;

    private String author;

    get + set + toString
}

2.3.2 Операции с базой данных

Требуется интерфейс для наследования JpaRepository , и в интерфейсе есть готовые методы или пользовательские методы

package com.bisnow.demo.repository;

import com.bisnow.demo.pojo.Book;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BookRepository extends JpaRepository<Book,Integer> {
}
  • Запустите создать таблицу, чтобы вставить данные

在这里插入图片描述

2.3.3 Тестирование

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    @Autowired
    BookRepository bookRepository;

    @Test
    public void test1(){
        List<Book> books = bookRepository.findAll();
        books.forEach(b-> System.out.println(b));
    }
}

在这里插入图片描述

2.4 Общие аннотации классов сущностей JPA

Когда проект JPA запущен, он автоматически создает таблицу в базе данных в соответствии с классом сущности.

2.4.1 @Entity

Указывает, что это класс сущностей, по умолчанию имя класса — это имя таблицы.

2.4.2 @Table

и@EntityПараллельное использование, пользовательское имя таблицы базы данных

2.4.3 @Id

пометить первичный ключ

2.4.4 @GeneratedValue

  • Используется вместе с @Id для обозначения стратегии генерации первичного ключа черезstrategyназначение атрибута
  • IDENTITYПервичный ключ генерируется методом самовозрастания идентификатора базы данных, который не поддерживается оракулом.
  • AUTOJPA автоматически выбирает подходящую стратегию и является вариантом по умолчанию.
  • SEQUENCEOracle не поддерживает саморасширение первичных ключей. Он предоставляет механизм, называемый «последовательность», для генерации первичных ключей. GenerationType.SEQUENCE можно использовать в качестве стратегии генерации первичных ключей. Недостатком является то, что его можно использовать только в некоторых базах данных. которые поддерживают последовательности (Oracle, PostgreSQL, DB2), обычно используемые с @SequenceGenerator, аннотация @SequenceGenerator указывает последовательность для генерации первичного ключа, а последовательность SEQ_GEN_SEQUENCE генерируется автоматически, если последовательность не указана
  • TABLE: первичный ключ генерируется таблицей, и платформа использует таблицу для имитации последовательности генерации первичного ключа.Использование этой стратегии упрощает миграцию базы данных.
package com.bisnow.demo.pojo;

import javax.persistence.*;

@Entity 
@Table(name = "t_person")  
public class Person {

    @Id 
    
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;

    private Integer age;

    get + set 方法
}
  • Запустите проект в этот момент, вы можете увидеть оператор создания таблицы в консоли, и вы можете просмотреть таблицу и связь между таблицами в базе данных.

在这里插入图片描述

  • Удалить созданную таблицу между. Если вы аннотируете атрибут @Table, измените@GeneratedValueстратегия, то
@GeneratedValue(strategy = GenerationType.IDENTITY)

在这里插入图片描述

2.4.5 @Column

Используется для описания соответствующих полей таблицы данных атрибутов сущности, гдеname、nullable、unique、lengthАтрибуты используются чаще и используются для описания имени поля, может ли поле быть нулевым, является ли поле уникальным и длина поля.Когда в фактической разработке необходимы другие атрибуты, вы можете получить адрес документа API из ссылки и проверьте конфигурацию документа.

@Column(length = 400,name = "p_name",nullable = false,unique = true)
private String name;

В этот момент можно увидеть таблицу

在这里插入图片描述

2.4.6 @Transient

Игнорировать этот атрибут при создании таблицы в базе данных

@Transient
private String name;

在这里插入图片描述

2.4.7 Односторонняя ассоциация @OneToOne

Отношение «один к одному» между двумя объектами, такими как человек и удостоверение личности, является отношением «один к одному».

При запросе объектов сущностей, содержащих связанные свойства, связанные объекты сущностей могут быть получены из базы данных синхронно, но не наоборот.

  • Создайте два класса сущностей Person, Card
package com.bisnow.demo.pojo;

import javax.persistence.*;

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;

    @OneToOne
    //关联的字段 name属性可以标注表中字段的值
    @JoinColumn(name = "card_id")
    private Card card;

    get + set + toString ...
}
package com.bisnow.demo.pojo;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Card {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String num;

    get + set + toString ... 
}
  • Создать интерфейс репозитория, тестовый запрос
    @Autowired
    PersonRepository personRepository;

    @Autowired
    CardRepository cardRepository;

    @Test
    public void contextLoads() {
        Optional<Person> person = personRepository.findById(1);
        Person p = person.get();
        System.out.println(p);
        Optional<Card> card = cardRepository.findById(1);
        Card c = card.get();
        System.out.println(c);
    }

在这里插入图片描述

  • На данный момент видно, что соответствующую Карту можно получить синхронно, запросив Person, но Карту нельзя получить, запросив
  • отношения между таблицами в базе данных

在这里插入图片描述

2.4.8 Односторонняя ассоциация @OneToMany и @ManyToOne

Связь «один ко многим» между двумя сущностями, такими как человек и телефон, — это связь «один ко многим».У человека может быть несколько телефонов, а телефон может принадлежать только одному человеку.

2.4.8.1 @ManyToOne

  • Создание классов сущностей Person и Phone
package com.bisnow.demo.pojo;

import javax.persistence.*;

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;

    get + set + toString ...
}

package com.bisnow.demo.pojo;

import javax.persistence.*;

@Entity
public class Phone {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private Integer number;

    @ManyToOne
    @JoinColumn(name = "person_id")
    private Person person;

    get + set + toString ...
}

  • вставить данные

在这里插入图片描述

  • Создать интерфейс репозитория, тестовый запрос
    @Autowired
    PersonRepository personRepository;

    @Autowired
    PhoneRepository phoneRepository;

    @Test
    public void test2(){
        List<Person> all = personRepository.findAll();
        all.forEach(p-> System.out.println(p));
        List<Phone> all1 = phoneRepository.findAll();
        all1.forEach(p-> System.out.println(p));
    }

在这里插入图片描述

2.4.8.2 @OneToMany

  • Создание классов сущностей Person и Phone
package com.bisnow.demo.pojo;

import javax.persistence.*;

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;

    @OneToMany(cascade = CascadeType.MERGE,fetch = FetchType.EAGER)
    @JoinColumn(name = "phone_id")
    private List<Phone> phone;

    get + set + toString ...
}

package com.bisnow.demo.pojo;

import javax.persistence.*;

@Entity
public class Phone {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private Integer number;

    get + set + toString ...
}
  • вставить данные

在这里插入图片描述

  • Создать интерфейс репозитория, тестовый запрос
    @Autowired
    PersonRepository personRepository;

    @Autowired
    PhoneRepository phoneRepository;

    @Test
    public void test2(){
        List<Person> all = personRepository.findAll();
        all.forEach(p-> System.out.println(p));
        List<Phone> all1 = phoneRepository.findAll();
        all1.forEach(p-> System.out.println(p));
    }

在这里插入图片描述

2.4.8.3 Атрибут выборки определяет стратегию выборки данных

  • EAGERпринести сейчас
  • LAZYленивая загрузка

2.4.8.4 Атрибут каскада определяет свойства каскада

  • CascadeType.PERSIST: Каскадные операции сохранения, когда объект сохраняется в базе данных, соответствующий связанный с ним объект также будет сохранен в базе данных.
  • CascadeType.REMOVE: Каскадные операции удаления, когда текущий объект удаляется из базы данных, связанный объект также будет удален.
  • CascadeType.DETACH: Каскадирование выходит из-под контроля, текущий объект перестает управляться структурой ORM, а связанный с ним объект также перестает управляться синхронно.Для сущностей в деуправляемом состоянии операции модификации не могут быть сохранены в базе данных.
  • CascadeType.MERGE: Операция каскадного слияния, при изменении данных объекта данные в Курсе будут обновляться соответствующим образом.
  • CascadeType.REFRESH: Каскадное обновление, когда текущая модификация объекта сохраняется в базе данных, связанное состояние объекта будет перезагружено из базы данных, игнорируя предыдущее состояние.
  • CascadeType.ALL: содержит все вышеперечисленные каскадные операции

2.4.9 @ManyToMany

Отношения сущностей «многие ко многим», такие как отношения между учащимися и выбранными курсами, учащийся может выбрать несколько курсов, а курс может быть выбран несколькими учащимися.

  • Создание классов сущностей Student и Course
@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;

    @ManyToMany(targetEntity = Course.class,fetch = FetchType.EAGER)
    private List<Course> courses;

    get + set + toString ...
}

@Entity
public class Course {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;

    get + set + toString
}
  • вставить данные

在这里插入图片描述

  • Создать интерфейс репозитория, тестовый запрос
    @Autowired
    StudentRepository studentRepository;
    @Autowired
    CourseRepository courseRepository;

    @Test
    public void test3(){
        List<Student> all = studentRepository.findAll();
        System.out.println(all);
        List<Course> all1 = courseRepository.findAll();
        System.out.println(all1);
    }

在这里插入图片描述

2.5 Операции с базой данных

Нужно наследование интерфейсаJpaRepository<实体类名,id类型>, вы можете написать существующие методы или пользовательские методы в интерфейсе

  • спецификация пользовательского метода

在这里插入图片描述

public interface BookRepository extends JpaRepository<Book,Integer> {

    List<Book> getBookByBooknameContains(String bookname);

    List<Book> getBookByIdGreaterThanAndAuthorEndsWith(Integer id,String author);

    //表示自定义的 dml 操作方法
    @Query(value = "select * from book where id = (select max(id) from book)",nativeQuery = true)
    Book getMaxIdBook();

    // 两种传参方式 使用 ?1 的方式不需要 @Param 注解
    // @Query(value = "select * from book where id > ?1",nativeQuery = true)
    @Query(value = "select * from book where id > :id",nativeQuery = true)
    List<Book> idGreaterThan(@Param("id") Integer id);

    //自定义 ddl 操作方法 需要 @Modifying 注解,告知此操作会对数据库的数据进行修改
    // 对数据库的数据进行修改时 需要添加事务管理@Transactional(一般加在Service层)
    @Query(value = "update t_book set bookname = ?1 where id = ?2",nativeQuery = true)
    @Modifying
    int updateBookById(String bookname,Long id);
}
  • Вставьте данные и проверьте

在这里插入图片描述

    @Autowired
    BookRepository bookRepository;

    @Test
    public void test4(){
        List<Book> b = bookRepository.getBookByBooknameContains("拾");
        System.out.println(b);
        List<Book> b2 = bookRepository.getBookByIdGreaterThanAndAuthorEndsWith(2, "夏达");
        System.out.println(b2);
        Book maxIdBook = bookRepository.getMaxIdBook();
        System.out.println(maxIdBook);
        List<Book> books = bookRepository.idGreaterThan(2);
        System.out.println(books);
    }

在这里插入图片描述

  • пройти через@QueryПользовательские методы dml и ddl
  • Пользовательские методы dml могут передавать параметры через ?1, ?2 или :s_id + (@Param("s_id"))
  • Пользовательский метод ddl необходимо добавить в пользовательский метод.@ModifyingАннотация и необходимость добавления управления транзакциями при работе@Transactional(Обычно добавляется на уровень сервиса)`
@Service
@Transactional
public class BookService {
}