Tiny Star

분류 전체보기 71

[쿠폰] 쿠폰 조회 (Redis 예외처리)

couponId에 따른 재고 조회하는 API (자세한 내용 Git Issue 참고) 1. 요구사항1. 목적Redis에 coupon:{couponId}:stock 형식으로 재고를 등록한다. 2. 작업 내용POST /api/admin/coupons요청 파라미터:couponId (Long, 필수) : 쿠폰 IDquantity (int, 필수) : 초기 재고 수량ttlSeconds (int, 선택) : 재고 만료시간(초 단위), 미지정시 무제한 유지 3. 요청/응답 예시요청POST /api/admin/coupon{ "couponId": 123, "quantity": 100, "ttlSeconds": 86400} 응답{ "couponId":13, "stock":100} 2. 작업 내용//..

프로젝트/쿠폰 2025.04.28

[쿠폰] 쿠폰 생성 (@Transactional, CustomException)

쿠폰 정보를 받아서 DB에 저장하고 Redis에도 올리는 작업을 했다. (자세한 내용은 Git Issue 참고) 1. 요구사항1. 목적쿠폰 등록 시 DB와 Redis를 일관성 있게 관리하기 위해 등록 흐름을 명확히 분리한다.쿠폰 정보를 먼저 DB에 저장하고, 생성된 coupon_id를 기반으로 Redis에 재고를 등록하는 프로세스를 구현한다. 2. 작업 내용쿠폰 종류 등록 API 구현POST /api/admin/coupons API 생성쿠폰 이름(name), 총 수량(total_quantity) 등을 받아 DB에 저장저장 후 생성된 coupon_id를 반환쿠폰 재고 Redis 등록반환된 coupon_id를 사용하여 Redis에 coupon:{coupon_id}:stock으로 재고 등록필요 시 TTL(만..

프로젝트/쿠폰 2025.04.28

[Spring] @Transactional 트랜잭션 어노테이션

쿠폰 프로젝트를 진행하면서 사용하게 된 어노테이션이다. [클라이언트 요청] ↓POST /api/admin/coupons ↓[CouponService] ↓1. couponsRepository.save(coupon) 실행 ↓2. RedisTemplate 재고 등록Redis에 재고 등록을 하게되는데, 만약 이 때 오류로 Redis 등록에 실패했다면 DB에 저장된 데이터도 삭제하는게 좋다고 판단했다. 왜냐면 실패했을 시 똑같은 쿠폰을 다시 발행할텐데, DB 에는 동일한 이름의 쿠폰이 두 개가 등록되기 때문이다. 1. @Transactional@Transactional은 메서드 실행을 하나의 트랜잭션 단위로 묶어서,전체가 성공하면 커밋(commit),중간에 실패하면 롤백(rollback) 하게..

IT 2025.04.28

Redis란?

공고보면 기술 스택에 Redis가 있는 경우를 왕왕 봤다.전 실무에서는 대용량데이터를 넣고 통계돌리는 일이 과반수였기 때문에 Redis를 사용할 일이 없었다.그래서 개인 프로젝트하면서 사용할건데, 막상 Redis 에 대해 자세히 알지 못해서 찾아서 정리해보려고 한다. 1. Redis 란?Remote Dictionary Server의 약자로 메모리 기반의 Key-Value 저장소이다.대표적인 In-Memory DataStructure Store로 데이터가 RAM에 저장되어 매우 빠른 읽기/쓰기 속도를 제공한다.RAM 사용으로 인한 단점은 없을까?- 비용 문제: 디스크에 비해 비싸기 때문에 대용량 데이터를 저장하려면 비용이 많이 든다.- 용량 한계: 디스크보다 훨씬 작기 때문에, 너무 많은 데이터를 넣..

IT 2025.04.28

[쿠폰] Redis 선착순 쿠폰 시스템

Redis를 사용하여 선착순 쿠폰 시스템을 만들어보기로 했다.쿠폰에 초점이 맞춰진만큼 로그인 기능 등은 안넣고 오로지 쿠폰 발급만 구현하려고 한다. 🎯 시스템 구성 목표로그인 없이 (단, userId는 요청에 포함)선착순 쿠폰 발급쿠폰 재고는 Redis로 관리쿠폰 발급 결과만 DB에 저장빠른 응답 최우선 ✅ API 설계 구분 내용 MethodPOSTURL/api/coupons/issue요청 Body{ "userId": "string", "couponId": "string" }응답성공: { "success": true, "message": "쿠폰 발급 성공" }실패: { "success": false, "message": "쿠폰 소진" } ✅ ERD 설계[Coupon] (쿠폰 종류 관리 테이블)-..

프로젝트/쿠폰 2025.04.28

[반려동물 프로젝트] 마무리

서비스 고민에서 구성했던 페이지에서 변경이 있다. 추가할 페이지RFID 통계품종 분포도 -> 지역별 대표 품종과 겹치므로 제거New! 연도별 등록 추이소개 나머지 페이지는 기존이랑 큰 차이가 없어서 어제 새벽에 한 페이지, 방금 남은 작업을 끝냈다. 최종 페이지소개 우리 지역 견종과 묘종은? RFID 비율 연도별 등록 추이 github code 는 [여기]에서 확인할 수 있다. 간단한 프로젝트를 끝내며그다지 어려운 프로젝트가 아니었다. 오히려 쉬웠다고 볼 수 있다.이런 쉬운 프로젝트를 뭐하러 하냐고 할 수 있다. 실무에서 썼던 툴은 잘 다룬다고 할 수 있지만, 다르게보면 다른 툴은 못한다라고 볼 수 있다. MyBatis 대신 JPA를 사용하고, JPA 속에서 복잡한 쿼리를 어떻게 할지 고민하다가..

[반려동물 프로젝트] 백엔드 수정 (SpringCache)

백엔드 수정 사항region 캐시species 캐시dog/cat List 말고 다른 방식 구현QueryRepository = Service 역할 분리 region + sepecies 합쳐도 50개도 안되기 때문에 Spring Cache를 사용하려고 한다.대용량이거나 이벤트성이었으면 Redis와 Kafka를 고려했을텐데, 전혀 아니니..다음엔 다른 성향의 프로젝트로 위 캐시를 써봐야겠다. 캐시@EnableCaching // 추가@SpringBootApplicationpublic class PetstatsApplication { public static void main(String[] args) { SpringApplication.run(PetstatsApplication.class..

[반려동물 프로젝트] 프론트 구현 (Mustache)

프론트는 JSP 로 하려고 했으나, 뷰에서는 백엔드와는 완전히 분리되는게 좋을 것 같다.(경험을 위한 JSP 는 다른 프로젝트에서 해보는 걸로...) JSP vs Mustache vs Thymeleaf 항목 JSP Mustache Thymeleaf 템플릿 문법자바 코드 삽입 가능 ()순수 템플릿, 로직 없음HTML 태그에 속성(th:)으로 표현문법 표현력강력하지만 복잡단순, 제한적 ({{#each}})풍부하고 직관적 (th:if, th:each)HTML 정합성❌ 깨질 수 있음 (스크립틀릿 등)⛔ HTML로 직접 열면 깨질 수 있음✅ HTML로 열어도 유효한 마크업성능/속도느림 (JSP 컴파일 필요)빠름 (경량 템플릿)중간 (HTML DOM 기반)유지보수성❌ 로직 섞이기 쉬움✅ 표현만 담당, 구..

[반려동물 프로젝트] 백엔드 구현 (QueryDSL)

화면으로 보낼 데이터를 작업하려고 한다.서비스 고민할 때 가장 첫 번째로 떠올렸던 '지역별 대표 품종' 쿼리부터 작업해보자. 의존성 설정val queryDslVersion = "5.0.0"dependencies { implementation("com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta") annotationProcessor("com.querydsl:querydsl-apt:${queryDslVersion}:jakarta") annotationProcessor("jakarta.annotation:jakarta.annotation-api") annotationProcessor("jakarta.persistence:jakarta.pers..

[반려동물 프로젝트] DB 구성 (JPA, Python)

쿼리해서 프론트로 보내주기만하면 되기 때문에데이터만 잘 셋팅해두면 그 이후에는 간단할 거라고 생각한다.(프론트 빼고...) DTO 생성 가장 먼저 JPA 를 사용해 테이블을 생성한다. (참고)테이블은 초기에 생각했던 테이블 구성으로 진행했다. 데이터 삽입 API가 업데이트되고 있는지 의심스럽기 때문에일단은 파일을 다운로드해서 데이터를 넣기로 했다. import pandas as pdfrom sqlalchemy import create_enginedef get_engine(db_info): return create_engine(f"mysql+pymysql://{db_info['user']}:{db_info['password']}@{db_info['host']}:{db_info['port']}/..

top