mysql (3)

💻 Programming

[MySQL] json 컬럼 업데이트 안되는 현상

mysql(AWS aurora aurora_version,2.07.1, innodb_version,5.7.12)에서 json 타입 컬럼을 지원하고 있고 json string을 저장해야할 일이 생겨 오랜만에 해당 타입으로 컬럼을 정의하여 사용했는데 컬럼의 내용이 업데이트가 안되는 현상을 확인했다. 문제가 생긴 데이터는 double 값을 포함하는 좌표데이터였다.

 

{"latitude": 24.4436779, "longitude": 116.35241670000043}

 

이런 데이터였는데 문제가 생긴 부분은 longitude 였다.

 

유닛테스트(java correto 11)에서 확인 시에 업데이트된 값이 제일 끝에 한자리가 바뀌어서 116.35241670000045 로 콘솔에 출력되었는데 jpa 업데이트 시 업데이트가 발생하지 않았다.

 

update일시 컬럼(timestamp)에 on update current_timestamp 설정이 되어있음에도 업데이트 일시가 변경되지 않았다.

 

쿼리를 아래와 같이 직접 날려도 마찬가지였다 -_-; 여기서 좀 멘붕;;

update location set coordinate = '{"latitude": 24.4436779, "longitude": 116.35241670000045}' where id=1;

jpa가 어떻게 쿼리를 날렸는지 확인해보니 직접 쿼리를 날린 것과 동일했다.

 

애초에 해당 데이터가 업데이트가 제대로 안되는 것을 확인했을 때 어차피 string으로 전달하기 때문에 double precision이 문제가 될거라는 생각은 없었으나, 구글링을 하면 할 수록 문제가 될만한건 double precision 밖에 없어보였다.

 

검색어를 좀 바꿔서 double precision 관련해서 찾아보니 double precision의 경우 16자리까지 ( . 제외하고 숫자만 셋을 때) 정확히 표한할 수 있다고 한다. 문제가 되었던 케이스는 총 17자리의 소수점이었고 따라서 마지막 자리수에 대한 정확도가 떨어지게 된 것이다.

 

해당 문제를 해결하려면 value의 타입을 double이 아닌 string으로 변경하여 저장할 필요가 있어보였으나, 좌표에 대한 자리수가 저렇게 긴게 맞는 것인지 확인해보니 좌표 데이터 저장시 8자리 이상은 노이즈값이라고 생각하고 저장할 필요가 없을것 같았다. -> 위키 참고

 

따라서 해당 이슈는 저장하는 쪽은 이슈가 없고 가져다 쓰는 쪽에서 잘 가져다 쓰면 될 문제였다.

 

오랜만에 야근했으나 또하나 알게된 것이 있어 기쁜 하루였다~

 

 

[참고내용]

stackoverflow.com/questions/49119871/mysql-json-stores-different-floating-point-value

 

 

자동으로 시작하는 mysql 데몬프로세스 강제종료

MySQL 8 버전(mysql-8.0.20-macos10.15)을 MacOS 10.14 (Mojave) 에 설치했다. 설치는 CE버전 dmg 파일을 다운받아서 했는데, 설치할 때 마지막에 인스톨 프로세스 종료 후 자동으로 MySQL을 시작할건지에 대한 체크를 해제하지 않고 finish했고, MAMP가 실행되지 않길래(팝업창이 뜨지 않길래) 애플리케이션에서 수동으로 실행을 시켰는데 nginx 서버만 뜨고 mysql 서버가 뜨지 않았다.

오랜만에 MAMP를 쓰려다보니 왜 안뜨는지 원인을 찾기가 힘들어서 정리해본다.

일단 mysql 서버의 로그를 확인해보려 했다. 로그 위치가 어디인지를 몰라서 그냥 find 명령어로 mysql*.log 파일을 찾으려했는데 안나온다 -_-; 그래서 구글링을 해봤더니 .err 확장자로 끝나는 파일이 MAMP 안에 log 디렉토리 안에 있었고(파일명은 mysql_error_log.err 이다) 해당 파일을 열어서 에러메시지를 확인했더니 해당 포트가 이미 사용중이란다. 오잉? 그럼 설치후에 실행이 됐다는 얘긴가??? 그래서 프로세스를 확인해보았다.

ps -ef|grep mysql

그랬더니 mysql 데몬이 이미 떠있다. 실행시킨 유저는 _mysql 이라고 되어있었고 이 프로세스를 끄고 다시 MAMP를 실행시켜서 mysql 서버를 띄우려고 kill -9 PID를 실행시켰는데 해당 프로세스는 꺼졌으나 다른 PID를 갖는 mysql데몬이 자동으로 실행이 되어있었다. ㅡㅡ;

뭐지?? 얘 좀비네? 다시 열심히 구글링을 해서 동일한 문제에 대해 설명을 잘 해놓은 미디엄 포스팅을 하나 찾았다. 바로 여기이다. 해당 사이트에서는 mysql-8.0.12-macos10.13 버전에 대한 설명이 있었고 내가 설치한 버전은 mysql-8.0.20-macos10.15 버전이었다. 아마 macOS 버전도 다르지 않을까 싶은데 아무튼 저 사이트의 설명대로 해도 해당 프로세스는 죽었다 살아나고 죽었다 살아나고를 반복했다.


