다대다 연관관계를 회원(Member)과 상품(Product)을 예시로 설명해보도록 하겠습니다.
JPA 에서 @ManyToMany 를 통해 다대다 연관관계를 제공하지만, 결론은 사용하지 않는 것 을 추천합니다.
그렇다면, 다대다 연관관계는 어떻게 객체로 표현할 수 있을까요??
- 연결 테이블(조인 테이블)을 추가하여 일대다, 다대일 관계로 풀어내야 합니다.
 
관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없습니다.

객체는 컬렉션을 사용해서 객체 2개로 다대다 관계를 표현할 수 있습니다.

@ManyToMany 를 사용한 다대다 연관관계 매핑 방법을 살펴보며, 왜 사용하지 않는 것 을 추천하는지 알아보도록 하겠습니다.
Member 클래스 (다대다 단방향 연관관계의 주인입니다.)
@Entity
public class Member {
	@Id
    @Column(name = "MEMBER_ID")
    private Long id;
    @ManyToMany
    @JoinTable(name = "member_product,
    		  joinColumns = @JoinColumn(name = "MEMBER_ID"),
              inverseJoinColumn = @JoinColumn(name = "PRODUCT_ID"))
    private List<Product> products = new ArrayList<>();
    
    @Column(name = "USERNAME")
    private String username;
	// Getter, Setter, Constructor
}
Produdct 클래스
@Entity
public class Product {
	
    @Id
    @Column(name = "PRODUCT_ID")
    private Long id;
    
    @Column(name = "NAME")
    private String name;
}
다대다 단방향 매핑에서는 연관관계의 주인에 해당하는 클래스에 반대편 클래스를 Collection 프레임워크로 감싼 형태의 참조 필드로 작성해주시면 됩니다.
이때, 해당 참조 필드위에 @ManyToMany 과 @JoinTable(name = "연결 테이블 이름")을 추가하여 줍니다.
다대다 관계에서 사용합니다.
조인 테이블을 생성합니다.
| 속성 | 기능 | 기본값 | 
|---|---|---|
| mappedBy | 연관관계의 주인 필드를 선택한다. | |
| fetch | 글로벌 패치 전략을 설정한다.  (자세한 내용은 추후에)  | FetchType.LAZY (지연 로딩) | 
| cascade | 영속성 전이 기능을 사용한다. (자세한 내용은 추후에)  | |
| targetEntity | 연관된 엔티티의 타입 정보를 설정한다.  이 기능은 거의 사용하지 않음  | 
연결 테이블을 매핑할 때 사용합니다.
| 속성 | 기능 | 기본값 | 
|---|---|---|
| name | 연결 테이블의 이름을 지정한다. | |
| joinColumns | 연결 테이블에 존재하는 다대다 연관관계의 주인에 해당하는 외래키를 매핑한다. | |
| inverseJoinColumns | 연결 테이블에 존재하는 다대다 연관관계의 주인이 아닌 객체에 해당하는 외래키를 매핑한다. | |
@Entity
public class Member {
	@Id
    @Column(name = "MEMBER_ID")
    private Long id;
    @ManyToMany
    @JoinTable(name = "member_product,
    		  joinColumns = @JoinColumn(name = "MEMBER_ID"),
              inverseJoinColumn = @JoinColumn(name = "PRODUCT_ID"))
    private List<Product> products = new ArrayList<>();
    
    @Column(name = "USERNAME")
    private String username;
	// Getter, Setter, Constructor
}
Produdct 클래스
@Entity
public class Product {
	
    @Id
    @Column(name = "PRODUCT_ID")
    private Long id;
    
    @ManyToMany(mappedBy = "products")
    private List<Member> members = new ArrayList<>();
    
    @Column(name = "NAME")
    private String name;
    // Getter, Setter, Constructor
}
다대다 양방향 매핑에서는 다대다 단방향 코드에 추가로 연관관계의 주인이 아닌 클래스에 반대편 클래스(연관관계 주인)를 Collection 프레임워크로 감싼 형태의 참조 필드로 작성해주시면 됩니다.
이때, 해당 참조 필드위에 @ManyToMany(mappedBy = "반대쪽 매핑의 필드 이름값")을 추가하여 연관관계의 주인을 지정하여 줍니다.

@ManyToMany 를 사용하면 편리한 점
하지만 실무에서 @ManyToMany 매핑은 사용하기에는 한계가 있습니다.
연결 테이블용 엔티티를 생성 후,
@ManyToMany 를 @ManyToOne 과 @OneToMany 를 활용하여 일대다, 다대일 관계로 풀어줍니다.

ORDER 는 예약어 이기 때문에, 테이블 이름을 수정해주어야 합니다. (예 - ORDERS)즉, 위와같이 @ManyToMany 매핑을 @ManyToOne 과 @OneToMany 를 사용하여 코드를 작성합니다.
Member 클래스 (기존 다대다 단방향 매핑 시, 연관관계의 주인 입니다.)
@Entity
public class Member {
    @Id
    @Column(name = "MEMBER_ID")
    private Long id;
	// 연결 테이블(MEMBER_PRODUCT)쪽이 외래키를 갖고있기 때문에, 연결 테이블이 연관관계의 주인이다.
    @OneToMany(mappedBy = "member") 
    private List<MemberProduct> memberProducts = new ArrayList<>();
    @Column(name = "USERNAME")
    private String username;
    // Getter, Setter, Constructor
}
Produdct 클래스
@Entity
public class Product {
	
    @Id
    @Column(name = "PRODUCT_ID")
    private Long id;
    @Column(name = "NAME")
    private String name;
    // Getter, Setter, Constructor
}
MemberProduct 클래스 (다대다 에서 연결 테이블)
@Table(name = "ORDERS")
@Entity
public class MemberProduct {
    @Id
    @Column(name = "ORDER_ID")
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;
    
    @Column(name = "ORDERAMOUNT")
    private Integer orderAmount;
    @Column(name = "ORDERDATE")
    private LocalDateTime orderDate;
    
    // Getter, Setter, Constructor
}
연관관계 사용에 대한 예시 코드는 아래 링크를 참고해주시기 바랍니다.
소스 코드
Member 클래스
@Entity
public class Member {
    @Id
    @Column(name = "MEMBER_ID")
    private Long id;
	// 연결 테이블(MEMBER_PRODUCT)쪽이 외래키를 갖고있기 때문에, 연결 테이블이 연관관계의 주인이다.
    @OneToMany(mappedBy = "member") 
    private List<MemberProduct> memberProducts;
    @Column(name = "USERNAME")
    private String username;
    // Getter, Setter, Constructor
}
Produdct 클래스
@Entity
public class Product {
	
    @Id
    @Column(name = "PRODUCT_ID")
    private Long id;
    
    // 연결 테이블(MEMBER_PRODUCT)쪽이 외래키를 갖고있기 때문에, 연결 테이블이 연관관계의 주인이다.
    @OneToMany(mappedBy = "product") 
    private List<MemberProduct> memberProducts;
    @Column(name = "NAME")
    private String name;
    // Getter, Setter, Constructor
}
MemberProduct 클래스 (다대다 에서 연결 테이블)
@Table(name = "ORDERS")
@Entity
public class MemberProduct {
    @Id
    @Column(name = "ORDER_ID")
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;
    
    @Column(name = "ORDERAMOUNT")
    private Integer orderAmount;
    @Column(name = "ORDERDATE")
    private LocalDateTime orderDate;
    
    // Getter, Setter, Constructor
}
연관관계 사용에 대한 예시 코드는 아래 링크를 참고해주시기 바랍니다.
소스 코드