@[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
Первичный ключ генерируется методом самовозрастания идентификатора базы данных, который не поддерживается оракулом.AUTO
JPA автоматически выбирает подходящую стратегию и является вариантом по умолчанию.SEQUENCE
Oracle не поддерживает саморасширение первичных ключей. Он предоставляет механизм, называемый «последовательность», для генерации первичных ключей. 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 {
}