实体Book:书籍。
实体Author:作者。
书籍和作者是多对多的关系。一本书籍可以由很多的作者编写,一个作者也可以编写写很多本书。
JPA中使用@ManyToMany来注解多对多的关系,由一个关联表来维护。这个关联表的表名默认是:主表名+下划线+从表名。(主表是指关系维护端对应的表,从表指关系被维护端对应的表)。这个关联表只有两个外键字段,分别指向主表ID和从表ID。字段的名称默认为:主表名+下划线+主表中的主键列名,从表名+下划线+从表中的主键列名。
需要注意的:
1、多对多关系中一般不设置级联保存、级联删除、级联更新等操作。
2、可以随意指定一方为关系维护端,在这个例子中,我指定Book为关系维护端,所以生成的关联表名称为: book_author,关联表的字段为:book_id和author_id。
3、多对多关系的绑定由关系维护端来完成,即由Book.setAuthors(authors)来绑定多对多的关系。关系被维护端不能绑定关系,即Author不能绑定关系。
4、多对多关系的解除由关系维护端来完成,即由Book.getAuthors.remove(author)来解除多对多的关系。关系被维护端不能解除关系,即Author不能解除关系。
5、如果Book和Author已经绑定了多对多的关系,那么不能直接删除Author,需要由Book解除关系后,才能删除Author。但是可以直接删除Book,因为Book是关系维护端,删除Book时,会先解除Book和Author的关系,再删除Author。
package com.zzg.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@SuppressWarnings("serial")
@Entity
@Table(name="book")
public class Book implements Serializable {
@Id
@GeneratedValue
private Long id;
@Column(name="name")
private String name;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "book_author", joinColumns = {
@JoinColumn(name = "book_id", referencedColumnName = "id")}, inverseJoinColumns = {
@JoinColumn(name = "author_id", referencedColumnName = "id")})
private Set authors;
public Book() {
super();
}
public Book(String name) {
super();
this.name = name;
this.authors = new HashSet<>();
}
public Book(String name, Set authors) {
super();
this.name = name;
this.authors = authors;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set getAuthors() {
return authors;
}
public void setAuthors(Set authors) {
this.authors = authors;
}
@Override
public String toString() {
return String.format("Book [id=%s, name=%s, authors=%s]", id, name, authors);
}
}
package com.zzg.entity;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@SuppressWarnings("serial")
@Entity
@Table(name="author")
public class Author implements Serializable {
@Id
@GeneratedValue
private Long id;
@Column(name="name")
private String name;
@ManyToMany(mappedBy = "authors")
private Set books;
public Author() {
super();
}
public Author(String name) {
super();
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set getBooks() {
return books;
}
public void setBooks(Set books) {
this.books = books;
}
@Override
public String toString() {
return String.format("Author [id=%s, name=%s, books=%s]", id, name, books);
}
}
package com.zzg.entity.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.zzg.entity.Author;
public interface AuthorRepository extends JpaRepository {
}
package com.zzg.entity.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.zzg.entity.Book;
public interface BookRepository extends JpaRepository {
}
package com.zzg.test;
import java.util.Arrays;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.zzg.entity.Author;
import com.zzg.entity.Book;
import com.zzg.entity.dao.AuthorRepository;
import com.zzg.entity.dao.BookRepository;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ManyToManyTest {
@Autowired
private AuthorRepository authorRepository;
@Autowired
private BookRepository bookRepository;
@Test
public void insertManyToMany() {
Author lewis = new Author("Lewis");
Author mark = new Author("Mark");
Author peter = new Author("Peter");
Book spring = new Book("Spring in Action");
spring.getAuthors().addAll(Arrays.asList(lewis, mark));
Book springboot = new Book("Spring Boot in Action");
springboot.getAuthors().addAll(Arrays.asList(lewis, peter));
bookRepository.save(Arrays.asList(spring, springboot));
}
@Test
public void selectManyToMany() {
Book book = bookRepository.findOne(1L);
System.out.println(book.toString());
book.getAuthors().stream().forEach(item->{
System.out.println(item.toString());
});
}
@Test
public void updateManyToMany() {
// 移除目标数据
Author author = authorRepository.findOne(1L);
// 查询指定数据
Book book = bookRepository.findOne(1L);
System.out.println(book.toString());
// 数据移除
book.getAuthors().add(new Author("zzg"));
// 数据保存
bookRepository.save(book);
}
@Test
public void deleteManyToMany() {
bookRepository.delete(1L);
}
}
效果截图:
新增
修改
删除
查询
CREATE TABLE IF NOT EXISTS `author` (
`id` bigint(10) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- 导出 表 oasys.book 结构
CREATE TABLE IF NOT EXISTS `book` (
`id` bigint(10) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- 导出 表 oasys.book_author 结构
CREATE TABLE IF NOT EXISTS `book_author` (
`book_id` bigint(10) NOT NULL,
`author_id` bigint(10) NOT NULL,
KEY `author_id` (`author_id`),
KEY `book_id` (`book_id`),
CONSTRAINT `author_id` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`),
CONSTRAINT `book_id` FOREIGN KEY (`book_id`) REFERENCES `book` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;