Node.js 개발자의 코-프링 적응기(2) | 인프런 워밍업 클럽 2기 - 백엔드
인프런 워밍업 클럽 2기입문자를 위한 Spring Boot with Kotlin(https://inf.run/bXQQQ) 강의를 듣고 작성하였습니다. h2자바로 구현된 인 메모리 DB 입니다. 애플리케이션이 종료되면 모든 메모리가 삭제됩니다.(휘발성) 프로젝트 내부에 임베드 해서 브라우저를 통해 매니징을 할 수 있다는 점이 특이했습니다. 겪은 오류 - user 테이블이 생기지 않음예전에 회사에서 user 테이블에 대해 데이터베이스를 명시하지 않아 오류가 발생한 적이 있었는데, 비슷한 상황인거 같아, 테이블 이름을 명시하였습니다.https://velog.io/@readnthink/DataJpaTest사용시-user-table-예약어-에러엔티티 정의 어노테이션@Table 와 @Entity테이블은 물리적인 정보, 엔티티는 논리적인 정보를 정의하는 걸까? 싶었는데, 아니었던 것 같습니다. 아예 목적이 좀 다른 느낌..?@Entity is useful with model classes to denote that this is the entity or table@Table is used to provide any specific name to your table if you want to provide any different namehttps://stackoverflow.com/questions/18732646/name-attribute-in-entity-and-tablehttps://www.inflearn.com/community/questions/75556 엔티티랑 테이블 어노테이션 내부에 들어가도 자세하게 테이블 옵션을 정의한다기보다는 느낌보다는 정말 bean임을 명시하기 위한 식별자라고 생각이 들었습니다. // Sequelize entity 정의 예시 @Table({ tableName: 'charge', timestamps: true, paranoid: true, createdAt: 'created_at', deletedAt: 'deleted_at', }) export class ChargeEntity extends Model<ChargeAttributes, ChargeCreationAttributes> implements ChargeAttributes {..} /* * node.js 의 Sequelize 라는 ORM에서는 @Table 에 이렇게 다양한 옵션이 존재해서 이런 차이가 있구나~~ 했었습니다. * 개인적으로는 이렇게 테이블에 옵션 때려박아두는 것 보다는 어노테이션(=데코레이터)을 여러개 사용하는 것이 낫다고 생각했습니다 */ @Id 와 @GeneratedValuehttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/idhttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/generatedvalue@Id @GeneratedValue(strategy = GenerationType.IDENTITY) // mysql auto_increment @Column(name = "report_id") /* column mapping */ var id: Long? = null /* spring에서 null로 보내면, DB에서 auto_increment */둘 다 엔티티 정의에서 기본키를 정의할 때 사용합니다. @Id는 말 그대로 기본키라는 것을 식별하기 위해 사용합니다. 함께 사용하는 GeneratedValue는, 기본키에 대한 생성 전략을 정의합니다. (전략 타입은 아래 표)https://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/generationtype이번 수업에서는 db 에 기본키 생성을 위임하는 GenerationType.IDENTITY 를 사용하였습니다. // Sequelize PK 정의 예시 @Column({ field: 'charge_id', primaryKey: true, autoIncrement: true, type: DataType.INTEGER, }) id: number; /* * 여긴 없지만 @PrimaryKey 라는 데코레이터가 존재합니다. @Id와 같은 역할을 할 듯,, * autoIncrement: true, 외에 다른 옵션이 없었는데, @GeneratedValue 는 컨트롤할수 있는 범위가 넓은 것 같아 좋았습니다. */ @Columnhttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/column@Column(name = "phone", nullable = false) /* column mapping */ var phone: String = phonename 은 말 그대로 물리 컬럼명을 이어주는 역할을 합니다. 사실 모든 경우에 대해, @Column을 해줘야 하는 줄 알았는데요, (DB에서 스네이크케이스, spring에서는 카멜케이스 )강의에서 "알아서 바꿔준다" 하고 슥 넘어간 거 같아 궁금해서 찾아보았습니다. By default, Spring Boot configures the physical naming strategy with CamelCaseToUnderscoresNamingStrategyhttps://docs.spring.io/spring-boot/how-to/data-access.html이렇게 스프링 부트에 내장되어 있는 전략에 영향을 받는 것으로? 우선 이해를 해 보았습니다.스프링이 참 딥해서,, 문서같은걸 뒤적거려도 확신이 잘 안서네요 ;ㅁ; nullable 은 default 가 true 이기 때문에 필요한 경우에만 명시해주면 됩니다!맨 위에 링크한 문서에, 각종 옵션들에 대한 default 가 나와있으니 개발할때 참고하면 좋을 것 같습니다.@Enumeratedhttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/enumerated@Enumerated(value = EnumType.STRING) var category: ReportType = ReportType.valueOf(category)말 그대로, enum 타입이어야 함을 명시합니다. (옵션은 아래 표) https://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/enumtype연관관계@ManyToManyhttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/manytomany다대다(n-m) 관계일 때 사용합니다.n-m 관계의 경우 아래 사진처럼 1-n / n-1 이렇게 분리하는게 약간 >국룰< 입니다.문서에서도 @Jointable 을 사용해 중간 테이블을 지정하라고 되어 있습니다.https://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/jointablemany-to-many는 정말 은근,, 사용할 일이 없었던 전적이 있어서 슥 넘어가겠습니다. @ManyToOne @OneToManyhttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/onetomanyhttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/manytoone@OneToMany( targetEntity = Post::class, fetch = FetchType.LAZY, cascade = [CascadeType.ALL] ) @JoinColumn(name = "user_id") var post: MutableList<Post> = mutableListOf()일대다 관계를 명시하는 어노테이션입니다. 관계를 맺고 있는 양쪽 테이블에 항상 모두 쓸 필요는 없고, 데이터가 필요한 부분에만 사용합니다. 이런 어노테이션의 경우 @OneToMany 앞(One)에 있는게 나고 타겟이 뒤(Many) 에 합니다.위 같은 코드가 User Entity 클래스 내부에 작성된 내용이라면, User(1) - UserTime(N) 입니다. 개인적으로 ORM의 관계는 요걸 헷갈리지 않는거부터 시작이라고 생각합니다..fetch 는 엔티티에서 항상 연관된 테이블의 정보를 가져올지 아닐지 선택합니다. (N+1 관련해서는 나중에 정리하겠습니다)cascade는 참조 무결성을 위한 키워드입니다. CascadeType.ALL 은 아래 표의 나머지들을 모두 적용하겠다는 뜻입니다.The value cascade=ALL is equivalent to cascade={PERSIST, MERGE, REMOVE, REFRESH, DETACH}.https://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/cascadetype // Sequelize 관계 정의 예시 // user 테이블 @HasMany(() => PostEntity) posts: PostEntity[]; // post 테이블 @BelongsTo(() => UserEntity) user: UserEntity; @OneToOnehttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/onetoone@OneToOne( targetEntity = UserTime::class, fetch = FetchType.LAZY, cascade = [CascadeType.ALL] ) @JoinColumn(name = "user_id") lateinit var timeInfo: UserTime일대일 관계를 명시할 때 사용합니다. user와 user가 사용한 시간인 userTime이 1-1 관계를 맺고 있는 경우의 예시입니다. // Sequelize 관계 정의 예시 // user 테이블 @HasOne(() => UserTimeEntity) userTime: UserTime; // userTime 테이블 @BelongsTo(() => UserEntity) user: UserEntity; @JoinColumnhttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/joincolumn조인의 기준? 되는 컬럼을 지정합니다. 프로젝트데이터베이스 관련해서 정의를 추가하였습니다. 근데 이번에 블로그 쓰면서 잘못 작성하고 그런걸 좀 찾아서 다시 해야할거같습니다. ....