개발 기록일지

[Mybatis/postgresql] foreach 를 통해 다중 insert/update 하기 본문

프로그래밍/Web 개발

[Mybatis/postgresql] foreach 를 통해 다중 insert/update 하기

JuoDev 2022. 2. 7. 18:09
  • INSERT

xml부분

<insert id="insertDev" parameterType="map">

	INSERT INTO 
	CH_DEV_INF(DEV_SEQ, CH_DEV_SEQ, DEV_MODEL_SEQ, MODL_CNT, CRETR, CRET_DT)
	VALUES
	<foreach collection="list" item="item" separator=",">
	(
	#{dev_seq}::NUMERIC
	,#{item.ch_dev_seq}
	,#{item.dev_model_seq}
	,#{item.combox_modl_cnt}::NUMERIC
	,#{cretr}
	,NOW()
	)
	</foreach>
	</insert>

 

 

 

controller 부분

@RequestMapping(value = "/equipmentRegister.do", method= RequestMethod.GET)
    public Map<String, Object> insertEquipmentInfo(@RequestParam Map<String, Object> param, DevComboxChModuleVO vo) throws Exception {
    	param.put("list", vo.getList());
    	System.out.println(param);
        return equipmentManageService.insertDev(param);
    }

 

insert 구문은 <insert></insert> 로 끝나게되고 controller 에서 지정한 반환형이 Map 이기때문에

parameterType="map" 으로 지정한다

 

이때 foreach 를 써서 list형태의 데이터를 받아 다중 insert 할때가 있는데

VALUES() 에 들어가는 부분을 위와같이 foreach 를 써서 처리해주면 된다.


이때 중요한부분은 collection="list"  처럼 설정하면 parameter 안에 "list"라는 key가 있어야한다.

그리고 foreach 구문에서 separator가 있는데 이부분은 foreach가 끝나는 부분마지막에 들어가는 구분자이다.

 

insert가 여러번 수행되므로 

아래와 같이 구분자가 들어가서 다중 insert가  수행되는것이다.

 

INSERT INTO 
CH_DEV_INF(DEV_SEQ, CH_DEV_SEQ, DEV_MODEL_SEQ, MODL_CNT, CRETR, CRET_DT)
VALUES(111,'123','123',5,'admin',NOW()),

VALUES(112,'1234','5123',5,'admin',NOW()),

VALUES(113,'1234','4123',5,'admin',NOW())


  • UPSERT

 

<insert id="updateDev" parameterType="map">

	<foreach collection="list" item="item" open="" separator=";" close="">
	INSERT INTO
	CH_DEV_INF(DEV_SEQ, CH_DEV_SEQ, DEV_MODEL_SEQ, MODL_CNT, CRETR, CRET_DT)
	VALUES
	(
	#{prev_dev_seq}::NUMERIC
	,#{item.ch_dev_seq}
	,#{item.dev_model_seq}
	,#{item.combox_modl_cnt}::NUMERIC
	,#{updtr}
	,NOW()
	)
	ON CONFLICT(DEV_SEQ,CH_DEV_SEQ)
	DO UPDATE SET
	DEV_MODEL_SEQ=#{item.dev_model_seq}
	,MODL_CNT=#{item.combox_modl_cnt}::NUMERIC
	,CRET_DT=NOW()
	</foreach>
	</insert>

 

이것도 기능적으로는 insert 부분인데 차이가 있다면

insert 할때 어떠한 조건에 의해 insert 가 안되는 상황이면 UPDATE를 하는 것이다.

 

MySQL 에서는 ON DUPLICATE KEY 를 사용하지만 

POSTGRESQL 에서는 ON CONFLICT / DO UPDATE SET 을 사용한다.

처음에 upsert 찾아보다가 on duplicate key가 있길래 그거 적용하는데 왜 안되나 해서 봤는데

자신이 사용하는 DB를 잘봐야한다...거기서 거기인줄 알았는데 차이가 있다 ㅠ

 

전체를 foreach로 묶었고 separator 구분자는 " ; " 설정해서 마지막에 ; 이 들어가서 쿼리가 동작하도록 해야한다.

 

ON CONFLICT() 부분에는

 

ON CONFLICT column_name : 특정 컬럼명을 기준으로 체크함(pk기준)

ON CONFLICT ON CONSTRAINT ~ : 테이블 생성시 만든 constraint명을 기준으로 체크

ON CONFLICT WHERE predicate : UNIQUE INDEX 생성 시 사용


위의 confilct 부분에서 충돌할경우 , 뭔가 조건에 안맞는경우 아래와 같은 동작을 수행하도록 할 수 있다.

 

DO UPDATE SET : UPDATE 동작

DO NOTHING : 아무것도 동작안하기

 

나같은 경우는 위와 같이 2개의 pk가 중복되면

해당 테이블의 3개의 컬럼을 list에 있는 값으로 update하도록 설정했다.

 

이렇게 하면 pk가 없으면 그냥 insert 하고 중복되면 update하도록 할 수 있다.

 

등록과정을 거치고 추후에 수정할때(사용자가 기존 값을 변경하거나 새로운 값을 추가할경우) upsert 를 사용한다.

아 그리고 찾아보니까 postgresql 9.5 이상부터 사용가능하다고 하니 버젼확인 잘해야한다.