여러명의 사용자가 동시다발적으로 데이터를 수정하는 경우 발생하는 문제점에 대해서 설명합니다.
1.예시
예시1) 상품 판매단가 등록 시
예를 들어 상품관리 페이지에서 관리자A가 item1의 판매단가를 1300원으로 수정하였고,
동시에 관리자B가 item1의 판매단가를 2000원으로 수정하였습니다.
item1의 단가를 1000원이라고 가정하였을 때,
관리자A는 판매이익을 300원으로 책정하여 계산하였고,
관리자B는 판매이익을 1000원이라고 책정하여 계산하였습니다.
이때 판매이익의 갭은 700원이 발생합니다.
2.해결방법
작업순서 : Data 조회 - 작업 - 저장
Data 저장시 기존 Data 조회한 최종 수정날짜와 현재 조회한 최종 수정날짜가 일치할 경우 update 하고 불일치할 경우 "Data 재조회 한 후 적용하세요." 라는 메세지를 출력할 수 있도록 합니다.
이때 발생하는 문제점이 있습니다.
신규 데이터 입력시 최종 수정날짜 데이터가 null 이므로 insert는 되지않고, 메세지만 출력하는 동작만 발생하여 신규 데이터를 등록할 수 없게 되는 문제점이 발생합니다.
이때 MERGE INTO 구문을 사용하여 해결할 수 있습니다.
key 가 있는 경우 update, key 가 없는 경우 insert 처리하여 기존 데이터 수정 또는 신규데이터 등록을 할 수 있습니다.
3.MERGE INTO(Oracle)
MERGE INTO [1.테이블명] -- UPDATE 또는 INSERT 할 테이블명
USING [2.조건 테이블명] -- 같은 테이블을 사용한다면 DUAL
ON [1과 2의 조건문] -- KEY 일치 여부
WHEN MATCHED THEN -- 일치하는 경우 UPDATE
WHEN NOT MATCHED THEN -- 일치하지 않는 경우 INSERT
3-1) 사용하는 경우
Key가 이미 할당되어 있는 경우 사용합니다..
3-2) 예시 : 달력 스케줄 관리
달력을 보면 스케줄 데이터가 없는 경우에도 날짜를 확인 할 수 있습니다.
달력에는 날짜별 Key가 할당되어 나타나는 형태입니다.
즉, 날짜를 선택(09/06)하여 스케줄을 입력하는 경우 key 값이 '20200906'이 되어 insert가 됩니다.
-- 달력
SELECT ym
, MIN(CASE dw WHEN 1 THEN d END) Sun
, MIN(CASE dw WHEN 2 THEN d END) Mon
, MIN(CASE dw WHEN 3 THEN d END) Tue
, MIN(CASE dw WHEN 4 THEN d END) Wed
, MIN(CASE dw WHEN 5 THEN d END) Thu
, MIN(CASE dw WHEN 6 THEN d END) Fri
, MIN(CASE dw WHEN 7 THEN d END) Sat
FROM (SELECT date_format(dt,'%Y%m') ym
, Week(dt) w
, Day(dt) d
, DayofWeek(dt) dw
FROM (SELECT CONCAT(y, '0101') + INTERVAL a*100 + b*10 + c DAY dt
FROM (SELECT 0 a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
) a
, (SELECT 0 b
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9
) b
, (SELECT 0 c
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9
) c
, (SELECT '2020' y) d
WHERE a*100 + b*10 + c < DayOfYear(CONCAT(y, '1231'))
) a
) a
GROUP BY ym, w
;
-- 스케줄
CREATE TABLE SCHEDULE
(
WORK_KEY CHAR(8)
, CONTENT VARCHAR(100)
, PRIMARY KEY(WORK_KEY)
)
-- TEST DATA 입력
INSERT INTO SCHEDULE
(WORK_KEY, CONTENT)
VALUES('20200906', 'TEST');
-- join
SELECT ym
, MIN(CASE dw WHEN 1 THEN d END) Sun
, MIN(CASE dw WHEN 2 THEN d END) Mon
, MIN(CASE dw WHEN 3 THEN d END) Tue
, MIN(CASE dw WHEN 4 THEN d END) Wed
, MIN(CASE dw WHEN 5 THEN d END) Thu
, MIN(CASE dw WHEN 6 THEN d END) Fri
, MIN(CASE dw WHEN 7 THEN d END) Sat
, CONTENT
FROM (SELECT date_format(dt,'%Y%m') ym
, Week(dt) w
, Day(dt) d
, DayofWeek(dt) dw
, CONTENT
FROM (SELECT CONCAT(y, '0101') + INTERVAL a*100 + b*10 + c DAY dt
FROM (SELECT 0 a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
) a
, (SELECT 0 b
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9
) b
, (SELECT 0 c
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9
) c
, (SELECT '2020' y) d
WHERE a*100 + b*10 + c < DayOfYear(CONCAT(y, '1231'))
) a
LEFT OUTER JOIN SCHEDULE s
ON date_format(s.WORK_KEY, '%Y-%m-%d') = a.dt
) a
GROUP BY ym, w;
결과
달력쿼리 : www.gurubee.net/article/65315
3-3) 단점
- 오라클에서만 사용가능합니다. : java에서 처리하거나 대체 SQL 문으로 처리
- 메모리 사용
4.MyBatis 사용예제
- MyBatis에서는 update 또는 insert 시 int 값으로 return 할 수 있습니다.
0일 경우 false, 0 초과인 경우 true를 적용하여 처리할 수 있습니다.
- select [컬럼명] from dual 사용 : 조건에 맞는 데이터만 select 하여 insert 하는 경우, java에서 조건처리하는 로직이 복잡할때 쿼리에서 간단하게 해결할 수 있습니다.
5.주의할점
업무 프로세스 계획을 잘 세워서 각 상황에 맞게 service 에서 처리할 지 SQL 로 처리할 지 판단해서 적용해야 합니다.
'Development' 카테고리의 다른 글
[Development] 프로그램 개발 순서 (0) | 2020.08.30 |
---|