'Programming/Network/Server/DB'에 5개의 글이 있습니다.

PHP+MySQL을 이용한 웹게임 개발

posted-at2013.06.18 16:38 :: posted-inProgramming/Network/Server/DB :: posted-byNarrL

http://115.68.7.121/mediawiki/index.php/Engineering_php%2Bmysql_web_games


이 문서는 PHP + MySQL로 웹게임 제작시 고려해야할 기술적인 문제에 대해 정리한 것이다.

Contents

 [hide]

[edit]Concurrency control

여러 명이 서버에 여러명이 접근하게 되면 웹게임이든 온라인 게임이든 동시성(concurreny)을 고려하고 제작을 해야한다. 동시에 여러명의 사용자가 게임에 접근하게 되면 database의 쿼리나 PHP코드 실행 순서 동기화가 깨지면서개발자가 생각하지 못한 식으로 갱신이 이루어지게 될 수 있다.

예를 들어 PHP 스크립트를 통해 다음과 같은 MySQL쿼리문 두개를 요청하였다고 하자. 다음 쿼리는 uid가 1인 플레이어가 가진 돈을 가져온후 100증가시키는 일을 하고 있다.

$result = mysql_query("SELECT money FROM player WHERE uid=1");
$row = mysql_fetch_row($result);
mysql_query("UPDATE SET money=$row[0] + 100 FROM player WHERE uid=1");

위와 같은 코드가 PHP 스크립트를 실행하는 프로세스 여러개에서 실행된다면 무슨 일이 일어날까? 위 PHP 코드를 두번 실행하면 돈이 200상승 한다고 생각하는게 자연스럽다. 하지만 다음과 같은 상황이 발생하면 돈은 100만 상승하게 된다. Process #1,#2 모두 같은 값의 돈의 크기에 100을 더해주는 상황이 발생하는 것이다.

  • 1. process #1이 SELECT쿼리 요청
  • 2. process #2가 SELETT쿼리 요청
  • 3. process #1이 UPDATE쿼리 요청
  • 4. process #2가 UPDATE쿼리 요청

이와 같은 동시 접근에 따른 순서가 보장되지 않는 문제는 MySQL의 storage engine을 MyISAM을 쓴다면 table lock으로, InnoDB라면 row level lock을 통해 해결할 수 있다. InnDB라면 위의 두개의 쿼리를 하나의 Transaction으로 묶어주고 SELECT ... FOR UPDATE문으로 SELECT 쿼리를 변경해준다.

mysql_query("START TRANSACTION");
$result = mysql_query("SELECT money FROM player WHERE uid=1 FOR UPDATE");
$row = mysql_fetch_row($result);
mysql_query("UPDATE SET money=$row[0] + 100 FROM player WHERE uid=1");
mysql_query("COMMIT");

위와같이 수정하게 되면 SELECT FOR UPDATE에서 접근된 row들은 다른 클라이언트에서 정보를 변경하지 못하게 lock이 걸리게 되어 쿼리 순서 직렬화를 보장받을 수 있는 것이다. 그런데 MySQL의 lock 기법은 transaction isolation level, storage engine에 따라 동작 방법이 틀려진다. 내부에서 일어나는 복잡한 동기화 구현방식을 이해하지 못하게 되면 문제 발생시 해결이 어려워질 수 있다. 게다가 row level lock은 table lock에 비해 빠르게 동작하지만 dead lock의 발생 위험을 지니고 있다. MySQL의 복잡한 row level locking 동작방식을 신경쓰지 않고 다른 방법으로 쿼리 순서 동기화를 처리할 수 있는 방법이 없을까? 순서 동기화 문제는 MySQL만의 이슈가 아니다. 다른 시스템을 이용하여 동시성 문제를 해결할 수도 있다는 말이다. 그럼 웹게임 제작시 사용될 수 잇는 여러가지 동기화 기법에 대해 알아보자.

platformsolution
Game server (one thread)Not Required
Game server (multi thread)Critical Section
WebServer + PHPSemaphore, Custom lock (ex)memcached lock)
MySQLtable lock, row level lock, 하나의 쿼리문으로 합쳐서 요청, procedure로 요청

