MySQL 라이브러리 사용시 config.h 파일 문제

리눅스에서 빌드시 다음과 같은 오류가 있었다.

In file included from /root/DServer2/src/dserver/protocol/../../dserver/database.h:6:0,
from /root/DServer2/src/dserver/protocol/../../dserver/define.h:41,
from /root/DServer2/src/dserver/protocol/base_protocol.h:3,
from /root/DServer2/src/dserver/protocol/base_protocol.cpp:1:
/root/Library/mysql-connector-c++-1.1.9/cppconn/resultset.h:30:20: fatal error: config.h: 그런 파일이나 디렉터리가 없습니다
#include "config.h"
^

config.h 파일이 없다는 에러 메시지인데 cppconn 디렉토리를 살펴보면 config.h.cm 파일이 있다.

mysql 커넥터를 다운 받은 디렉토리로 가서 cmake를 실행한다. 실행이 되지 않는다면 yum 으로 cmake를 설치한다.

[root@localhost Library]# cmake mysql-connector-c++-1.1.9
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Could NOT find Boost
-- Could NOT find Boost
CMake Error at CMakeLists.txt:194 (MESSAGE):
Boost or some of its libraries found. If not in standard place please set
-DBOOST_ROOT:STRING=


-- Configuring incomplete, errors occurred!
See also "/root/Library/CMakeFiles/CMakeOutput.log".
[root@localhost Library]#

https://dev.mysql.com/doc/connector-cpp/en/connector-cpp-installation-source-unix.html 를 참조했다.

https://dev.mysql.com/doc/connector-cpp/en/connector-cpp-source-configuration-options.html 를 읽어봤더니 BOOST 경로를 설정해줘야한다.

/etc/profile 에 BOOST_ROOT 경로를 지정한다.

export BOOST_ROOT=/부스트경로/

다시 cmake를 실행했다.

[root@localhost mysql-connector-c++-1.1.9]# cmake .
-- Boost version: 1.65.1
-- BOOST_INCLUDE_DIRS=/root/Library/boost_1_65_1
-- You will link dynamically to the MySQL client library (set with -DMYSQLCLIENT_STATIC_LINKING=<bool>)
-- Searching for dynamic libraries with the base name(s) "mysqlclient_r mysqlclient"
CMake Error at FindMySQL.cmake:531 (message):
Could not find "mysql.h" from searching "/usr/include/mysql
/usr/local/include/mysql /opt/mysql/mysql/include
/opt/mysql/mysql/include/mysql /usr/local/mysql/include
/usr/local/mysql/include/mysql /MySQL/*/include /MySQL/*/include"
Call Stack (most recent call first):
CMakeLists.txt:252 (INCLUDE)


-- Configuring incomplete, errors occurred!
See also "/root/Library/mysql-connector-c++-1.1.9/CMakeFiles/CMakeOutput.log".
[root@localhost mysql-connector-c++-1.1.9]#

mysql 라이브러리 파일이 있어야한다고 나온다. CentOS 7에서는 MySQL이 빠지고 그대신 MariaDB가 들어가 있기 때문에 mariadb-libs 와 mariadb-devel 을 yum으로 설치해준다.

다시 cmake 하니…

[root@localhost mysql-connector-c++-1.1.9]# cmake .
-- Boost version: 1.65.1
-- BOOST_INCLUDE_DIRS=/root/Library/boost_1_65_1
-- You will link dynamically to the MySQL client library (set with -DMYSQLCLIENT_STATIC_LINKING=<bool>)
-- Searching for dynamic libraries with the base name(s) "mysqlclient_r mysqlclient"
-- mysql_config was found /usr/bin/mysql_config
-- MySQL client environment/cmake variables set that the user can override
--   MYSQL_DIR                   :
--   MYSQL_INCLUDE_DIR           : /usr/include/mysql
--   MYSQL_LIB_DIR               : /usr/lib64/mysql
--   MYSQL_CONFIG_EXECUTABLE     : /usr/bin/mysql_config
--   MYSQL_CXX_LINKAGE           :
--   MYSQL_CFLAGS                : -I/usr/include/mysql
--   MYSQL_CXXFLAGS              : -I/usr/include/mysql

