├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── hellokoding │ │ └── jpa │ │ ├── HelloJpaApplication.java │ │ ├── model │ │ ├── Book.java │ │ └── Publisher.java │ │ └── repository │ │ ├── BookRepository.java │ │ └── PublisherRepository.java └── resources │ ├── application.properties │ └── db.sql └── test └── java └── com └── hellokoding └── jpa └── HelloJpaApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | target 4 | *.DS_Store 5 | .mvn 6 | mvn* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Hello Koding 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JPA Many-To-Many Relationship Example with Spring Boot, Maven, and MySQL 2 | 3 | ## Guide 4 | https://hellokoding.com/jpa-many-to-many-relationship-mapping-example-with-spring-boot-maven-and-mysql/ 5 | 6 | ## Prerequisites 7 | - JDK 1.8 or later 8 | - Maven 3 or later 9 | - MySQL 5.6 or later 10 | 11 | ## Stack 12 | - Spring Data JPA 13 | - Spring Boot 14 | - MySQL 15 | 16 | ## Run 17 | `mvn spring-boot:run` 18 | 19 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.hellokoding 7 | jpa 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | JPA Many-To-Many Example 12 | JPA Many-To-Many Example 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.2.6.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-data-jpa 30 | 31 | 32 | 33 | mysql 34 | mysql-connector-java 35 | runtime 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-test 40 | test 41 | 42 | 43 | 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-maven-plugin 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/main/java/com/hellokoding/jpa/HelloJpaApplication.java: -------------------------------------------------------------------------------- 1 | package com.hellokoding.jpa; 2 | 3 | import com.hellokoding.jpa.model.Book; 4 | import com.hellokoding.jpa.model.Publisher; 5 | import com.hellokoding.jpa.repository.BookRepository; 6 | import com.hellokoding.jpa.repository.PublisherRepository; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.CommandLineRunner; 11 | import org.springframework.boot.SpringApplication; 12 | import org.springframework.boot.autoconfigure.SpringBootApplication; 13 | 14 | import javax.transaction.Transactional; 15 | import java.util.HashSet; 16 | 17 | @SpringBootApplication 18 | public class HelloJpaApplication implements CommandLineRunner { 19 | private static final Logger logger = LoggerFactory.getLogger(HelloJpaApplication.class); 20 | 21 | @Autowired 22 | private BookRepository bookRepository; 23 | 24 | @Autowired 25 | private PublisherRepository publisherRepository; 26 | 27 | public static void main(String[] args) { 28 | SpringApplication.run(HelloJpaApplication.class, args); 29 | } 30 | 31 | @Override 32 | @Transactional 33 | public void run(String... strings) throws Exception { 34 | // save a couple of books 35 | Publisher publisherA = new Publisher("Publisher A"); 36 | Publisher publisherB = new Publisher("Publisher B"); 37 | Publisher publisherC = new Publisher("Publisher C"); 38 | 39 | bookRepository.save(new HashSet(){{ 40 | add(new Book("Book A", new HashSet(){{ 41 | add(publisherA); 42 | add(publisherB); 43 | }})); 44 | 45 | add(new Book("Book B", new HashSet(){{ 46 | add(publisherA); 47 | add(publisherC); 48 | }})); 49 | }}); 50 | 51 | // fetch all books 52 | for(Book book : bookRepository.findAll()) { 53 | logger.info(book.toString()); 54 | } 55 | 56 | // save a couple of publishers 57 | Book bookA = new Book("Book A"); 58 | Book bookB = new Book("Book B"); 59 | 60 | publisherRepository.save(new HashSet() {{ 61 | add(new Publisher("Publisher A", new HashSet() {{ 62 | add(bookA); 63 | add(bookB); 64 | }})); 65 | 66 | add(new Publisher("Publisher B", new HashSet() {{ 67 | add(bookA); 68 | add(bookB); 69 | }})); 70 | }}); 71 | 72 | // fetch all publishers 73 | for(Publisher publisher : publisherRepository.findAll()) { 74 | logger.info(publisher.toString()); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/hellokoding/jpa/model/Book.java: -------------------------------------------------------------------------------- 1 | package com.hellokoding.jpa.model; 2 | 3 | import javax.persistence.*; 4 | import java.util.Set; 5 | 6 | @Entity 7 | public class Book{ 8 | private int id; 9 | private String name; 10 | private Set publishers; 11 | 12 | public Book() { 13 | 14 | } 15 | 16 | public Book(String name) { 17 | this.name = name; 18 | } 19 | 20 | public Book(String name, Set publishers){ 21 | this.name = name; 22 | this.publishers = publishers; 23 | } 24 | 25 | @Id 26 | @GeneratedValue(strategy = GenerationType.AUTO) 27 | public int getId() { 28 | return id; 29 | } 30 | 31 | public void setId(int id) { 32 | this.id = id; 33 | } 34 | 35 | public String getName() { 36 | return name; 37 | } 38 | 39 | public void setName(String name) { 40 | this.name = name; 41 | } 42 | 43 | @ManyToMany(cascade = CascadeType.ALL) 44 | @JoinTable(name = "book_publisher", joinColumns = @JoinColumn(name = "book_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "publisher_id", referencedColumnName = "id")) 45 | public Set getPublishers() { 46 | return publishers; 47 | } 48 | 49 | public void setPublishers(Set publishers) { 50 | this.publishers = publishers; 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | String result = String.format( 56 | "Book [id=%d, name='%s']%n", 57 | id, name); 58 | if (publishers != null) { 59 | for(Publisher publisher : publishers) { 60 | result += String.format( 61 | "Publisher[id=%d, name='%s']%n", 62 | publisher.getId(), publisher.getName()); 63 | } 64 | } 65 | 66 | return result; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/hellokoding/jpa/model/Publisher.java: -------------------------------------------------------------------------------- 1 | package com.hellokoding.jpa.model; 2 | 3 | import javax.persistence.*; 4 | import java.util.Set; 5 | 6 | @Entity 7 | public class Publisher { 8 | private int id; 9 | private String name; 10 | private Set books; 11 | 12 | public Publisher(){ 13 | 14 | } 15 | 16 | public Publisher(String name){ 17 | this.name = name; 18 | } 19 | 20 | public Publisher(String name, Set books){ 21 | this.name = name; 22 | this.books = books; 23 | } 24 | 25 | @Id 26 | @GeneratedValue(strategy = GenerationType.AUTO) 27 | public int getId() { 28 | return id; 29 | } 30 | 31 | public void setId(int id) { 32 | this.id = id; 33 | } 34 | 35 | public String getName() { 36 | return name; 37 | } 38 | 39 | public void setName(String name) { 40 | this.name = name; 41 | } 42 | 43 | @ManyToMany(mappedBy = "publishers") 44 | public Set getBooks() { 45 | return books; 46 | } 47 | 48 | public void setBooks(Set books) { 49 | this.books = books; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/hellokoding/jpa/repository/BookRepository.java: -------------------------------------------------------------------------------- 1 | package com.hellokoding.jpa.repository; 2 | 3 | import com.hellokoding.jpa.model.Book; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface BookRepository extends JpaRepository{ 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/hellokoding/jpa/repository/PublisherRepository.java: -------------------------------------------------------------------------------- 1 | package com.hellokoding.jpa.repository; 2 | 3 | import com.hellokoding.jpa.model.Publisher; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface PublisherRepository extends JpaRepository{ 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:mysql://localhost/jpa_manytomany 2 | spring.datasource.username=hellokoding 3 | spring.datasource.password=hellokoding 4 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 5 | 6 | spring.jpa.show-sql=true 7 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect -------------------------------------------------------------------------------- /src/main/resources/db.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS `jpa_manytomany`; 2 | USE `jpa_manytomany`; 3 | 4 | -- 5 | -- Table structure for table `book` 6 | -- 7 | 8 | DROP TABLE IF EXISTS `book`; 9 | CREATE TABLE `book` ( 10 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 11 | `name` varchar(255) DEFAULT NULL, 12 | PRIMARY KEY (`id`) 13 | ) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8; 14 | 15 | -- 16 | -- Table structure for table `book_publisher` 17 | -- 18 | 19 | DROP TABLE IF EXISTS `book_publisher`; 20 | CREATE TABLE `book_publisher` ( 21 | `book_id` int(10) unsigned NOT NULL, 22 | `publisher_id` int(10) unsigned NOT NULL, 23 | PRIMARY KEY (`book_id`,`publisher_id`), 24 | KEY `fk_bookpublisher_publisher_idx` (`publisher_id`), 25 | CONSTRAINT `fk_bookpublisher_book` FOREIGN KEY (`book_id`) REFERENCES `book` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 26 | CONSTRAINT `fk_bookpublisher_publisher` FOREIGN KEY (`publisher_id`) REFERENCES `publisher` (`id`) ON DELETE CASCADE ON UPDATE CASCADE 27 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 28 | 29 | -- 30 | -- Table structure for table `publisher` 31 | -- 32 | 33 | DROP TABLE IF EXISTS `publisher`; 34 | CREATE TABLE `publisher` ( 35 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 36 | `name` varchar(255) DEFAULT NULL, 37 | PRIMARY KEY (`id`) 38 | ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8; -------------------------------------------------------------------------------- /src/test/java/com/hellokoding/jpa/HelloJpaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.hellokoding.jpa; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.SpringApplicationConfiguration; 6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 7 | 8 | @RunWith(SpringJUnit4ClassRunner.class) 9 | @SpringApplicationConfiguration(classes = HelloJpaApplication.class) 10 | public class HelloJpaApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | --------------------------------------------------------------------------------