제일 먼저 보통 온라인 게임에서 쓰이는 socket방식의 game server부터 알아보자. 해당 서버가 원스레드라면 동기화 문제는 일어나지 않으므로 해결할 필요가 없다. 만약 멀티스레드라면 critical section과 같은 동기화 객체를 이용하여 실행 순서를 보장하면 된다.

PHP는 코드 실행 동기화를 위해 Semaphore 함수를 제공한다. web serve가 여러개의 PHP프로세스를 실행하더라도 Sempaphore객체가 순서를 보장해주기 때문에 동시성 문제가 일어나지 않지만 Semaphore 함수는 해당 서버 머신에서만 동기화를 보장하기 때문에 확장성이 떨어진다. 여러 머신간의 코드 실행 동기화는 Memcached를 이용한 lock기법을 사용할 수 있다(이는 PHP가 여러 머신간의 세션 공유를 위해 Memcached에 세션정보를 저장하고 있는 방식과 유사한 개념이다)

MySQL은 쿼리의 실행 동기화를 위해 transaction을 통한 lock 기법을 사용한다.

정리하면 웹게임 제작시에 추천하는 쿼리 순서 동기화 방법은 다음과 같다.

  • 1. Gamer server의 critical section을 통한 쿼리 동기화
  • 2. MySQL의 Transaciotn을 통한 lock 기법을 통한 쿼리 동기화(InnoDB)
  • 3. Memcached로 구현된 custom lock을 구현해 쿼리 동기화

Critical section을 통해 특정 코드 영역을 동기화 하면 쿼리문 요청 순서도 같이 동기화 된다. 타 머신간의 쿼리 동기화가 불가능하므로 확장성면에서는 불리하다. MySQL의 transction을 통한 lock은 숙련자가 사용하면 동시성 보장이 되면서 성능도 우수하게 만들 수 있다. 하지만 isolation level, transacion, storage engine에 따라 같은 쿼리문도 lock의 동작이 틀려져 transaction이 적은 웹게임에서는 과한 해결방법이 될 수 있다.

과거 바이시티 개발시에 MySQL의 쿼리 순서 동기화를 위해 특정 키를 memcached에 저장하고, 처리가 끝나면 키를 삭제해서 한번에 명령을 하나만 처리하는 식으로 동시성문제를 해결했다. lock되어 있는 상태에서 다른 유저가 해당 처리를 요청하면 "처리에 실패했습니다" 라는 메시지를 발생시키고 유저의 요청처리를 취소했기 때문에 매끄럽지 못했다. 이를 해결하기 위해서는 php의 while문을 이용하여 spin-lock형태로 memcached를 이용하면 된다. lock wait time을 너무 길게 잡으면 웹 브라우저가 웹서버 프로세스를 계속 물고 있게 되어 다른 유저들이 접속하지 못하는 상황이 발생할 있는 점은 주의해서 만들어야 한다.

[edit]Development design

웹게임 개발을 위한 시스템 구성은 다음 세가지가 대표적이다.

  • 1. Web server and game server(one thread)
  • 2. Web server and game server(multi thread)
  • 3. Only web server

첫번째 구성은 Web server는 게임을 보여주는 역할을 하고 게임 로직처리는 게임서버에서 수행하는 모델. 원스레드로 서버 하나로 유저 요청을 모두 처리하게 되면 MySQL 쿼리에 대한 동시성 문제가 일어 나지 않는다. 이 모델은 서버는 한가지 처리밖에 진행 못하기 때문에 조금이라도 처리가 길어지는 요청이 들어오게 되면 다른 요청을 처리하지 못하고 지연되는 현상이 일어나게 된다. 이런 병목현상이 일어나게 되면 필경 원스레드 서버를 자원갱신 서버, 유저요청처리 서버등의 역할별로 분리하게 될 것이다. 그렇게 되면 다시 외부 기능을 이용하여 동시성 문제를 해결해야 한다.

두번째 구성은 Web server는 게임을 보여주는 역할을 하고 게임 로직처리는 게임서버에서 수행하는 모델. Game server내에서 critical secion을 사용하여 외부 기능을 이용하지 않고 동기화 수행이 가능. Game server code 순서가 보장되면 MySQL 쿼리의문의 순서도 동기화 된다. 멀티스레드 방식이기 때문에 1번에서 제기 되었던 성능문제가 없다. 이 모델 역시 하나의 월드에 대해 게임서버를 여러대 운영할 경우 외부 기능을 이용하여 동시성 문제를 해결해야 한다.

