중고책 판매 사이트 제작 프로젝트를 하던 중, 회원(User)-채팅방(Chat)의 관계를 다대다로 설정해야했다.
처음 생각했던 방법은 @ManyToMany
@ManyToMany
다대다 단방향
다대다 관계에서는 기본적으로 두 테이블 사이에 연결 테이블이 들어간다. 그 연결 테이블은 @JoinTable
에서 지정해줄 수 있다.
단방향 연결은 연관 관계의 주인(User
)에서 joinColumn
(내 쪽에서 연결할 컬럼), inverseJoinColumn
(상대 쪽에서 연결할 컬럼)을 모두 JoinTable
지정 시에 같이 설정할 수 있다.
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id", nullable = false, unique = true)
private Long userId;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
@ManyToMany
@JoinTable(name = "user_chat",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "chat_id"))
private List<Chat> chats = new ArrayList<>();
}
@Entity
@Table(name = "chat")
public class Chat {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "chat_id", nullable = false, unique = true)
private Long chatId;
}
다대다 양방향
두 Entity가 모두 List<상대 Entity>
를 갖고있다.
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id", nullable = false, unique = true)
private Long userId;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
@ManyToMany
@JoinTable(name = "user_chat",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "chat_id"))
private List<Chat> chats = new ArrayList<>();
}
@Entity
@Table(name = "chat")
public class Chat {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "chat_id", nullable = false, unique = true)
private Long chatId;
@ManyToMany(mappedBy = "chats")
private List<User> users = new ArrayList<>();
}
두 방법 동일하게 연결 테이블이 user_id
, chat_id
하나씩 참조하게 된다.
mysql> desc user_chat;
+---------+--------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------+------+-----+---------+-------+
| user_id | bigint | NO | MUL | NULL | |
| chat_id | bigint | NO | MUL | NULL | |
+---------+--------+------+-----+---------+-------+
2 rows in set (0.01 sec)
@ManyToMany 한계
단순히 두 테이블의 다대다 관계를 나타내기 위한 연결 테이블을 생성하기에 각 테이블의 기본 키만 갖고있다.
그렇기 때문에 확장 가능성을 고려했을 때 좋은 선택이 아니다.
그래서 프로젝트에선 @ManyToMany
대신 연결 테이블(엔티티)을 직접 생성하고 연결 테이블과 각 테이블을 다대일 관계로 만들었다.
연결 테이블 직접 정의 후 다대일 연결(@OneToMany, @ManyToOne)
User
와 Chat
에 UserChat
(연결 엔티티)의 리스트를 정의하고 mappedBy
에는 각 엔티티의 테이블 이름(user
, chat
)을 지정했다.
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id", nullable = false, unique = true)
private Long userId;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
@OneToMany(mappedBy = "user")
private List<UserChat> userChats = new ArrayList<>();
}
@Entity
@Table(name = "chat")
public class Chat {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "chat_id", nullable = false, unique = true)
private Long chatId;
@OneToMany(mappedBy = "chat")
private List<UserChat> userChats = new ArrayList<>();
}
연결 테이블에는 각 엔티티와 다대일(@ManyToOne
)로 기본키와 연결하도록 했다.
@Entity
public class UserChat {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_chat_id", nullable = false, unique = true)
private Long userChatId;
@ManyToOne
@JoinColumn(name = "chat_id")
private Chat chat;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
연결 테이블의 기본키를 따로 둬서 복합 기본 키일때 생길 수 있는 문제점(쿼리 작성 시 복잡함 등)을 배제하고자 했다.
mysql> desc user_chat;
+--------------+--------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------+------+-----+---------+----------------+
| user_chat_id | bigint | NO | PRI | NULL | auto_increment |
| chat_id | bigint | YES | MUL | NULL | |
| user_id | bigint | YES | MUL | NULL | |
+--------------+--------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
참고
'Web > Spring' 카테고리의 다른 글
[ERROR] gradle - java version (0) | 2024.06.09 |
---|---|
[Spring Security] OAuth, JWT .. 적용기 (1) (0) | 2024.01.05 |
[Exception Handler] Java, SpringBoot 에서의 예외 처리 (0) | 2023.12.23 |