기본적으로 하이디와 같은 툴에서 Mysql, Maria DB를 접근하여 쿼리를 날릴 때, 다중으로 delete, update, insert등을 처리 할 수 있다. mysql의 경우에는 구분자 ;(세미콜론)을 추가하여 DML 쿼리를 여러번 처리 할 수 있는데, 당연히 mybatis에서도 처리가 될 것이라고 생각하여 테스트 해봤지만 계속해서 문법 에러가 발생하였다.
확인을 해보니 Mybatis에 mysql연결을 할 때 옵션 설정이 필요하였다.
allowMultiQueries=true
allowMultiQueries 을 true처리해주고 DB를 연결해주면 다중으로 날려도 정상적으로 처리가 된다.
자바 소켓 프로그램 + 스케줄러로 구성된 프로세스를 실서버 운용중에 있었는데, 주말간 문제가 없었는지 확인해보니 주말사이에 스케줄러가 동작할때마다 에러를 뿜어내고 있었습니다.
[2020-07-18 11:00:00] ERROR (utils.SqlSessionUtils - selectList:92) - Exception
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.apache.ibatis.transaction.TransactionException: Error configuring AutoCommit. Your driver may not support getAutoCommit() or setAutoCommit(). Requested setting: false. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet successfully received from the server was 86,387,538 milliseconds ago. The last packet sent successfully to the server was 0 milliseconds ago.
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
at kr.or.kisa.ktoaInterlock.utils.SqlSessionUtils.selectList(SqlSessionUtils.java:90)
at kr.or.kisa.ktoaInterlock.dao.InterlockDao.selectYesterdayReportList(InterlockDao.java:95)
at kr.or.kisa.ktoaInterlock.scheduler.InterLockScheduler.execute(InterLockScheduler.java:40)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
와 같은 에러를 출력중이였는데...
DB는 mysql을 사용중이며 해당 스케줄러는 하루에 한번 돌도록 구성되어 있습니다.
에러 내용을 가지고 검색을 해보니, 너무 오랫동안 mysql을 사용하지 않고 있다가 갑자기 사용하려고 하면 발생하는 에러로 mysql에서 오랫동안 사용을 하지 않으니 강제로 종료해버리는 이슈라고 합니다.
기존 5버전대 mysql을 쓰다가 해당 구조만 가져올 일이 있어서 그대로 백업한 .sql파일을 복원 하는 과정에서 아래와같은 에러가 발생하였다.
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
함수 생성시 옵션 에러라고 하는데 버전이 올라가면서 기본값이 변경된 것 같다.
발생하는 에러로그를 토대로 검색해보니 함수 생성시 생성 제약처리를 할 수 있었고, 생성할 수 있는 부분이 OFF처리 되어있는걸 볼 수 있었다.
log_bin_trust_function_creators 옵션 확인하기
show global variables like 'log_bin_trust_function_creators';
해결방법 설치한 Mysql은 8버전대였고 아래의 쿼리를 실행 후 동일한 .sql파일 실행시 정상적으로 동작하였다.
SET GLOBAL log_bin_trust_function_creators = 1; //ON
#SET GLOBAL log_bin_trust_function_creators = 0; //OFF
1은 ON처리로 함수 생성을 시킬수 있다.
0은 OFF처리로 정상적으로 처리 후 다시 원복시 사용하거나 다른 사용자가 함수를 추가하지 못하도록 막을 수 있을것이다.
특정 문자열에 데이터가 ','를 기준으로 들어가고 개수는 3개까지 제한되어 들어가지만 1개가 들어갈지 2개가 들어갈지 비어있을지 모르는 상황에서 해당 데이터를 쪼개고 JOIN을 하던지 SubQuery를 날리던지 해야하는 상황이였다.
쉽게 설명하자면 위 그림과 같은 상황이였다.
각각 컬럼별로 쪼개어 넣으면 좋았겠지만, 기존 프로젝트 구조 설계도 이런 기능이 지원되지 않는 상황이였고 어거지로 집어넣었기때문에 개수는 3개제한인점을 활용하여 각각 특수문자를 비교하고 서브쿼리를 통해 처리하기로 하였다.
처리한 방법
1. 먼저 구분자값인 ','의 개수가 몇개인지 파악할 필요가 있었다.
SELECT
SUM((CHAR_LENGTH(column)-CHAR_LENGTH(REPLACE(column,',',''))+1))
FROM TABLENAME
해당 쿼리를 사용하면 특정 데이터의 특수문자나 문자열등의 개수를 체크할수 있다.
사용예시)
2. 다음 해당 개수에 따른 CASEWHEN문을 통해 비교후 SPLIT 하였다.
각각 SPLIT된 데이터의 이름값을 concat_ws메소드를 통해 문자열을 다시 합쳐주었다.
SELECT
CASE
SUM((CHAR_LENGTH(column)-CHAR_LENGTH(REPLACE(column,',',''))+1))
#1개라면 특정테이블에서 바로 조회해온다.
WHEN 1 THEN (SELECT columnName FROM R_FILEUPLOAD WHERE no = column)
#2개라면 ,기준으로 1개만 자른값을 비교하여 넣고
# 2번째까지 가져오고 문자열을 합치다.
WHEN 2 THEN (SELECT concat_ws(
','
,(select columnName from R_FILEUPLOAD
where no = SUBSTRING_INDEX(column, ',', 1))
,(select columnName from R_FILEUPLOAD
where no = SUBSTRING_INDEX(SUBSTRING_INDEX(column, ',', 2), ',', -1))
))
#3개라면 ,기준으로 1개만 자른값을 비교하여 넣고
# 2번째까지 가져오고
# 3번째까지 가져와서 문자열을 합친다.
WHEN 3 THEN (SELECT concat_ws(
','
,(select columnName from R_FILEUPLOAD
where no = SUBSTRING_INDEX(column, ',', 1))
,(select columnName from R_FILEUPLOAD
where no = SUBSTRING_INDEX(SUBSTRING_INDEX(column, ',', 2), ',', -1))
,(select columnName from R_FILEUPLOAD
where no = SUBSTRING_INDEX(SUBSTRING_INDEX(column, ',', 3), ',', -1))
))
END as REAL_NAME;
결과 데이터는 '테스트1,테스트2,테스트3' 의 형태로 처리되었다.
어쩔수 없는 상황에 임시대처로 해당방법을 사용하였고... 어지간하면 컬럼별로 쪼개어서 조인을 하는게 맞는것 같다...