세번째 구성은 Web server가 게임을 보여주는 역할과 로직처리를 모두 수행하는 모델. Web server가 설치된 머신에서는 PHP의 Semaphore를 이용하여 코드를 직렬화 할 수 있지만 여러 머신간의 동시성 문제는 외부 기능을 이용하여 동기화 해야 한다.

부족전쟁류 웹게임이라면 첫번째 모델인 Web server and game server(one thread)를 이용하는 것이 적절하겠다. game server를 운영하게 되면 memory에 게임상태를 저장할 수 있어 좀더 유연한 컨텐츠 기획이 가능해진다. 그리고 원스레드 서버이기 때문에 스레드를 썻을때 생기는 여러가지 개발 이슈에서 자유롭게 된다. 역할별로 분리하여 분산처리하면 확장성도 가능해지게 된다. 하지만 점점 더 웹게임은 온라인 게임과 같은 게임 콘텐츠를 원할 것이므로 일반적인 온라인 게임의 시스템 구성방식인 두번째 모델 사용이 많아 질 것으로 예상된다.

[edit]Performance

웹게임 성능을 좌우하는 요소는 무엇인가? 스크립트만의 처리는 빠르지만 문제는 다른 모듈혹은 서버간의 통신속도이다.( MySQL, Memcached) 특히 다음 요소에 주의를 기울여야 한다.

  • 페이지당 쿼리 개수 10개 이하로 유지
  • 최대한 이미지 개수 줄이기(이미지 하나하나가 HTTP 요청이다). 캐싱이 된다고 하지만 갑자기 최초방자가 몰리는 상황이라면?
  • CDN으로 분리하자
  • 필요한 모듈만 include한다. include명령어 자체는 eaccelerator로 캐싱하면 i/o부하는 일어나지 않으므로 큰 문제는 아니다. 하지만 스크립트 파싱도 의외로 속도가 들어갈 수 있다.

성능을 체크하기 위해서 JMeter등의 툴을 사용한다.

  • 초당 몇 개의 요청을 처리할 수 있는가

많은 수의 js파일이 있으면 성능저하가 일어나는지도 확인이 필요한다. Nginx+php_cgi와 같이 여러클라이언트를 하나의 프로세스에서 처리하는 형태를 가진 웹서버에서 웹스크립트 에러는 hang을 일으켜 성능을 저하시키는 원인이 된다. 바이시티 테스트시에 Nginx의 경우 hang으로 인한 BadGateway 에러등을 내보내기도 했었다. Apache와 같이 클라이언트당 하나의 프로세스를 실행시키면 그 프로세스만 문제가 생기지만 nginx의 경우 여러 클라이언트를 하나의 프로세스에서 처리하기 때문에 오류가 발생하면 잠시 동안 프로세스가 제일을 처리 못하는 것으로 보인다.

