Spring MVC 를 사용하여 Web Application 을 개발 할 때에, 통상 Database 와 연동을 해서 개발 한다. 데이터의 시발점이기도 하기 때문에, 문제가 발생 하는 경우 다른 무엇보다 최우선으로 확인 한다. 이 때 필요한 것은 로그 이다. 개발자의 생명줄 이나 다름없다.


log4jdbc 는 로그를 상세하게 출력 한다. 라이브러리를 추가 하자. 0.2.7 이 stable 버전 이다.


<dependency>
    <groupId>org.lazyluke</groupId>
    <artifactId>log4jdbc-remix</artifactId>
    <version>0.2.7</version>
</dependency>


그 다음은 DataSource 이다. driverClassName 을 변경 하면 지원 하는 Database 가 제한적 이기 때문에, 보존 하면서 설정 하는 방법 이다.


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    <!-- ConnectionPool Information -->
    <beans:bean id="dataSourceSpied" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <beans:property name="driverClassName" value="#{config['jdbc.driver']}" />
        <beans:property name="url" value="#{config['jdbc.url']}" />
        <beans:property name="username" value="#{config['jdbc.username']}" />
        <beans:property name="password" value="#{config['jdbc.password']}" />

        <beans:property name="defaultAutoCommit" value="false"/>

        <beans:property name="initialSize" value="1"/>
        <beans:property name="maxActive" value="1"/>
        <beans:property name="maxIdle" value="1"/>
        <beans:property name="maxWait" value="20000"/>
        <beans:property name="logAbandoned" value="true"/>
        <beans:property name="removeAbandoned" value="true"/>
        <beans:property name="removeAbandonedTimeout" value="60"/>
        <beans:property name="validationQuery" value="SELECT 1 FROM DUAL" />
        <beans:property name="testOnBorrow" value="true" />
        <beans:property name="testOnReturn" value="true" />
    </beans:bean>

    <beans:bean id="dataSource" class="net.sf.log4jdbc.Log4jdbcProxyDataSource">
        <beans:constructor-arg ref="dataSourceSpied" />
        <beans:property name="logFormatter">
            <beans:bean class="net.sf.log4jdbc.tools.Log4JdbcCustomFormatter">
                <beans:property name="loggingType" value="MULTI_LINE" />
                <beans:property name="margin" value="19" />
                <beans:property name="sqlPrefix" value="SQL:::" />
            </beans:bean>
        </beans:property>
    </beans:bean>
</beans>


Database 연결 정보를 가지고 있는 dataSource 는 Proxy 클래스를 생성하여 추가적으로 로그를 처리하는 부분이 구현 되어 있으며, Log4jdbcProxyDataSource 는 DataSource 를 상속 형태로 구현하여 확장되어 있다. CGLIB Proxy 라고 불 수 있다.


<logger name="jdbc.connection">
    <level value="info" />
</logger>
<logger name="jdbc.sqltiming">
    <level value="debug" />
</logger>
<logger name="jdbc.resultsettable">
    <level value="info" />
</logger>


log4j.xml 에 위 내용을 추가 하자. 접속 정보, Query, 응답 데이터에 대한 상세 로그가 출력 된다.


2014-10-23 04:19:39,130  INFO connection - 17. Connection opened
2014-10-23 04:19:39,130 DEBUG getBoardList - ooo Using Connection [net.sf.log4jdbc.ConnectionSpy@378c3efb]
2014-10-23 04:19:39,130 DEBUG getBoardList - ==>  Preparing: select no, title, content, create_dt from tb_board
2014-10-23 04:19:39,130 DEBUG getBoardList - ==> Parameters: 
2014-10-23 04:19:39,132 DEBUG sqltiming -  sun.reflect.GeneratedMethodAccessor36.invoke(null:-1)
17. select no, title, content, create_dt from tb_board  {executed in 1 msec}
2014-10-23 04:19:39,135  INFO resultsettable - |-------|--------|---------|----------------------|
2014-10-23 04:19:39,135  INFO resultsettable - |NO     |TITLE   |CONTENT  |CREATE_DT             |
2014-10-23 04:19:39,135  INFO resultsettable - |-------|--------|---------|----------------------|
2014-10-23 04:19:39,135  INFO resultsettable - |1      |title1  |ko       |2014-10-07 12:04:16.0 |
2014-10-23 04:19:39,136  INFO resultsettable - |2      |title2  |en       |2014-10-07 12:04:24.0 |
2014-10-23 04:19:39,136  INFO resultsettable - |3      |title3  |cn       |2014-10-07 12:04:31.0 |
2014-10-23 04:19:39,136  INFO resultsettable - |-------|--------|---------|----------------------|
2014-10-23 04:19:39,138  INFO connection - 17. Connection closed


Database 와 연결 되는 시나리오가 상세하게 로그로 출력 되고 있어 개발, 검증 단계에서 편리하게 사용할 수 있다.


실 서버 적용 에는 sqltiming 부분만 사용하면 장애 대응이나 데이터에 대한 문의도 편리하게 대응이 가능 하다.


log4jdbc 를 사용할 수 있는 환경이라면, 주저 말고 사용 해 보자.