(...중략...)

-- Configuring performance test - statement
-- Configuring bugs test cases - unsorted
-- Configuring unit tests - group template_bug
-- Configuring done
CMake Warning (dev) in driver/CMakeLists.txt:
  Policy CMP0022 is not set: INTERFACE_LINK_LIBRARIES defines the link
  interface.  Run "cmake --help-policy CMP0022" for policy details.  Use the
  cmake_policy command to set the policy and suppress this warning.

  Target "mysqlcppconn" has an INTERFACE_LINK_LIBRARIES property which
  differs from its LINK_INTERFACE_LIBRARIES properties.

  INTERFACE_LINK_LIBRARIES:

    mysqlclient;pthread;z;m;ssl;crypto;dl

  LINK_INTERFACE_LIBRARIES:



This warning is for project developers.  Use -Wno-dev to suppress it.

-- Generating done
-- Build files have been written to: /root/Library/mysql-connector-c++-1.1.9
[root@localhost mysql-connector-c++-1.1.9]#

이제서야 완료. config.h 파일이 정상적으로 생성되었다.

Redis 사용시 SET 이 에러나거나 Protected Mode 가 활성화 될 때 해결방법

Redis를 캐시서버로 쓰고자 했을 때 SET이 되지 않았다. GET은 되는데 SET만 안되는 특이한 현상.

레디스 클라이언트 라이브러리 제작자가 첨부한 예제도 작동하지 않아서 C++에서 발생한 에러메시지를 살피던 중 다음과 같은 에러 메시지를 발견했다.

SET error: DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command ‘CONFIG SET protected-mode no’ from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to ‘no’, and then restarting the server. 3) If you started the server manually just for testing, restart it with the ‘–protected-mode no’ option. 4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.

처음 보는 이 메시지에 당황해서 찾아보았다.

해결방법은 레디스 프로그램 파일에 첨부된 redis.conf 에 있었다. 이 파일에 보면 protected-mode 라는 환경설정 항목이 있고 이 항목의 값은 yes 로 되어 있다. 이 protected-mode 지시자가 무엇인지는 위에 주석에 자세히 써있다.

# Protected mode is a layer of security protection, in order to avoid that
# Redis instances left open on the internet are accessed and exploited.
#
# When protected mode is on and if:
#
# 1) The server is not binding explicitly to a set of addresses using the
# “bind” directive.
# 2) No password is configured.
#
# The server only accepts connections from clients connecting from the
# IPv4 and IPv6 loopback addresses 127.0.0.1 and ::1, and from Unix domain
# sockets.
#
# By default protected mode is enabled. You should disable it only if
# you are sure you want clients from other hosts to connect to Redis
# even if no authentication is configured, nor a specific set of interfaces
# are explicitly listed using the “bind” directive.

대략적인 내용은 보호모드라는 항목이 있으며 이것은 인터넷을 통한 접속과 부당한 이용을 막기 위함이라고 한다. 이 보호모드를 다음과 같은 경우에 켜라고 한다. 서버가 bind 지시어를 통해 바인딩되어 있지 않은 경우, 암호가 설정되지 않은 경우.

여튼 보호모드라는게 문제이니 이 문제를 해결하려면 두가지가 있는데 bind 지시어에 서버의 외부아이피 주소를 지정하거나 혹은 보호모드를 yes 에서 no 로 변경해주면 된다.

변경하고나면 SET이 잘되기 시작한다.

예전에 윈도우용 레디스 2.8 버전을 쓸 때 이러한 모드가 없었는데 최근 3.0 버전에 생긴건가…?

서로 다른 DB 머신에서 데이터 트랜잭션 처리

오랫만에 이곳에 글을 쓴다. 신입사원으로 지원시 열심히 썼었던 잊고 있던 오답노트를 다시 정리해본다. 경력이 3년이 넘었는데 아직도 이러한 문제조차 모르는 내 자신을 반성하며 다시 정리한다.

판교의 N 게임사에서 받은 질문.