siege,ab등의 툴을 이용해 초당 Transaction수를 파악하도록 한다.( Redorf rasmus의 문서참고: http://hardworker.tistory.com/102 ,http://talks.php.net/show/flux) yslow를 이용해서 페이지를 분석한다.

[edit]Web server

웹서버는 nginx 사용(Nginx + fastcgi)한다. apache같은 웹서버보다 사용자 폭주시 안정적으로 버텨준다

[edit]Database

하드웨어 개선을 통해 6000쿼리까지도 처리가능하다고 하지만 기본적으로 초당 3000이상 요청하면 안된다고 생각해야 한다. 웹게임의 성능은 Database최적화에 달려 있다고 해도 과언이 아닌다. 이때 Web server와 database사이에 game server나 memcached등의 미들웨어를 통해 database 접근을 줄여서 빠르게 처리할 수도 있다. GDC강연을 보면 FarmVill도 MySQL의 바로 접근하지 않고 memcached pool을 통해 성능 개선을 한것을 알 수 있다.

데이타베이스 설계시 중요한 것은 테이블 설계를 적절히 하는 것이다. 너무 많게 테이블을 나눠 구성하면 Transaction 코드가 많아질 수밖에 없다. 그러면 실행 순서 동기화 문제가 발생하면 lock을 통해 동기화 해야 되므로 어려움이 예상되기 때문이다. 기본적으로 웹게임이든 온라인 게임이든 단일문의 짧은 쿼리로 데이타 갱신을 처리하고 필요한 부분에만 조심스럽게 transaction lock을 걸어주는 것이 성능과 안정성 면에서 모두 좋은 전략이다.

[edit]Deadlock

데드락은 트랙잭션이 무한히 기다리는 교착상태에 빠진것을 말한다. 혹은 lock wait time이 너무 길어져서 설정된 시간을 넘겨서 transaction이 실패나는 경우에도 데드락이라고 한다

예를 들면 다음과 같은 쿼리가 호출되는 상황에서는 dead lock이 발생한다.

  • 1. client #1> BEGIN; SELECT name FROM table LOCK IN SHADE MODE;
  • 2. client #2> BEGIN; SELECT name FROM table LOCK IN SHADE MODE;
  • 3. client #1> UPDATE SET name= “test1”table; (lock wait .. )
  • 4. client #2> UPDATE SET name= “test2”table; (lock wait .. dead lock!)
  • 5. client #1> COMMIT;

1번과 2번 쿼리가 UPDATE를 제한하는 읽기락의 종류인 LOCK IN SHADE MODE를 사용하였다. 하지만 같은 row을 두고 두개의 클라이언트 모두 lock wait상황이 빠졌기 때문에 어느 클라이언트도 COMMIT을 통해 트랜잭션을 끝낼수가 없다. 그래서 client #2에서 dead lock이란 에러가 뜨고 트랜잭션이 종료된다. 그외 lockwait timeout이 있는데 이는 다른 트랜잭션에 의한 락이 오랫동안 풀리지않는 경우 발생하는 에러이다. 보통 10초가량 세팅해 놓는다. 이것도 dead lock상황의 하나라고 볼수 있다. 게임에서는 추천하지 않지만 일반 웹어플리케이션의 경우 dead lock 상황이 나오면 다시 요청해주는 코드를 추가해주는 것도 고려할만 한다.

게임 개발시 transaction 쿼리는 많지 않다. 많이 사용하는 것 자체가 문제지 많은 transaction에 의한 dead lock을 해결하고자 lock 코드를 변경하거나 외부 custom lock객체등을 이용해 쿼리 순서를 동기화 하는 것은 일을 더 크게 만드는 것이다. 테이블 구조와 게임 기획 변경을 통해 단일 쿼리로 처리할 수 있게 만들어 lock걸리는 상황이 아예 사라지도록 변경하는 것이 옳은 전략이다

[edit]Authentication

쿠키인증은 빠르다. 세션인증은 상대적으로 느리다.(memcached를 이용해서 저장하여 최적화 가능) 쿠키인증이든 세션인증이든 결국 쿠키를 사용하기 때문에 XSS를 통해 쿠키를 훔쳐오는게 가능해진다. 로그인시마다 유효키를 발급받아 셰션에 저장하고 이를 모든 요청에 넣어서 보내주는 방식이 가장 무난할 것으로 보인다.

[edit]Security

웹게임의 보안이슈는 다음과 같다.

  • 입력값는 모두 XSS, SQL Injection을 대비해서체크
  • Parameter Query방식을 통해 Injection방어와 효율성 개선 -> 메모리사용률도 줄어든다.
  • URL입력에 ../을 통해 상위 path로 이동이 가능한 경우도 있따. 이를 통해 /etc/passwd파일을 열어 볼 수 있는 경우도 있었다
  • 사용안하는 port는 블로킹 처리
  • DDOS 방어는? Nginx용 모듈을 찾아보자
  • Nginx는 기본적으로 많은요청에 대해 잘 방어한다. 처리 못하는 유저가 발생한지 아파치처럼 완전히 멈추지는 않는다
  • 하드웨어적으로 상위에서 방어해줘야 한다. DDOS는 어쩔수가 없다. 특정 아이피차단 정도가 할 수 있는 방어의 전부
  • 로그인시 POST 전송 패스워드 암호화 . 네이버 인증시스템을 보면 공개키암호화 시스템이 도입되어 있는 것을 볼 수 있다. 즉 자바스크립트를 딴에서 아이디/암호 문자열 자체를 공개키로 암호화해서 POST전송에 들어가는 내용까지 보호해준다. 이 처리까지 수행하기에는 현실적인 어려움이 따른다. 네트워크 스누핑에만 노출안된다면 별 문제가 없을 것으로 본다.

그외 BurpSuite등의 툴로 취약성 파악이 필수다. rasmuas의 security관련 문서도 읽어보자( http://talks.php.net/show/flux )

[SQL] 데이터 정의 및 타입 - INSERT

posted-at2012.12.17 18:46 :: posted-inProgramming/Network/Server/DB :: posted-byNarrL

1. 데이터 삽입(INSERT INTO)
테이블 이름은 RENAME 구문을 사용하여 변경할 수 있다.
1) 구문
INSERT INTO table_name [ ( attribute_list ) ] VALUES ( value_list ) [ ; ]
INSERT INTO table_name DEFAULT [ VALUES ] [ ; ]
 table_name : 데이터를 생성하고자 하는 테이블 이름을 지정한다.
 attribute_list : 입력하고자 하는 값의 컬럼 이름을 지정한다. 만약 attribute_list를 명시하지 않으면 테이블에 정의된 모든 컬럼에 대한 값을 채워야 한다. 만약attribute_list에 일부 컬럼만 명시가 된다면 나머지 컬럼에는 정의된 디폴트 값이 할당되며 디폴트 값이 없을 경우 NULL 값이 할당된다.
 value_list attribute_list 의 컬럼에 대응되는 값을 명시한다. value_list 의 항목은 표현식, 메소드 호출일 수 있고, attribute_list 의 속성 위치와 도메인 형식이 일치해야 한다. 각 이름과 값은 콤마(,)로 구별된다.
 DEFAULT : 두 번째 구문 형식의 INSERT 문은 각각의 속성에 디폴트 값을 할당하여 데이터를 생성한다. 만약 테이블 정의에서 컬럼에 디폴트 값이 설정되어 있지 않으면 그 컬럼의 값으로 NULL이 할당된다.
2) 예제
 다음은 athlete 테이블에 2008 베이징 올림픽 펜싱 은메달리스트 남현희 선수의 정보를 입력하는 예제이다. code 컬럼은 auto_increment이므로 값을 입력하지 않는다. 자세한 내용은 컬럼에서 자동 증가 특성 내용을 참조한다.
