일하면서, 테이블에 데이터가 없으면 insert 하고, 있으면 update 하는 동작이 필요한 경우가 생겼다. Oracle DB에서는 MERGE INTO를 사용하면 되고, Mysql에도 이와 비슷한 기능들이 있다.
INSERT IGNORE
REPLACE INTO
INSERT ... ON DUPLICATE UPDATE
위와 같은 3가지 문법이 비슷한 역할을 한다고 친다. 나는 마지막 3번쨰 문법을 활용했다.
먼저 테이블을 하나 만들어두자.
create table patient
(
pid int auto_increment primary key NOT null,
patientUserId varchar(100) not null unique,
firstname varchar(100),
lastname varchar(100),
gender int,
age int ,
height DOUBLE,
weight DOUBLE,
lastSession varchar(200),
comment varchar(300)
);
위와 같은 환자테이블이 있고, 두 개의 DB가 있다. A DB는 100개의 데이터가 존재하고, B는 150개의 환자 데이터가 저장되어있다.
내가 구현해야 되는 것은 먼저 클라이언트로부터 환자 정보 요청이 오면 100개의 데이터가 존재하는 A DB의 환자테이블을 조회하고 거기서 환자정보가 없으면, B DB로 넘어가서 환자 정보를 조회해 가져온 다음, 다시 A DB에 가져온 환자정보를 업데이트시키는 게 목적이다.
pid에 primary key 제약조건을 걸었다. 만약 같은 키를 insert하려면 duplicate key 에러가 뜰 것이다. 이걸 이용하는 게 3번째 문법이다.
https://soft.plusblog.co.kr/8
https://wakestand.tistory.com/454
Mysql에서 사용법은 아래와 같다.
INSERT INTO patient(pid, patientUserId, firstname, lastname, gender, age, height, weight, lastSession, comment)
values (80, 'patient80', 'GILDONG80', 'HONG', 1, 27, 180, 75, null, 'update Data' )
ON DUPLICATE KEY
UPDATE
patientUserId = 'patient80', firstname = 'GILDONG80', lastname='MIN',
gender = 1, age=27, height=180, weight = 75, lastSession= null, comment='update data' ;
만약 80이라는 키가 이미 있으면 업데이트하라는 간단한 명령어다.
public void insertOnDuplicateKeyUpdate(List<Patient> patients); //@Mapper 로 인터페이스 추상함수 메모리에 띄우기
<insert id="insertOnDuplicateKeyUpdate" >
INSERT INTO patient
(pid, patientUserId, firstname, lastname, gender, age, height, weight, lastSession, comment)
values
<foreach collection="list" item="item" index="index" separator=",">
(#{item.pid} , #{item.patientUserId}, #{item.firstname}, #{item.lastname}, #{item.gender}, #{item.age}, #{item.height}, #{item.weight}, #{item.lastSession}, #{item.comment} )
</foreach>
ON DUPLICATE KEY
UPDATE
patientUserId = values(patientUserId), firstname =values(firstname), lastname= values(lastname),
gender = values(gender), age=values(age), height=values(height), weight = values(weight), lastSession= values(lastSession), comment=values(comment)
</insert>
요런 식으로 만들 수 있다. values로 값을 불러온다는 게 특이한 점이다.
https://firstboos.tistory.com/entry/MySQL-insert-all-on-update-MyBatis-%EC%BF%BC%EB%A6%AC%EB%AC%B8
https://myhappyman.tistory.com/67
<foreach collection="list" item="item" open="(" close=")" separator=",">
#{item.authority}
</foreach>
<foreach collection="array" item="arr" open="(" close=")" separator=",">
#{arr}
</foreach>
public List<Members> getListTest(List<Members> chkList) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("chkList",chkList);
return sqlSession.selectList("getListTest", map);
}
<foreach collection="chkList" item="item" open="(" close=")" separator=",">
#{item.authority}
</foreach>
public List<Members> getAuthUserList(String[] userArray) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("userArray",userArray);
return sqlSession.selectList("getAuthUserList", map);
}
<foreach collection="userArray" item="arr" open="(" close=")" separator=",">
#{arr}
</foreach>
https://java119.tistory.com/85
@Slf4j
@ExtendWith(SpringExtension.class)
@SpringBootTest
public class IntegTest {
@Qualifier("MysqlPatientMapper")
@Autowired
private PatientMapper patientMapper;
@Qualifier("MysqlMeasureDataMapper")
@Autowired
private MeasureDataMapper mapper;
@Autowired
private net.lunalabs.central.mapper.oracle.PatientMapper oraclePatientMapper;
@Transactional //실제 DB에 값이 들어가지 않도록.
@Test
public void insertOnDuplicateKeyUpdateTest() {
HashMap<String,Object> map = new HashMap<String,Object>();
map.put("patientUserId", "110");
oraclePatientMapper.findByContainPatientUserId(map); //오라클 프로시저 호출
//log.info(map.toString());
List<Patient> bilabPatients = (List<Patient>)map.get("key"); //key가 out
log.info("확인... " + bilabPatients);
patientMapper.insertOnDuplicateKeyUpdate(bilabPatients);
List<Patient> list = patientMapper.findAll();
System.out.println("정상적으로 업데이트 되었는지.. " + list.size() + " :" + list);
}
List<Patient> patients = mysqlPatientMapper.findByContainPatientUserId(patientUserId);
//만약 patientUserId가 없다면, oracle DB에서 찾는 로직 추가
if(patients.isEmpty()) {
//약간 애매 포함하는 거라서 먼저 병원 DB에서 찾아야 될 것 같기도 하고.
HashMap<String,Object> map = new HashMap<String,Object>();
map.put("patientUserId", patientUserId);
oraclePatientMapper.findByContainPatientUserId(map); //오라클 프로시저 호출
//log.info(map.toString());
List<Patient> bilabPatients = (List<Patient>)map.get("key"); //key가 out
log.info("확인... " + bilabPatients);
//여기서 merge into
patientMapper.insertOnDuplicateKeyUpdate(bilabPatients);
}else {
addPatientsListAndWriteOut(patients, schn, sb, writeBuffer);
}