참고 사이트


보통, 공지 글 이 존재하는 게시판 작성 시 실수 할 수 있다. 게시 글 중 Top 1~3 개를 가져올 것이다.


select * from board where rownum = 1 order by board_id desc


위와 같은 Query 는 rownum = 1 조건이 먼저 실행 되고 그 후 order by board_id desc 이 실행 되기 때문에, Top 1 게시 글을 받아 올 수 없다.


select * from (select * from board order by board_id desc) where rownum = 1


이렇게 하면 order by board_id desc 먼저 실행 한 후, rownum = 1 조건을 적용 하기 때문에 원하는 게시 글을 볼 수 있다.



Nodejs에서 Query를 이용 할 경우 Java에서 JDBC를 이용한 것이 JavaScript 라고 생각 하면 된다.


JDBC



// STEP1: Query 작성
PreparedStatement preparedStatement = connection.prepareStatement("select * from tb_test where test_no = ? and test_title = ? and test_content = ?");
   
// STEP2: 조건 처리
preparedStatement.setInt(1, 2);

preparedStatement.setString(2, "title");

preparedStatement.setString(3, "content");



Nodejs



client.query('select * from tb_test where test_no = $1 and test_title = $2 and test_content = $3',

[2, 'title', 'content'],

function(error, result) {

// result...

})



위와 같은 모습은 기본 형태라고 볼 수 있다.


Java는 set 하는 순간에 type을 다 정해주기 때문에 고민 할 필요가 없지만 javascript는 동적으로 타입이 변하기 때문에 문제가 발생 한다.

IN 절을 썼을 때 ',' 과 숫자가 결합이 되는 형태가 되면 문자열로 인식 하게 되어 Error가 발생 할 수 있다.


해결 방법



var nos = '1, 2, 3, 4, 5';


client.query('select * from tb_test where test_no in (' + nos + ') and test_title = $1 and test_content = $2',

['title', 'content'],

function(error, result) {

// result...

})



위와 같이 문자열로 직접 결합 해주어야 해결 할 수 있다.


'Nodejs' 카테고리의 다른 글

node-gyp rebuild 시 command not found 해결 방법  (0) 2013.04.26
file system library mkdirp  (0) 2013.03.29
Debian Linux에서 Eclipse, Nodejs 연동하기  (0) 2013.02.16
Nodejs is that ?  (0) 2013.02.10
Nodejs 설치 하기  (0) 2013.02.10


게시판을 만들 때 대표적으로 페이징 테스트를 하고 싶을 경우. 많은 데이터가 필요하다. 테이블의 레코드를 복사하여 Insert 하는 방법을 알아보자.



insert into tb_test (column...)

select column... from tb_test where ...



위와 같은 형태로 Query를 작성하여 실행하면 된다. Sequence가 있을 경우에는 신경 쓰도록 하자.



복잡한 Query vs 여러 개의 Query


쿼리를 설계할 경우에는 복잡한 쿼리 하나가 좋을지 혹은 간단한 쿼리 여러 개가 좋을 지 심각하게 고민 해봐야 한다. 전통적으로는 데이터베이스를 설계할 때 소수의 쿼리로 가능한 많은 일을 하도록 해왔다. 이런 방식은 네트워크 통신 비용과 쿼리 파싱 및 최적화 단계의 오버헤드 때문에 역사적으로 더 좋은 결과를 보여왔다.


지금은 다르다. 최신 네트워크는 예전에 비해 굉장히 빨라졌고, 네트워크 지연도 줄어들었다. 가능한 적은 쿼리를 사용하는 편이 좋으나, 여러개의 쿼리를 이용하는것이 오히려 더 효율적일 때도 있다. 


실제로 어플리케이션 중 한번에 쿼리를 사용 하는게 아니라 여러 행의 컬럼을 각각 따로 불러오기 위해 여러 번에 걸쳐 쿼리를 수행하기도 한다.


여러 개의 쿼리로 분해 하기 위해서는 쿼리 자르기, 조인 분해 이런 기법 들이 있다.


※ 참고 서적: [Mysql 성능 최적화 - 베론 슈와츠, 피터 제이트세브, 바딤 카첸코, 제레미 자워드니, 아르엔 렌츠, 데렉 볼링 지음][04장 쿼리 성능 최적화]


 

 Sql을 작성하면, 일반적인 Select 가 아닌 합이나, 통계 등 다양한 조건을 수용하기 위해서는 count() 라는 함수를 사용하게 된다. 아래 목록을 보자.

 

 

 

    • 값을 셀 수 있다.
    • 행을 셀 수 있다.
    • NULL이 아닌 것을 의미 한다.

 

 

 

 크게 3가지로 구분 할 수 있다. count()는 사용 할 경우, 단순히 결과에 있는 행 수를 세게 된다. 괄호 안에 있는 내용은 표현이 절대 NULL을 가질 수 없다는 조건을 염두해 두고 동작 한다고 한다.

 

※ 참고 서적: [Mysql 성능 최적화 - 베론 슈와츠, 피터 제이트세브, 바딤 카첸코, 제레미 자워드니, 아르엔 렌츠, 데렉 볼링 지음][04장 쿼리 성능 최적화]