INSERT INTO athlete (name, gender, nation_code, event) VALUES ('Nam Hyun-Hee','W', 'KOR', 'Fencing');
 다음은 olympic 테이블에 2008 베이징 올림픽의 대략적인 정보를 넣는 예제이다.
INSERT INTO olympic (host_year, host_nation, host_city, opening_date, closing_date) VALUES (2008, 'China', 'beijing', '2008-08-08','2008-08-24');
 다음은 DEFAULT를 이용한 데이터 삽입을 보여주는 예제이다. 예제를 위해 de_test 테이블을 생성하고 데이터를 삽입한다. 아래와 같이 설정된 디폴트 값이 자동으로 삽입된 것을 알 수 있다.
CREATE TABLE de_test(
   a INT DEFAULT 10,
   b INT DEFAULT 20,
   c CHAR(1) DEFAULT 'M'
);
INSERT INTO de_test DEFAULT;

csql> SELECT * FROM de_test;
csql> ;x
=== <Result of SELECT Command in Line 1> ===
   a    b    c
===============
   10   20   'M'
1 rows selected.
2. 질의를 이용한 INSERT
INSERT 문에 질의를 사용하면 하나의 INSERT 문으로 다수의 데이터를 생성할 수 있다.
다른 테이블로부터 특정 검색 조건을 만족하는 데이터를 추출하고 싶은 경우 질의를 이용하면 조건을 만족하는 모든 데이터는 INSERT 문에 명시된 테이블의 데이터가 된다.
1) 구문
INSERT INTO table_name [ (attribute_list ) ] query_statement [ ; ]
 table_name : 데이터를 삽입할 테이블의 이름을 지정한다.
 attribute_list : 입력하고자 하는 값들의 컬럼 이름을 지정한다. 이 곳에 정의된 데이터 타입은 query_statement의 결과의 데이터 타입과 일치해야 한다.
 query_statement : 삽입할 데이터를 추출하는 질의문을 정의한다.
2) 예제
 다음은 man 테이블을 생성하고 athlete 테이블에서 남자 선수들의 이름을 조회하여 결과를 삽입한다. 하나의 INSERT 문을 이용하여 4087건의 데이터가 삽입되는 것을 알 수 있다.