그래서 좀 더 구글링을 하여 MySQL 공식 문서 중 MySQL launch daemon에 관한 문서를 보게 되었다. 해당 문서에는 아래와 같은 내용이 있었다.

2.4.3 Installing and Using the MySQL Launch Daemon
macOS uses launch daemons to automatically start, stop, and manage processes 
and applications such as MySQL.

By default, the installation package (DMG) on macOS installs a launchd file named 
/Library/LaunchDaemons/com.oracle.oss.mysql.mysqld.plist that contains a plist 
definition similar to:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" 
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>             <string>com.oracle.oss.mysql.mysqld</string>
    <key>ProcessType</key>       <string>Interactive</string>
    <key>Disabled</key>          <false/>
    <key>RunAtLoad</key>         <true/>
    <key>KeepAlive</key>         <true/>
    <key>SessionCreate</key>     <true/>
    <key>LaunchOnlyOnce</key>    <false/>
    <key>UserName</key>          <string>_mysql</string>
    <key>GroupName</key>         <string>_mysql</string>
    <key>ExitTimeOut</key>       <integer>600</integer>
    <key>Program</key>           <string>/usr/local/mysql/bin/mysqld</string>
    <key>ProgramArguments</key>
        <array>
            <string>/usr/local/mysql/bin/mysqld</string>
            <string>--user=_mysql</string>
            <string>--basedir=/usr/local/mysql</string>
            <string>--datadir=/usr/local/mysql/data</string>
            <string>--plugin-dir=/usr/local/mysql/lib/plugin</string>
            <string>--log-error=/usr/local/mysql/data/mysqld.local.err</string>
            <string>--pid-file=/usr/local/mysql/data/mysqld.local.pid</string>
            <string>--keyring-file-data=/usr/local/mysql/keyring/keyring</string>
            <string>--early-plugin-load=keyring_file=keyring_file.so</string>
        </array>
    <key>WorkingDirectory</key>  <string>/usr/local/mysql</string>
</dict>
</plist>

즉, mysql을 설치하면 /Library/LaunchDaemons/com.oracle.oss.mysql.mysqld.plist 파일에 위와 같은 설정 내용이 들어있다는 내용이었고 설정 항목들 중에 자동실행과 관련된 항목이 있을까 싶어 쭈욱 훑어보니 RunAtLoadLaunchOnlyOnce 항목이 눈에 띄었다.
일단 둘다 기본값과 반대로 설정하여 RunAtLoad 값은 false로, LaunchOnlyOnce의 값은 true로 수정해서 저장하고 다시 kill을 해보았다. (이 과정에서 재부팅을 했었는지 정확히 기억이 나지는 않는다;; 안했던것 같은데..^^; ) 그랬더니 더이상 자동으로 실행되지 않았고, MAMP를 실행시켜서 mysql 서버를 start하니 이제 잘 동작하는 것을 확인할 수 있었다.
 

도움이 되었다면 공감 꾸~~욱~~ 

MySQL의 auto_increment 값이 증가하는 시점

사내에서 테이블 데이터 수집을 위해서 테이블 만들 때 auto increment 컬럼을 pk로 추가해달라는 요청이 있어서 테이블 생성시 꼭 추가하고 있다. 그리고 그 auto increment 컬럼의 값은 실제로 데이터가 저장(insert)될 때만 올라갈 거라고 지레짐작만 하고 있었는데 이번에 어떤 서비스를 빨리 개발해줘야해서 새로운 테이블을 만들어 테스트하다가 auto increment값이 순서대로 올라가지 않는 현상을 보게되었다.

테스트코드는 insert -> select -> update -> select 순으로 동작하도록 구성했고 동일한 테스트를 최소 두 번 이상 돌렸다. 이렇게 돌리니까 처음에는 당연히 동일한 데이터가 없어서 no값은 default로 1로 생성이 되었다. 하지만 똑같은 테스트케이스를 다시 돌리면 duplicate key exception이 발생하면서 내부적으로 auto increment값이 증가하지 않을 줄 알았으나, 예외가 발생하여 데이터를 저장하지 못한다해도 insert가 시도될 때마다 no값이 증가하는 것을 확인할 수 있었다. auto increment값이 증가하는 케이스를 정리하자면 다음과 같다.

1. insert가 시도되면 no가 증가하게 된다.

2. duplication key 예외가 발생한다해도 증가하게 된다.

3. update시에는 증가하지 않았다.

일부 테이블은 많은 양의 insert on duplicate key update 문을 실행하고있는데 auto increment값이 overflow 되지 않을까 염려되어 현재 max no값을 조회해보니 아직 수 년은 버틸 수는 있을 정도였다.

만약 overflow 될정도로 많이 올라간다면 어떻게 해야할까 ??? no 값을 다시 1로 세팅하여 처음부터 시작하도록 할 수 있기는 하다. 아래 쿼리를 실행시키면 다시 1부터 세팅을 해준다.

ALTER TABLE YOUR_TABLE_NAME AUTO_INCREMENT=1;
SET @COUNT = 0;
UPDATE YOUR_TABLE_NAME SET AUTO_INCREMENT_COLUMN_NAME = @COUNT:=@COUNT+1;

하지만 해당 쿼리를 실행하는 동안 lock이 잡힐 것이라서 점검때에나 실행 할 수 있을 것이다.

이 방법 말고 직접 no를 세팅하는 방법도 있을 것 같다. 데이터 저장 시에 no값을 직접 할당해줄 수 있으니 말이다.