MYSQL 에서 ORACLE 의 MERGE INTO 기능 - Mybatis 연동

공부는 혼자하는 거·2021년 9월 8일
0

DB

목록 보기
4/7

목적

일하면서, 테이블에 데이터가 없으면 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이라는 키가 이미 있으면 업데이트하라는 간단한 명령어다.

Mybatis와 연동


	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 사용법

  • 리스트 파라미터를 직접 넘겼을 경우
<foreach collection="list" item="item" open="(" close=")" separator=",">
 #{item.authority}
</foreach>
  • 배열 파라미터를 직접 넘겼을 경우
<foreach collection="array" item="arr" open="(" close=")" separator=",">
 #{arr}
</foreach>
  • 리스트 Map을 통해 넘겼을 경우
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>
  • 배열 파라미터를 Map을 통해 넘겼을 경우
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);	
			}



profile
시간대비효율

0개의 댓글