CREATE TABLE man (
   name VARCHAR(40)
);

csql> INSERT INTO man (name) SELECT name FROM athlete WHERE gender ='M';
csql> ;x
4087 rows inserted.
Current transaction has been committed.
1 command(s) successfully processed.
3. 부질의를 이용한 INSERT
INSERT 문의 VALUES 항목의 하나로 질의를 포함하여 데이터를 삽입할 수 있다.
1) 구문
INSERT INTO table_name [ ( attribute_list ) ]
VALUES value_listquery_statement ) [ ; ]
 table_name : 데이터를 삽입할 테이블의 이름을 지정한다.
 attribute_list : 입력하고자 하는 값들의 컬럼 이름을 지정한다.
 value_list attribute_list의 컬럼에 대응되는 값들을 명시한다.
 query_statement : 부질의를 정의한다. 부질의의 결과는 해당 컬럼에 대응되는 하나의 값이어야 한다.
2) 예제
 다음은 athlete 테이블에 2008 베이징 올림픽 유도 73kg 은메달 리스트 왕기춘 선수의 정보를 입력하는 예제이다.
INSERT INTO athlete VALUES (16800, 'Wang Ki-chun','M',SELECT code FROM nation WHERE name ='Korea', 'Judo');

  ================================================ 
    * 데이터베이스 정보공유 커뮤니티 oracleclub.com 
    * 강좌 작성자 : 모현철 (hcmo_at_cubrid.com) 
    * 큐브리드 다운로드 URL : http://www.cubrid.com/zbxe/download_2008 
  ================================================

[SQL] 저장프로시저 (Stored Procedure)

posted-at2012.12.17 18:42 :: posted-inProgramming/Network/Server/DB :: posted-byNarrL

저장프로시저

- 저장 프로시저는 하나 이상으로 구성된 Transact-SQL 문을 데이터베이스에 저장한 개체입니다.

저장프로시저 특징
  • 모듈 프로그래밍
    자주 반복해서 사용하는 T-SQL문을 DB에 저장해 필요한 시점에만 사용함. 
    매번 같은 구문을 다시 작성할 필요가 없음
  • 유연한 보완관리
    데이터 조회하는 저장프로시저. 접근권한이 없어도 저장프로시저를 실행할 권한이 있다면 조회가능
  • 네트워크 트래픽 감소
    쿼리전체를 서버로 전송해서 작업하는 것이 아닌 저장 프로시저와 매개변수값만을 전달함으로 데이터량이 작음
  • 빠른실행
    저장프로시저는 실행후 쿼리 실행계획을 메모리에 저장 > 저장된 실행계획 사용 > 구문분석이나 최적화 과정 거치지 않아서 더 빠른 실행을 할수 있고 캐시에 없더라도 구문분석, 표준화등의 작업을 하지 않기에 성능이 빠름

저장프로저의 구성요소
저장 프로시저명, 매개변수들, SQL문, 결과값 반환의 반환값

저장프로시저의 종류
  • 확장프로시저 : C와 같은 언어를 이용해서 구현한 프로시저, master DB에만 추가가능
  • 사용자 정의 저장 프로시저 : T-SQL문을 이용해 저장 프로시저로 구현
  • 시스템 저장 프로시저 : SQL서버관리를 위해 시스템에서 제공해주는 저장 프로시저
    sys의 스키마로 나타남, 데이터베이스 명 필요없이 시스템 저장 프로시저명을 통해서 실행가능

    Sp_who, sp_who2 : 사용자 정보
    Sp_lock : lock 정보
    Sp_help : 지정한 개체 정보
    Sp_helpdb : 지정한 DB정보
    Sp_configure : SQL 서버 설정변경
  • 임시 저장프로시저
    T-SQL 문 또는 일괄처리의 실행계획을 재 사용하지 않던 이전 버전의 방식
    사용자 정의 프로시저와 동일하게 작성하지만, 저장프로시저 명을 #으로 하면 임시저장프로시저가 됨
    SQL Server 2005에서는 T-SQL문과 일괄처리의 실행계획을 재 사용할수 있음으로 임시저장프로시저 사용이 거의없음
  • CLR 저장 프로시저
    T-SQL에서 부족한 프로그래밍 부분을 CLR 저장 프로시저를 통해 T-SQL 저장 프로시저보다는 더 강력한 구조적 프로그래밍이 가능