Q. DB 머신이 물리적으로 서로 다른 머신일 때 어떠한 DB 작업시 트랜잭션 처리를 어떻게 하는가?

A. 하나의 단일 머신에서 처리해서 그러한 것에 신경 쓰지 못했다.

역시 정답을 말하지 못했다. 사실 이러한 처리가 필요하다는 것을 꽤 오래전에 인지했지만 실제로 해본적이 없어서 제대로 대답을 할 수 없었다. 실제로 3년간 했던 프로젝트들 전부 단일 DB 머신에서 처리했던게 사실이고.

다시 찾아본 정답은 다음과 같다.

출처 : 네이버지식인 (http://kin.naver.com/qna/detail.nhn?d1id=1&dirId=10205&docId=68228257)

MSSQL을 기준으로하며, 서로 링크드 서버로 연결되어 있어야 한다는 전제가 붙는다.

변경할 테이블에 트리거를 생성한다.

CREATE        TRIGGER dbo.트리거명 ON dbo.A서버테이블명
FOR UPDATE
AS

DECLARE @I_NO char(4) --변경 전
DECLARE @D_NO char(4) --변경 후

Select  @D_NO =NO --변경 전 값
From  DELETED

Select  @I_NO =NO --변경 후 값
From  INSERTED

--분산트랜잭션 처리(링크드 서버 UPDATE시 에러 없으면 에러 나는 경우가 존재합니다.)
SET XACT_ABORT ON

UPDATE [220.123.123.120].B서버DB명.DBO.B서버테이블명
SET NO = @I_NO
WHERE ID = @D_NO

SET XACT_ABORT OFF

결론적으로 문제의 해답은 변경할 테이블에 트리거 처리를 한다. 이고 그것을 위해 XACT_ABORT_ONXACT_ABORT_OFF 두개의 명령어를 사용해야한다는 것이다.

그렇다면 방금 처음 본 XACT_ABORT_ON/OFF가 도대체 뭔지 찾아보았다. 이에 대한 내용을 가장 잘 설명해준 글이 있었다.

http://fbshot.blog.me/80162695844

가장 중요한 차이점은 다음과 같다.

만약 프로시져 안에 INSERT 쿼리가 두개가 있는 상태에서 두번째 INSERT 쿼리에서 오류가 난다면,

  • XACT_ABORT_ON을 해놓으면 트랜잭션 안에 묶인 여러 쿼리 중 하나만 실패해도 전부다 실패처리하고 롤백한다.
  • XACT_ABORT_OFF일 때에는 첫번째 INSERT는 적용되고 두번째 INSERT 쿼리만 롤백한다.

이것을 이용해 배치쿼리에서 트랜잭션 처리에 대한 문제를 해결할 수 있다.

면접하면서 배치쿼리를 사용해봤냐는 질문도 받았는데 이 내용도 관련되어 있던 내용이었다.

배치쿼리와 트랜잭션에 대해 앞으로 잘 알아두어야 할 것 같다.

 

2016년 4월 4일 추가.

회사 동료 광연씨와 얘기해본 결과, 메시지큐나 웹서버 등의 미들웨어를 두고 여기에서 트랜잭션 처리를 하는게 더 좋지 않느냐는 결론에 이르렀다. 링크드서버로 연결된 DB를 이용해 트랜잭션을 이용하는 것은 적절하지 않은 해답일 것 같다. 메시지큐나 다른 미들웨어를 이용하여 이 문제를 해결하는 방법을 찾아보고 있다.

MSSQL 로그 파일 용량 줄이는 방법

개발용 MSSQL 서버를 사용하면서 로그 파일 용량이 점점 늘어갔다. 평소에는 별 상관 없는데 데이터베이스를 복사 떠가려고 하거나 백업할 때마다 엄청나게 많은 시간이 소요되니… 로그 파일이 무려 3기가가 넘었다. 그래서 로그 파일 용량을 줄였다. 데이터베이스 속성을 보면 다음과 같이 크기가 엄청나게 크다.

다음의 코드를 입력한다.

USE GameDB
SELECT DATABASEPROPERTYEX('GameDB', 'Recovery');
ALTER DATABASE GameDB SET RECOVERY SIMPLE
DBCC SHRINKFILE (GameDB_New_log, 10)
ALTER DATABASE GameDB SET RECOVERY FULL

쿼리 실행시 해당하는 데이터베이스에 가서 실행해야 하므로 USE를 한번 써준다. GameDB는 사용하는 데이터베이스 이름, GameDB_New_log는 로그 파일의 논리적 이름을 써주면 된다.

쿼리를 실행하면 몇초 걸리지 않고 굉장히 빨리 처리된다.

다시 데이터베이스 속성을 열어보면 다음과 같이 로그 파일 크기가 줄어있다.

JSP에서 MySQL 데이터 입력시 한글 깨질 때 처리법

로그 솔루션을 구축하던 중 JSP에서 MySQL에 데이터를  입력하다가 한글이 계속 깨졌다.

C++ 서버에서도 TCHAR로 한글을 처리하고 UTF-8로 맞추어 HTTP 전송했고, JSP 페이지들 모두 UTF-8 설정을 했고, JSP 파일 자체의 인코딩도 문제가 없었으며 request.setCharacterEncoding(“utf-8”); 코드도 입력된 상태였다.

이유를 몰라서 몇일을 헤메다가 해결방법을 찾았다.

MySQL 접속시 접속주소에 설정을 해주어야 한다.

나같은 경우 Commons 커넥션풀을 썼기 때문에 .jocl 파일 설정을 다음과 같이 변경했다.

<object class="org.apache.commons.dbcp.PoolableConnectionFactory" xmlns="http://apache.org/xml/xmlns/jakarta/commons/jocl">
<object class="org.apache.commons.dbcp.DriverManagerConnectionFactory">
<string value="jdbc:mysql://localhost:3306/log_conquest?useUnicode=true&amp;characterEncoding=utf-8" />
<string value="root" />
<string value="root_passwd" />
</object>
<object class="org.apache.commons.pool.impl.GenericObjectPool">
<object class="org.apache.commons.pool.PoolableObjectFactory" null="true" />
</object>
<object class="org.apache.commons.pool.KeyedObjectPoolFactory" null="true" />
<string null="true" />
<boolean value="false" />
<boolean value="true" />
</object>

중요한 부분은 MySQL 접속 주소를 쓸 때 뒤에 붙는 파라미터이다.

useUnicode=true&amp;characterEncoding=utf-8 을 붙여야만 정상적으로 UTF-8로 된 한글이 입력되게 된다.

WITH(UPDLOCK) 힌트와 MSSQL에서 락 해제하는 방법

MSSQL에서 의도치 않게 락이 걸리는 상황이 발생했다. 내가 만든게 아니니 뭐…

에러가 나는 프로시져를 찾아보니 UPDATE 쿼리에서 WITH(UPDLOCK) 구분이 있었다.

쭈기님의 블로그에 있는 글 (http://jjugi0606.tistory.com/30)에 의하면 이 힌트를 쓰는 경우, WHERE 검색에 들어가는 컬럼들은 인덱스 설정이 되어야만 한다고 한다. 그래서 인덱스를 일단 설정. 앞으로 또 락이 걸리는지는 두고봐야 알 수 있을 것 같다.

어찌됐던 MSSQL에서 걸려있는 락을 해제하기 위한 방법도 찾아보았다. 이 글 (http://yongandju.tistory.com/74)에서 방법을 찾았다.

EXEC sp_lock

명령어를 통해 락이 걸린 부분을 찾는다. (Mode 부분이 X 표시가 된 것이 락이 걸린 것이다.)

dbcc inputbuffer(해당 spid)

를 입력해서 어떤 쿼리에서 락이 걸렸는지 확인한다.

kill 해당spid

를 입력해서 강제종료시킨다.

어찌됐던 위 과정을 통해서 락은 해제되었다.

MySQL에서 현재 시간 자동 입력 방법

MySQL에서 현재 시간을 구하고 자동으로 입력하려면 다음의 쿼리를 이용한다.

INSERT INTO time_test VALUES ((SELECT NOW()));

로그 정보를 DB에 입력할 때 유용하게 사용했다. 아예 컬럼 기본값으로 함수를 지정하는 방법이 있지 않을까 싶은데 나중에 한번 찾아봐야할듯.

출처 : http://blog.naver.com/yoonhok_524?Redirect=Log&logNo=60170357042

CentOS에 FreeTDS 설치하기

Step 1. 소스 다운로드

http://www.freetds.org 에서 FreeTDS 소스를 받는다.

Step 2. 압축 해제

다음의 명령으로 압축을 푼다.

gunzip freetds-stable.tgz

압축을 풀면 tar 파일이 하나 나온다. tar xvf 명령으로 압축을 해제한다.

tar xvf freetds-stable.tar

Step 3. 컴파일

압축 해제가 되면 freetds 폴더가 나오는데 여기에 들어가서 컴파일을 시작한다. configure / make / make install 명령으로 실행한다. 난 소스 설치할 때 위치를 지정해서 설치하는 편이라 –prefix 로 위치를 지정했다.

[dongbum@localhost freetds-0.91]$ ./configure --prefix=/usr/local/FreeTDS --enable-msdblib
[dongbum@localhost freetds-0.91]$ make
[dongbum@localhost freetds-0.91]$ make install

실행을 다 하고 나면 /usr/local/FreeTDS 에 freetds 관련 파일들이 설치된다.

Step 4. 라이브러리 파일 경로 설정

/etc/profile 에 LD_LIBRARY_PATH에 freetds의 라이브러리 파일들을 연결해준다. /etc/profile 파일을 vi로 연다음 다음처럼 추가한다.

LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/FreeTDS/lib

설정이 적용되도록 재부팅을 한번 해준다.

Step 5. odbc.ini 파일 수정

/etc/odbc.ini 파일에 내가 사용할 DB의 이름을 설정해준다. 내 경우에는 freetds 외에도 sqlite 설정도 같이 추가하였다.

[dongbum@localhost log]$ cat /etc/odbc.ini
[111.222.333.444]
Driver = FreeTDS
Description = 111.222.333.444
Trace = No
Servername = 111.222.333.444
Database = 기본DB이름

[TEST_SQLITE3]
Description = TEST SQLITE
Driver = SQLite
Database = /test/sqlite/test_sqlite.db
StepAPI = NO

Step 6. odbcinst.ini 파일 수정

/etc/odbcinst.ini 파일에도 다음과 같은 설정을 추가해준다. 역시 SQLite를 사용하기 위한 설정도 추가하였다.

[FreeTDS]
Description = v0.64 with protocol v4.2
Driver = /usr/lib64/libtdsodbc.so
UsageCount = 5

[SQLite]
Description = ODBC for SQLite
Driver = /usr/local/lib/libsqlite3odbc.so
Setup = /usr/local/lib/libsqlite3odbc.so
FileUsage = 1
CPTimeout =
CPReuse =

/usr/lib64/libtdsodbc.so 파일은 /usr/local/FreeTDS/lib/libtdsodbc.so 파일을 향하도록 심볼릭링크를 걸어준다.

Step 7. freetds.conf 파일 수정

마지막으로 freetds.conf 파일을 수정해준다. 난 /usr/local/FreeTDS에 설치하였으므로 /usr/local/FreeTDS/etc/freetds.conf 파일을 수정해주면 된다.

[global] 섹션에

client charset = EUCKR
text size = 4290000000
tds version = 4.2

를 추가한다. 캐릭터셋과 tds 버전 등을 지정하는 문구 같은데 이 옵션에 대해 정확히는 나도 잘 모르겠다. 그리고 아까 추가한 서버이름을 그대로 추가해준다.

[111.222.333.444]
host = 111.222.333.444
port = 1433
tds version = 8.0

여기까지 다 설정하고나면 FreeTDS 사용이 가능하다.

리눅스에서 MSSQL 접속이 쉬운게 아니란걸 다시 한번 느낀다.