안녕하세요. 지식공유자 설동민입니다.
현재 카카오 백엔드 개발자로 근무하고 있으며, 복잡한 문제를 명쾌하게 풀어내는걸 좋아합니다.
경영학부 비전공자 출신으로, 다양한 OpenSource들에 대한 분석과 여러 기술적인 경험들을 통해
웹의 전반적인 기술을 학습하였습니다. OOP와 SQL, 이 어울리지 않는 두가지를 제일 좋아합니다.
Github: https://github.com/SightStudio
이력
2021. 12 ~ 현재 : 카카오 백엔드 개발
2020.12 ~ 2021.12: 전) 이스트소프트 백엔드 개발
강의
수강평
- 실전 jOOQ! Type Safe SQL with Java
- 실전 jOOQ! Type Safe SQL with Java
- 실전 jOOQ! Type Safe SQL with Java
- 실전 jOOQ! Type Safe SQL with Java
게시글
질문&답변
Routines 관련 질문
해당 질문은 우선 해결 처리해놓도록 하겠습니다. 만약 아직 해결되지 않았다면, 댓글로 답변주시면 마저 도움드릴수 있도록 하겠습니다.감사합니다 :)
- 1
- 2
- 58
질문&답변
Routines 관련 질문
lannn님 안녕하세요 사용 방언(dialect) 확인혹시 어떤 db와 함께 사용하시려는건가요?상용db (예를들어 오라클이나 MSSQL)을 사용하려면 라이센스를 구매하셔야합니다 연동 방식 확인testcontainer 없이 DDLDatabase로 사용하시면 H2 db기준으로만 dsl을 생성할 수 있습니다 아래 강의를 확인부탁드려요섹션 5. jOOQ 고급 - 다양한 방식으로 jOOQ DSL 만들기 추가로 궁금하신부분이 있다면 에러 로그도 같이 첨부 부탁드립니다
- 1
- 2
- 58
질문&답변
JOOQ 환경설정 중에 db 패스워드 관련 질문입니다.
안녕하세요. 임준용님우선 결론부터 말씀드리면 gradle 파일에 패스워드를 넣지 않고도 사용 할 수 있습니다. 개발 db를 직접 보고 DSL을 만드는 경우, 다음과 같이 gradle 파일이 아닌 외부에서 환경변수로db 비밀번호를 넣도록 처리 할 수 있습니다. 실무에서는 보통 vault hashicorp 같은 곳에 db 비밀번호를 저장하는데요.그 값 또한 gradle 파일에서 가져오게 처리하고 있습니다. String dbUser = System.properties["db-user"] ?: "root" String dbPasswd = System.properties["db-passwd"] ?: "passwd" jooq { configurations { testDB { generationTool { jdbc { driver = 'com.mysql.cj.jdbc.Driver' url = 'jdbc:mysql://localhost:3306' user = "${dbUser}" password = "${dbPasswd}" } } } // ...... } } 또한 개발(혹은 운영) DB를 직접 접근하지 않아도 DSL을 만들 수 있습니다.섹션 5. jOOQ 고급 - 다양한 방식으로 jOOQ DSL 만들기-> 해당 섹션 영상을 참고부탁드려요.
- 1
- 1
- 56
질문&답변
DB 벤더별 내장함수에 대한 방언 지원 듣고 질문드려요
이경용님 안녕하세요. 강의에서 MySQL의 경우 MySQLDSL.group_concant(), PostgreSQL의 경우 group_concat() 이렇게 적어놓았는데요. 실제로는 static import 되어서 PostgreDSL.group_concat() 이라고 보시면 됩니다. ㅎㅎ 그리고 MySQLDSL, PostgreDSL 이 둘 모두 DSL 클래스를 상속받기 때문에 사실상 DSL.group_concat() 과 동일하다고 보시면 됩니다 :) (사진)
- 1
- 1
- 97
질문&답변
인텔리제이 테마 질문
Jacob Lee 님 안녕하세요. 강의에서 사용된 테마는 이클립스 다크 테마 플러그인을 적용해서 사용하고 있습니다.https://plugins.jetbrains.com/plugin/11055-eclipse-dark-theme-color-scheme 예전에 이클립스에서 쓰던 다크테마를... 잊지 못해서 인텔리제이에서도 사용하고 있습니다🙂 감사합니다 ㅎㅎ
- 2
- 3
- 166
질문&답변
jooq로 auditing 구현하는방법
안녕하세요. 질문이 올라왔는지 몰랐네요 ㅎㅎ제 메일로도 받았던 질문인데 기록차 인프런에도 올려달라고 요청드렸던 글입니다. jOOQ RecordListener는 ActiveRecord 기반으로 동작합니다.아래의 코드는 ActiveRecord 기반으로 동작하지 않기때문에 이벤트 리스너가 트리거되지 않습니다. // RecordListener가 트리거되지 않음 fun insertUser(user: UsersRecord): Long? { return dslContext .insertInto( USERS, USERS.NAME, USERS.AGE, ).values( user.name, user.age ).returningResult(USERS.ID) .fetchOneInto(Long::class.java) } // RecordListener가 트리거됨 fun insertUser_record(user: UsersRecord): Long? { user.insert(); return user.getId(); } JPA처럼 영속성 컨텍스트 내에서 insert or update가 되는 형태를 원하신다면 ActiveRecord 내부에 DB 연동 상태가 있는데요. 이를 통해 처리 할 수 있습니다. JPA의 경우 엔티티 매니저가 영속성 컨텍스트 내에서 이 insert or update의 라이프사이클을 관리하지만 jOOQ는 영속성 컨텍스트 개념이 없기 때문에 ActiveRecord 객체 단위로 라이프사이클을 관리합니다. 이부분을 유의해서 적용 부탁드립니다. 이 부분 관련 질문이 몇번 들어와서 강의에 추가해놔야겠네요. 감사합니다 ~
- 1
- 2
- 121
질문&답변
FilmWithActor로 fetch 시 select와 생성자의 매개변수 순서가 다를 경우 map이 정상적으로 이루어 지지않는 케이스
하디님 안녕하세요 강의에서는 일부 row를 그룹핑해서 다른 객체로 만들 수 있다는걸 보여주기 위해서 위의 방식으로 소개했었는데요. 테이블 자체를 select하는 경우에는 Tables as SelectField 방식으로 처리하는것을 추천드립니다. 🙂 테이블 객체를 field로 사용하는 경우 아래와 같이 mapping 할 때 테이블 명으로 매핑할 클래스 필드명을 찾아서 매칭해주기 때문에 순서를 고려하지 않으셔도 됩니다. 예시 1) 위의 "Table as SelectField"를 사용한 경우 (사진) 예시 2) 강의의 DSL.row를 사용한 경우 (사진) 강의오픈 후에 이부분 설명이 아쉽다고 생각해서 강의노트에 추가했었는데요.이부분은 추후에 다른분들도 어떻게 잘 알 수 있을지 고민해보도록 하겠습니다. 테이블이 아닌경우 DSL.row()와 매퍼를 적절히 사용해주시면 됩니다.dslContext.select( DSL.row( FILM.FILM_ID, FILM.TITLE, FILM.DESCRIPTION ).mapping(SimpleFilmInfo::new) ) .from(FILM) .where(FILM.FILM_ID.eq(id)) .fetchOneInto(SimpleFilmInfoWrapper.class); // class SimpleFilmInfoWrapper { private SimpleFilmInfo simpleFilmInfo; }
- 1
- 1
- 109
질문&답변
from절 subquery table filed nullable 처리
안녕하세요. 어떤상황인지 정확히 파악이 안되서 답변드리기가 어려운데요.관련된 예시 코드나 사진이 있을까요?
- 1
- 1
- 130
질문&답변
kotlin mapping error
최종 정리본 안녕하세요. 이부분 조금 이해가 안가서 jOOQ 쪽에 이슈를 올렸었는데요.창시자 답변을 받아서 공유합니다. https://github.com/jOOQ/jOOQ/issues/17157 원인은 DefaultRecordMapper의 아래 두 옵션때문에 다르게 동작하는것으로 확인되었습니다.자바: isMapConstructorParameterNames (기본값: false)코틀린: isMapConstructorParameterNamesInKotlin (기본값: true) 해당 옵션은 생성자가 존재 할 경우 생성자의 변수명을 리플랙션으로 읽어서 sql의 alias와 매핑해주는 옵션입니다. 자바의 default 값이 false인 이유는 해당 옵션이 자바 8 이후 도입되어서 하위 의존성을 위해 false로 되어있기 때문에 그렇습니다. 다만 implicit path join 과 explicit path join은 이렇게되면 sql의 alias가 "alias_xxxx" 형식으로 나타나기 때문에 매핑이 안되고 에러가 발생하는 것이였습니다. (생성되는 SQL에서 확인 할 수 있습니다.) isMapConstructorParameterNamesInKotlin 옵션을 false로 처리하면 자바처럼 동작하겠지만,이 옵션을 켤지말지에 대한 판단이 필요합니다. (사실 코틀린이라면 이 옵션을 키는게 좋다고 생각합니다. 필드 선언부가 생성자와 같이 있기 때문에, 개인적인 의견입니다.) @Configuration class JooqConfig { @Bean fun jooqDefaultConfigurationCustomizer(): DefaultConfigurationCustomizer { return DefaultConfigurationCustomizer { c -> c.settings() // where 절 없이 delete, update 실행 금지 .withExecuteDeleteWithoutWhere(ExecuteWithoutWhere.THROW) .withExecuteUpdateWithoutWhere(ExecuteWithoutWhere.THROW) // -- 이부분 .withMapConstructorParameterNamesInKotlin(false) // implicit join 사용 금지 .withRenderImplicitJoinType(RenderImplicitJoinType.THROW) // schema 미포함 .withRenderSchema(false) } } } 만약 옵션을 키고 Explicit Path Join을 사용하고 싶다면 현재는 아래처럼 Path에 강제로 alias를 주시면 됩니다.fun findFilmWithActorsListLast(): List { val FILM_ACTOR = FILM.filmActor.`as`("filmActor") val ACTOR = FILM.filmActor.actor.`as`("actor") return dslContext .select( FILM, FILM_ACTOR, ACTOR, ).from(FILM) .join(FILM_ACTOR) .join(ACTOR) .fetchInto(FilmWithActor::class.java) } 창시자도 이부분이 애매한것같아 alias를 주지 않아도 되도록 개선해보겠다고 하니 지켜보면 될듯합니다. 감사합니다. (저도 이런 세팅이 존재하는지 몰랐네요 ㅎㅎ)https://github.com/jOOQ/jOOQ/issues/17170
- 0
- 4
- 405
질문&답변
R2DBC 관련해서 질문 드립니다.
안녕하세요. 인프런에 jOOQ 강의를 출시한 강사입니다.다른분들 질문 답변드리다가 이 질문이 보여서 슬쩍... 의견드리고 갑니다. 본 강의 강사님의 생각이 다르실 수도 있지만. 제가 생각하기엔jOOQ 자체가 생각보다 잘 알려지지 않은 기술이기 때문에 강의의 내용과 동떨어 질 수 있음jOOQ는 다른 데이터베이스 접근 기술보다 초기 세팅비용이 큼 (마찬가지로 이때문에 강의의 내용과 멀어질 수 있음) jOOQ도 R2DBC 환경에서 기존 기능의 100%를 지원하지 못함 (이 질문에서도 확인 할 수 있습니다.)이런 이유 때문에 사용 안하셨을것이라고 조심스럽게 의견드려봅니다. 감사합니다 🙂
- 0
- 3
- 400