저장 프로시저의 생성

CREATE PROCEDURE usp_withANumber <- 소문자 : 스키마. 저장 프로시저명
@ EmployeeID INT <- 매개변수, 데이터 형식
AS
SELECT ANumber, AContent, ManagerID
FROM HumanResource.analysisDate
WHERE ManagerID = @ EmployeeID
GO

EXECUTE usp_withANumber

GO
* 임시 저장프로시저의 생성은
CREATE PROCEDURE #usp_withANumber <- 소문자 : 스키마. 저장 프로시저명앞에 샾
* 저장프로시저 생성시, SP_ 접두사는 시스템저장프로시저와 혼란을 줄수 있음으로 사용금지
* 그룹화면 저장프로시저 삭제시 개별적으로 하나씩 삭제할수 없음으로 가급적 사용하지말것
- 그룹화하기 : 같은 저장 프로시저명에 ; 하고 숫자를 매김

CREATE PROCEDURE usp_withANumber;1
AS
[ T-SQL구문 ]
GO

CREATE PROCEDURE usp_withANumber;2
AS
[ T-SQL구문 ]
GO

* 다른 사용자의 접근막기위해서는 CREATE아래쪽에 WITH ENCRYPTION을 사용함
시스템뷰에서 저장프로시저의 텍스트가 나타나지 않음. 암호화된 저장프로시저의 내용은 다시 확인할수 있는 방법이 없음으로 암호화되기전의 저장프로시저를 잘 보관해야함



저장 프로시저의 수정

ALTER PROCEDURE 스키마. 저장프로시저명.
@ 매개변수 데이터 형식
AS
[ 변경된 SQL문 ]



저장 프로시저의 삭제

DROP PROCEDURE 스키마.저장프로시저명;



기본값을 지니는 매개변수의 사용과 output사용

CREATE PROCEDURE usp_withANumber 
@EmployeeID INT = 10 <- EmployeeID에 기본값을 지정한 것
@outvalue int output <- outvalue에 output 변수를 쓰겠다는것
@currency_cursor CURSOR VARYING OUTPUT <- output 매개변수로 커서를 사용할때
AS
SELECT @outvalue = ManagerID <- 관리자 ID를 output 매개변수에 설정
FROM HumanResource.analysisDate
WHERE ManagerID = @ EmployeeID
GO

DECLARE @ManagerID INT; <- 저장프로시저 output 매개변수에 반환하는 값저장을 위한 지역변수선언

EXECUTE usp_withANumber 20, @ManagerID output <-반환되는값 조회

GO

[Tomcat] server.xml 의 reloadable 속성

posted-at2012.10.07 06:31 :: posted-inProgramming/Network/Server/DB :: posted-byNarrL

reloadable

Set to true if you want Catalina to monitor classes in /WEB-INF/classes/ and /WEB-INF/lib for changes, and automatically reload the web application if a change is detected. This feature is very useful during application development, but it requires significant runtime overhead and is not recommended for use on deployed production applications. That's why the default setting for this attribute is false. You can use the Manager web application, however, to trigger reloads of deployed applications on demand.


tomcat 5.5 server.xml 내용 중 ... 에서 클래스 파일 reroding 설정 부분.. 

개발할때는 reloadable = true; 를 사용하지만, 실제 서비스 할때는 reloadable = false; 을 권장한다.

수정된 class 파일을 적용할때는 Tomcat/Manager 을 사용할 수 있다... 


 출처: http://tomcat.apache.org/tomcat-5.5-doc/config/context.html


[Tomcat] 이클립스 tomcat start시 오류

posted-at2012.10.07 06:29 :: posted-inProgramming/Network/Server/DB :: posted-byNarrL

Publishing failed
Could not load the Tomcat server configuration at \Servers\Tomcat v5.0 Server @ localhost-config. The configuration may be corrupt or incomplete.
Resource is out of sync with the file system: /Servers/Tomcat v5.0 Server @ localhost-config/server.xml.
Could not load the Tomcat server configuration at \Servers\Tomcat v5.0 Server @ localhost-config. The configuration may be corrupt or incomplete.
Resource is out of sync with the file system: /Servers/Tomcat v5.0 Server @ localhost-config/server.xml.

<해결법>

1. server.xml 파일을 새로고침
2. 혹은 server.xml 파일의 오류