2019년 4월 15일 월요일

mysql http post json 전송 트리거

mysql http post json 전송 트리거


테이블에 값이 insert 되면 trigger를 이용하여 http post를 전송하도록 한다.
mysql 자체적으로는 해당 기능을 지원하지 않는다.

검색해 보니 mysql의 UDF(user define function)를 이용하여 만들어진 mysql-udf-httpmysql-udf-http lib가 있다.


근데 최근 업데이트 2013년이다. 찜찜한 면이 있지만, 소스를 살펴보니 별 거 없다.
libcurl을 이용하여 http 전송해 주는 c로 짠 플러그인이다.



소스를 서버에 받은 후 압출을 풀고 컴파일 하면 된다.
문서상으로 되어 있는 설치가이드는 mysql을 소스 설치 했을 때 상황으로 보인다.
yum을 이용하여 설치 하였기 때문에 config 설정이 조금 다르다.
config 시 mysql_config 명령어를 사용하는 데, mariadb-devel를 설치해야 한다.


sudo yum install mariadb-devel -y

sudo wget https://github.com/y-ken/mysql-udf-http/archive/master.zip

unzip master.zip


or
(git 명령어가 있으면)
git clone https://github.com/y-ken/mysql-udf-http.git


여기서 소스를 조금 수정 해야 된다.
실제 테스트 해보면, http_post로 json 전송하면 받는 server에서 json 타입으로 인식을 하지 못한다.
json으로 post 전송하기 때문에 header에 "Content-Type: application/json"이 필요하지만 그런 설정 부분이 없다.
워낙 소스가 간단해서 http_post function을 복사해서 http_post_json을 하나 만들고
해더만 아래처럼 추가 했다.
...
  if (curl)
  {
    struct curl_slist *hs=NULL;
hs = curl_slist_append(hs, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hs);
...

소스 수정 파일


재컴파일 후 mysql 재시작 후 function 등록.
create function http_post_json returns string soname 'mysql-udf-http.so';

테스트 해보면 정상적으로 인식 된다.



cd mysql-udf-http-master/

sudo CPPFLAGS="-I/usr/include/mysql" sh ./configure --with-mysql=/etc/my.cnf   --enable-shared --libdir=/usr/lib64/mysql/plugin && sudo make && sudo make install



설치가 정상적으로 완료 되었으면 /usr/lib64/mysql/plugin 디렉토리에 mysql-udf-http.* 파일들이 생긴다.
동적으로 인식이 되기 때문에 mysql 재시작은 안해도 된다. (*** 같은 이름으로 다시 넣으면 인식 안된다. 그럴 때는 재시작하자)

mysql console 상에서 function을 등록해 준다.

create function http_get returns string soname 'mysql-udf-http.so';
create function http_post returns string soname 'mysql-udf-http.so';
create function http_put returns string soname 'mysql-udf-http.so';
create function http_delete returns string soname 'mysql-udf-http.so';


사용법
SELECT http_get('<url>');
SELECT http_post('<url>', '<data>');
SELECT http_put('<url>', '<data>');
SELECT http_delete('<url>');

테스트로 가져오면 잘 가져온다.
select http_get('http://example.com/');



lib_mysqludf_json을 설치해서 json 타입을 리턴 받을 수 있다.


소스를 다운받은 후 so 파일로 만들어 주면 된다.
이건 make를 지원하지 않아 다른 방식으로 만들어야 된다.
같이 다운받아지는 so 파일을 사용하려고 봤는데, 32bit이다.
[root@VM1554776686489 lib_mysqludf_json]# file lib_mysqludf_json.so
lib_mysqludf_json.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped

삭제 하자.

git clone https://github.com/mysqludf/lib_mysqludf_json.git

cd lib_mysqludf_json/

gcc -fPIC -shared -o lib_mysqludf_json.so -I/usr/include/mysql/  lib_mysqludf_json.c


만들어진 lib_mysqludf_json.so 파일을 plugin 폴더로 넣자.
mv lib_mysqludf_json.so /usr/lib64/mysql/plugin/

.sql 파일을 보면 function 만드는 법이 나온다. 복사해서 쓰자.


mariadb 기반으로 설치 하였다.


https://github.com/y-ken/mysql-udf-http
https://github.com/mysqludf/lib_mysqludf_json

워드프레스 서버 날라가다.

워드프레스를 사용하던 서버가 드디어 날라가 버렸다.
한 10개의 글도 같이 날라 갔다.

서버를 다시 맞추기가 어렵다.
구글 블로그로 갈아 타기로 했다.

최초로 설치형 블로그를 시작한 개기도 당시 근무하던 회사에서 외부 블로그 검색 자체를 막아 놨기 때문이였다.

이제 그런 것도 없으니 구글블로그를 써도 무방하다.
도메인 역시 필요없어지게 됐다. 연장 하지 않을 예정이다.

2018년 5월 24일 목요일

스택트레이스(stacktrace) 읽는 팁

자바는 에러 발생시 익셉션을 발생시켜서 에러가 발생한 위치를 정확히 알려준다.

스택트레이스는 꽤나 중요한 사항인데, 나 역시도 깊게 생각해 본 적이 없다.

그러다 okky 글을 읽고 내 나름의 스택트레이스 읽는 팁을 적어 본다.

 
1. lib 는 제외하고, 내 소스 부분만 본다.

2. 스택의 제일 윗 부분을 본다.

3. Caused by 가 있을 경우 제일 하단의 Caused by 부터 본다.

대부분의 경험있는 개발자라면 느낄 것이다. lib에서 에러가 발생하는 경우는 99%이상 없다고 본다.
에러의 대부분은 내가 짠 소스에서 발생한다.
개발할 때는 기본적으로 여러가지 라이브러리를 사용하기 때문에 스택이 복잡해 지는 데, 라이브러리를 제외하고 보면 꽤나 단순해 진다.

스택은 알다시피 First in Last Out (FILO)이다. 그렇기 때문에 제일 상단의 라인이 제일 마지막에 실행된 부분이고 이 부분이 에러인 경우가 가장 많다.

"Caused by: " 부분은 exception chaining 이 발생 할 때 나타나는 메시지이다.
제일 하단의 "Caused by: " 섹션에서 내 패키지가 없다면 패스, 있다면 해당 부분이 원인일 경우가 많다.

검색해 보니, 이런 부분을 이용하여 보기 스택트레이스를 보기 좋게 해주는 사이트도 있다.

참조
https://stackoverflow.com/questions/3988788/what-is-a-stack-trace-and-how-can-i-use-it-to-debug-my-application-errors
https://bukkit.org/threads/how-to-read-stack-traces-and-troubleshoot-your-own-plugins-by-yourself.32457/

2018년 2월 10일 토요일

Parameter index out of range (3 > number of parameters, which is 2)

mybatis 사용시 아래와 같은 에러 발생.

Parameter index out of range (3 > number of parameters, which is 2)

원인은 mybatis 변수 사용시 '를 사용하였기 때문이였다.
#before
AND reg_date BETWEEN CONCAT('#{start_search_date}', ' 00:00:00') AND CONCAT('#{end_search_date}',' 23:59:59')

#after
AND reg_date BETWEEN CONCAT(#{start_search_date}, ' 00:00:00') AND CONCAT(#{end_search_date},' 23:59:59')

 

 

2017년 12월 26일 화요일

Mysql 암호화, 복호화

 
#암호화
INSERT INTO 테이블명 (컬럼1) VALUES (HEX(AES_ENCRYPT('문자열', SHA2('My secret passphrase',512))));

#복호화
SELECT CAST(AES_DECRYPT(UNHEX(컬럼1), SHA2('My secret passphrase',512)) as char) FROM 테이블명;
OR
#복호화
SELECT CONVERT(AES_DECRYPT(UNHEX(컬럼1), SHA2('My secret passphrase',512)) USING utf8) FROM 테이블명;

 

CAST나 CONVERT으로 형변환 하는 부분 때문에 한참 해맸다.
대부분의 블로그가 형변환을 안 써 놨다.(심지어 공식 사이트 에서도...)

암복호화 함수의 리턴값은 BINARY 이기 때문에 HEX를 사용하지 않으면 필드 타입을 BINARY 저장이 가능한 타입으로 지정해야 된다. 공식문서는 BLOB을 추천한다고...

문제는 BINARY타입으로 지정시 일반 문자열 저장이 안되는 문제가 있기 때문에 필드타입을 VARCAHR로 사용하고 HEX를 사용하여 저장이 가능 하도록 한다.

 

MySQL 5.6이상부터 변경 가능.
암호화 모드 확인
select @@block_encryption_mode

암호화 모드 변경
SET block_encryption_mode = 'aes-256-cbc';#기본값 aes-128-ecb

암호화 모도는 처음부터 확인. 중간에 바뀌면 골치 아파진다.

2017년 12월 18일 월요일

svnadmin: E140001: 잘못된 덤프 파일 헤더

svnadmin: E140001: 잘못된 덤프 파일 헤더

윈도우에 설치된 visualsvn 에서
리눅스 svnserve로 옮기려고 할 때
발생하는 에러이다.

원인은 인코딩 문제라고 한다.
왜 이런 에러가 나냐면 command로 덤프 파일을 생성하지 않고,
Repository 의 우측 클릭 후 Backup Repository로 덤프를 생성하였기 때문이다.

command로 덤프를 생성하면 linux svnserve에서 에러 없이 제대로 올라 간다.

2017년 11월 30일 목요일

mybatis List객체에 제대로 select 데이터를 못 가져오는 경우.

기본적으로 mybatis 사용시 select 데이터는 아래와 같이 리스트로 받는다.

List<ConfirmingReceiptT> result2 = service.selectListConfirmingReceiptT(map);



이걸 객체에 List 변수로 받고자 하면 아래와 같이 한다.
public class GetConfirmingReceiptListResponseT {

@XmlElement(name = "ConfirmingReceipt")
protected List<ConfirmingReceiptT> confirmingReceipt;
...



여기서 문제가 발생.
최상위 객체인 GetConfirmingReceiptListResponseT의 confirmingReceipt에 내용이 담기지 않는 문제가 발생.

대략 일주일 정도 삽질 한 결과 최상위 객체에 달랑 List 변수 하나만 있으면 mybatis가
이걸 인식을 못한다.

해결책은 필요는 없지만 result를 한개더 추가 해 준다.

해결한 resultMap
<resultMap type="kr.co.auction.schema.arche_apisvc.ConfirmingReceiptT" id="ConfirmingReceiptT">
  <result property="receiptStatus" column="receiptStatus" />
  <result property="sellingType" column="SELLINGTYPE" />
  <result property="paymentTimeLimit" column="paymentTimeLimit" />
  <association property="orderBase" javaType="kr.co.auction.schema.arche_apisvc.OrderBaseT" >
   <id property="itemID" column="itemID" />
   <result property="orderNo" column="orderNo" />
   <result property="itemName" column="itemName" />
   <result property="awardQty" column="awardQty" />
   <result property="awardAmount" column="awardAmount" />
   <result property="deliveryFeeAmount" column="deliveryFeeAmount" />
   <result property="buyerName" column="buyerName" />
   <result property="buyerID" column="buyerID" />
   <result property="groupOrderSeqno" column="groupOrderSeqno" />
   <result property="requestOption" column="requestOption" />
   <result property="requestOptionPrice" column="requestOptionPrice" />
   <result property="sellerStockCode" column="sellerStockCode" />
   <result property="orderDate" column="orderDate" />
  </association>
  <association property="addressBase" javaType="kr.co.auction.schema.arche_apisvc.AddressBaseT" >
   <result property="name" column="name" />
   <result property="tel" column="tel" />
   <result property="mobileTel" column="mobileTel" />
   <result property="email" column="email" />
   <result property="postNo" column="postNo" />
   <result property="addressPost" column="addressPost" />
   <result property="addressDetail" column="addressDetail" />
   <result property="addressRoadName" column="addressRoadName" />
  </association>

</resultMap>


<resultMap type="kr.co.auction.schema.arche_apisvc.GetConfirmingReceiptListResponseT" id="GetConfirmingReceiptListResponseT" autoMapping="true">
 <result column="ADDUSERCD"  /><!-- temp, collection 한개만 있으면, List객체로 반환이 안됨. -->
 <collection property="confirmingReceipt" ofType="kr.co.auction.schema.arche_apisvc.ConfirmingReceiptT" resultMap="ConfirmingReceiptT" />
</resultMap>