'Database' 카테고리의 다른 글

Mysql Timestamp Column 생성 하기  (0) 2012.12.06
Mysql root 비밀번호 변경하기  (0) 2012.12.03
Oracle 덤프 뜨기  (0) 2012.11.26
having 사용하기  (0) 2012.11.15
Mysql 사용자 생성 하기  (0) 2012.11.13

 

 sql을 작성 하는데 데이터의 특정 조건의 합, 특정 값 이상 등 group by를 해야할 경우가 생길 수 있다. 이와 같은 경우 inline view를 이용하여 처리를 할 수도 있지만, having을 이용하면 처리 하기가 유용하다. 직접 사용해보도록 하자.

 

 Mysql은 설치되어 있다고 가정 한다. 아래 sql을 실행 하자.

 

 

create table tt_date (
    tt_time timestamp,
    title varchar(10)
);

 

insert into tt_date values ('2012-01-01','title1');
insert into tt_date values ('2012-01-02','title2');
insert into tt_date values ('2012-01-03','title3');
insert into tt_date values ('2012-01-04','title4');
insert into tt_date values ('2012-01-05','title5');
insert into tt_date values ('2012-01-06','title6');
insert into tt_date values ('2012-02-07','title7');
insert into tt_date values ('2012-02-08','title8');
insert into tt_date values ('2012-02-09','title9');
insert into tt_date values ('2012-02-10','title10');
insert into tt_date values ('2012-02-11','title11');
insert into tt_date values ('2012-03-12','title12');
insert into tt_date values ('2012-03-13','title13');
insert into tt_date values ('2012-03-14','title14');
insert into tt_date values ('2012-03-15','title15');

 

 

 테이블을 생성 했을 것 이다. 아래의 조건을 보도록 하자.

 

 

Step 1. 1월 데이터만 출력 하기.

 

 

select tt_time from tt_date group by tt_time having month(tt_time) = 1

 

 

 

Step2. 1월 3일 ~ 1월 5일 데이터만 출력 하기.

 

 

select tt_time from tt_date

group by tt_time having month(tt_time) = 1 && day(tt_time) > 2 && day(tt_time) < 6

 

 

 

사용한 날짜 함수.

 

  • month(date): 날짜에 대한 월을 반환 한다.
  • day(date): 날짜에 대한 일을 반환 한다.

 

group by 후에 조건을 걸어 조회를 할 수 있다. 날짜 함수와 같이 사용하여 알아보았다.

 

'Database' 카테고리의 다른 글

Mysql Timestamp Column 생성 하기  (0) 2012.12.06
Mysql root 비밀번호 변경하기  (0) 2012.12.03
Oracle 덤프 뜨기  (0) 2012.11.26
count() 에 대해서  (0) 2012.11.16
Mysql 사용자 생성 하기  (0) 2012.11.13

 Mysql이 설치가 되어 있다고 가정 한다.

Step 1. 데이터베이스 생성

 생성할 사용자가 사용하는 데이터베이스를 생성 한다. 생성시 명시를 해줘야 하기 때문에 먼저 작업 한다.

 create database if not exists [데이터베이스 명]

 create database if not exists whitelife;


 Step 2. 사용자 생성

 사용자를 생성 한다. 접속을 허용할 IP를 whitelife@IP 작성 하거나 '%' 모든 접속이 허용 된다.

 grant usage on [데이터베이스 명].* to [사용자 명]@[호스트] indentified by [비밀번호];

grant usage on whitelife.* to whitelife@localhost identified by 'whitelife';
grant usage on whitelife.* to whitelife@'127.0.0.1' identified by 'whitelife';
grant usage on whitelife.* to whitelife@'%' identified by 'whitelife';


 Step 3. 권한 부여

 권한을 부여 한다. 최소한 권한만 정의 하였다. 사용자 생성시 3가지 종류로 작성 하였다면 권한도 3가지 다 부여해야 한다.

grant select, insert, update, delete, create, drop, index, alter on whitelife.* to whitelife@localhost;
grant select, insert, update, delete, create, drop, index, alter on whitelife.* to whitelife@'127.0.0.1';
grant select, insert, update, delete, create, drop, index, alter on whitelife.* to whitelife@'%';


 Step 4. 적용 하기

 아래 명령어를 실행 한다.

flush privileges;


  Step 5. 확인 하기

 생성한 사용자로 로그인하여 확인해보자. 정상적으로 접속 되는 것을 확인 할 수 있다.

C:\Program Files\MySQL\MySQL Server 5.5\bin>mysql -u whitelife -p whitelife
Enter password: *********
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 29
Server version: 5.5.28 MySQL Community Server (GPL)

Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>


'Database' 카테고리의 다른 글

Mysql Timestamp Column 생성 하기  (0) 2012.12.06
Mysql root 비밀번호 변경하기  (0) 2012.12.03
Oracle 덤프 뜨기  (0) 2012.11.26
count() 에 대해서  (0) 2012.11.16
having 사용하기  (0) 2012.11.15

+ Recent posts