도커데스크탑만 켜둔 상태 (참고로 cli로 하면 desktop켜고 싶어도 colima끈상태로는 접속안됨)
❯ docker exec -it mysql-container bash
bash-4.4# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \\g.
Your MySQL connection id is 15
Server version: 8.0.33 MySQL Community Server - GPL
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.
mysql>
접속 성공!
도꺼데스크탑 껐음
데이터베이스 서버 죽어서 연결끊김
결론
나는 Colima를 통한 도커 환경과
도터 데스크탑 환경 이렇게 두가지 환경을 구축해놨었다.
mysql 계정 설정했던 환경은 도커 데스크탑 환경이었어서 colima를 통해 띄운 도커 컨테이너로는 접속이 안되었던 것이다.
@Select("SELECT * FROM Clothes where userCloset_id = #{UserClosetId}")
List<Clothes> selectClothes(@Param("UserClosetId") int userClosetId);
{
"status": "BAD_REQUEST",
"exceptions": [
"Error attempting to get column 'id' from result set. Cause: java.lang.IllegalArgumentException: No enum constant com.favorite.project.ClothesCategory.ClothesCategoryEnumType.4"
],
"message": "매핑 실패"
}
No enum constant 찾아보니 DB에서 가져온 값을 객체화하려고 보니
enum타입에 없어서 생기는 문제라고 한다
즉, enum타입에 없는 값이 DB에 있다는 것..
이넘상수객체를 필드로 참조하고 있는 환경과
외래키로 값을 참조하고 있는 데이터베이스 환경을 어떻게 맞춰줄까라는 고민에 빠졌다.
사실상 문제의 시작은
옷장에 옷Clothes를 넣을 때부터 시작되었다.
서비스 단에서 데이터 삽입 시에
public int getClothesCategoryId(ClothesCategoryEnumType clothesCategoryEnumType) {
int idByCategoryName = categoryMapper.selectCategoryIdByCategoryName(clothesCategoryEnumType.name());
return idByCategoryName;
}
이렇게 clothes 테이블에 clothes_categoryid를 enum인 카테고리 이름으로
clothes_category테이블에 있는 id값을 찾아서 값을 넣었는데
이제 clothes 테이블 값을 전체 가져오려고 하니까 문제가 생긴다.
가져온 clothes_categoryid값은 enum 객체에는 없는 값이고 clothes_category테이블을 거쳐서 그 상수값이 들어와야하기 때문이다.
enum 하나 때문에 매핑에 실패해서 다른 값들을 못불러오고 있어서
문제되는 enum값 제외하고 호출해보았다.
(이래가지고 select * from말고 필요한 데이터 선언해서 불러와야 문제점을 파악하기 쉽겠다는 깨달음도 얻었다.)
Clothes테이블에서 sql타입이 카테고리 id가 int로 선언한 dto 객체에
매핑하기 위해서 SQL문과 매핑하는 객체를 다음과 같은 형식으로 바꾸면 값이 가져와진다
@Builder
@Getter
public class ClothesPriceAndImgAndPurchasedDate {
private int id;
private int clothesCategoryEnumType; //이렇게 int값으로
private int price;
private String img;
private LocalDate purchasedDate;
}
옷장에 옷 데이터 삽입할 때는 어떻게 했을지 코드를 보자면,
나는 이러한 객체와 데이터베이스의 다른 구조를 어떻게 해결해야될지 몰라서
id를 세터로 직접 지정하는 선택을 했는데 이게.. 이게.. 맞아?
@Builder
@Getter
public class Clothes {
private ClothesCategoryEnumType clothesCategoryEnumType;
private SeasonType seasonType;
private int price;
private String imgUrl;
private LocalDate purchasedDate;
@Setter
private int categoryId;
//TODO: 세터로 박지 말고 다른 방법 찾기
@Setter
private int userClosetId;
}
ClothesService 클래스
public ClothesResponseDto addClothes(ClothesAddDto clothesAddDto) {
Clothes clothes = clothesAddDto.toClothes(clothesAddDto);
boolean checkValidClosetResult = checkValidCloset(clothes);
if (checkValidClosetResult) {
//이넘타입 이름 가져와서
ClothesCategoryEnumType categoryEnumType = clothes.getCategoryName();
//카테고리 테이블에서 검색해서
int clothesCategoryId = clothesCategoryService.getClothesCategoryId(categoryEnumType);
//그 id로 카테고리 id값을 넣고 있구나
clothes.setCategoryId(clothesCategoryId);
clothesMapper.insertClothes(clothes);
return clothes.toClothesResponseDto(clothes);
} else {
throw new IllegalArgumentException("유효한 옷장이 아닙니다");
}
}
내가 원하는 것은 객체지향적인 프로그래밍이다.
목표:
밖에서 clothes의 clothesCategoryId를 함부로 설정할 수 없게 객체 내부에서 알아서 처리해줬으면 좋겠다.
ClothesCategoryEnumType객체 내에서
상수타입 → id로 변환해서 SQL문에 적용하면 어떨까 생각해봤다.
그러면 상수타입을 Clothes_category 테이블에서 조회해서 id를 가져와 보내줘야 하지 않을까 싶어
지금처럼 카테고리 id값을 객체에 설정해주었다.
id값을 직접 설정하는 것이 유연하지 않은 코드라고 느껴졌다. 그럼에도 id를 추가했던 이유는 상수타입 TOPS들고 카테고리 테이블을 다시 조회해서 id값을 들고 오기 위해 sql요청을 두 번하는 것보다는 상수객체에서 관리하는 게 낫겠다는 생각이 들어서였다.
이제 카테고리타입을 알면 그 카테고리id를 알 수 있게 되었다.
public enum ClothesCategoryEnumType {
TOPS(1, "상의"),
PANTS(3, "하의"),
OUTERWEAR(4, "겉옷"),
ACTIVE(9, "활동복");
private int clothesCategoryId;
private String clothesCategoryName;
ClothesCategoryEnumType(int clothesCategoryId, String clothesCategoryName) {
this.clothesCategoryId = clothesCategoryId;
this.clothesCategoryName = clothesCategoryName;
}
public static String getClothesCategoryName(int clothesCategoryId) {
for (ClothesCategoryEnumType type : values()) {
if (type.clothesCategoryId == clothesCategoryId) {
return type.clothesCategoryName;
}
}
return null;
}
}
그런데 계속 막히는 지점들이 있다.
데이터 조회시 특정 옷장의 모든 옷들을 가져온다.
조회마다 다른 api를 작성해야하는 걸까? (결론은 yes)
Clothes 도메인으로 값을 모두 가져온다음에
사용할 데이터만 다른 dto로 담아서 컨트롤러에 응답하면 되려나? ( 결론은 쿼리매핑하는 dto객체를 별도로 만들어서 사용했다 )
위에도 언급했지만 지금 내 프로젝트는 JPA를 사용하고 있지 않기 때문에
데이터베이스 테이블과 매핑하는 entity개념이 빠져있다. 그래서 더 헷갈렸었다.
1. setter제거하기
setter를 제거하고 어떻게 id값을 설정할지는
Clothes 빌더로 생성할 때 설정하는 것으로 해결하였다.
서비스단에서
이름을 가져와서 id를 찾았던 코드
id값을 따로 설정했던 코드를 삭제했다
2. SQL문과 매핑할 객체 만들기
데이터 조회 수정하려는데 객체와 mysql문 매핑할 때
객체 필드와 컬럼 순서가 맞아야했다!!! 사용하지 않는 필드도 들어가있으면 컬럼을 가져오지 못했다!)
{
"status": "BAD_REQUEST",
"exceptions": [
"Error attempting to get column 'price' from result set. Cause: java.lang.IllegalArgumentException: No enum constant com.favorite.project.Clothes.SeasonType.500.00"
],
"message": "매핑 실패"
}
쿼리와 매핑하는 객체
@Builder
@Getter
public class ClothesListDto {
private int id;
private int userClosetId;
private int clothesCategoryEnumTypeId;
private int price;
private String img;
private LocalDate purchasedDate;
private SeasonType season;
}
(참고로 애드몹 계정 생성할 때 개인/법인 잘 선택해야함. 계좌 유형에서 개인에서 법인으로 바꾸고 싶었는데 안되어서
삭제하고 다시 만듦...유형 바꿀 수 없다고 해서!!!)
3. 애드몹 계정 생성 후 앱 ID 받아서 app.json파일에 넣기
앱추가하기: 앱 > 앱 추가
앱 ID 받아오기 : 앱> 앱 설정 > 앱 ID
4. SKAdNetwork를 활성화하여 전환 추적(iOS) "Google 모바일 광고 SDK는 IDFA를 사용할 수 없는 경우에도 Google 및 참여하는 제3자 구매자가 앱 설치를 기여할 수 있는 Apple의 SKAdNetwork를 사용하여 전환 추적을 지원합니다. 프로젝트 app.json 파일 내에서 50개의 필수 SKAdNetwork 식별자를 추가합니다."