클로저 내부의 this 객체는 꽤 복잡하게 동작한다. this 객체는 런타임에서 함수가 실행 중인 컨텍스트에 묶인다. 즉 전역 함수에서 this는 스트릭트 모드가 아닐 때는 window, 스트릭트 모드에서는 undefined이며 함수가 객체 메서드로 호출되었을 때 this는 해당 객체이다. 하지만 클로저를 작성하는 방식으로 인해 이를 분명히 알기는 어렵다. 다음 코드를 보자.


var name = "The Window";


var object = {

name: "My Object",

getNameFunc: function() {

return function() {

return this.name;

};

}

};


alert(object.getNameFunc()());    // "The Window" (스트릭트 모드가 아닌 경우)


여기에서 name이라는 전역 변수와 객체를 함께 생성했는데 객체에도 name 프로퍼티가 존재한다. 객체의 getNameFunc() 메서드는 익명 함수를 반환하며 익명 함수는 this.name을 반환한다. getNameFunc()는 함수를 반환하므로 object.getNameFunc()()을 호출하면 getNameFunc()가 반환하는 함수를 즉시 호출하는 것이나 마찬가지이며 문자열을 얻는다. 반환 받은 문자열은 전역 name 변수의 값인 "The Window"이다. 익명 함수가 외부 스코프의 this 객체를 포함하지 않았던 이유는 무엇일까?


모든 함수는 호출되는 순간 자동으로 this와 arguments 두 특별한 변수를 갖게 됨을 상기하자. 내부 함수는 결코 외부 함수의 this와 arguments에 직접적으로 접근할 수 없다. 다음과 같이 외부 함수의 this 객체를 다른 변수에 저장해서 클로저가 이 변수에 접근하도록 하는 일은 가능하다.


var name = "The Window";


var object = {

name : "My Object",

getNameFunc : function() {

var that = this;

return function() {

 return that.name;

};

}

};


alert(object.getNameFunc()());    // "My Object"


굵게 처리한 두 줄로 인해 다른 결과가 나왔다. 익명 함수를 정의하기 전에 외부 함수의 this 객체를 that이란 변수에 할당했다. 이제 클로저를 정의하면 that은 외부 함수에 고유한 변수이므로 클로저는 이 변수에 접근이 가능하다. 함수가 반환한 뒤에도 that은 여전히 object에 묶여 있으므로 object.getNameFunc()()을 호출하면 "My Object"를 반환한다.



this의 값이 예상과 다른 특별한 경우가 몇 가지 있다. 이전 예제를 조금 수정한 다음 코드를 보자.


var name = "The Window";


var object = {

name : "My Object",

getName : function() {

return this.name;

}

};


getName() 메서드는 단순히 this.name의 값을 반환한다. object.getName()을 호출하는 다양한 방법과 그 결과를 보자.


object.getName();    // "My Object"

(object.getName)();    // "My Object"

(object.getName = object.getName)();    // "The Window" (단, 스트릭트 모드가 아닌 경우)


첫 번째 줄은 일반적인 방법으로 object.getName()을 호출했는데 this.name과 object.name은 같으므로 "My Object"를 반환했다. 

두 번째 줄은 object.getName을 호출하기 전에 괄호로 감쌌다. 함수를 참조한 것처럼 보이겠지만 object.getName과 (object.getName)은 같은 것으로 정의되어 있으므로 this 값은 그대로 유지된다. 

세 번째 줄에서는 먼저 할당한 후 그 결과를 호출했다. 할당 표현식의 값은 함수 자체이므로 this의 값이 유지되지 않기 때문에 "The Window"를 반환하게 된다. 

저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by 우너효

자바스크립트에서 '익명 함수'와 '클로저'는 자주 잘못 혼용되곤 한다. '클로저'란 다른 함수의 스코프에 있는 변수에 접근 가능함 함수를 뜻한다. 다음의 코드를 보자.


function createComparisonFunction(propertyName) {

return function(object1, object2) {

var value1 = object1[propertyName];

var value2 = object2[propertyName];


if (value1 < value2) {

return -1;

} else if (value1 > value2) {

return 1;

} else {

return 0;

}

};

}


위 코드에서 Bold 처리 된 부분은 내부 함수(익명 함수)이면서 외부 함수의 변수(propertyName)에 접근한다. 내부 함수가 반환되어 다른 컨텍스트에서 실행되는 동안에도 propertyName에 접근할 수 있다. 이런 일이 가능한 것은 내부 함수의 스코프 체인에 createComparisonFunction()의 스코프가 포함되기 때문이다. 


좀 더 쉽게 이해하기 위해 함수를 처음 호출할 때 무슨 일이 일어나는 지 생각해보자.


함수를 호출하면 실행 컨텍스트와 스코프 체인이 생성된다. 함수의 활성화 객체는 arguments 및 이름 붙은 매개변수로 초기화된다. 외부 함수의 활성화 객체는 스코프 체인의 두 번째 객체이다. 이 과정이 포함 관계에 있는 함수에서 계속 발생하여 스코프 체인이 전역 실행 컨텍스트에서 종료될 때까지 이어진다.


함수를 실행하면 값을 읽거나 쓸 변수를 스코프 체인에서 검색한다. 다음 코드를 보자.


function compare(value1, value2) {

if (value1 < value2) {

return -1;

} else if (value1 > value2) {

return 1;

} else {

return 0;

}

}


var result = compare(5, 10);


위 코드는 전역 실행 컨텍스트에서 호출하는 compare()라는 함수를 만든다. compare()를 처음으로 호출하면 arguments, value1, value2를 포함한 활성화 객체가 만들어진다. 전역 실행 컨텍스트의 변수 객체는 this와 result, compare를 포함하는 compare() 실행 컨텍스트의 스코프 체인의 다음에 위치한다. 


실행 컨텍스트마다 변수를 나타내는 객체가 존재한다. 전역 컨텍스트의 변수 객체는 항상 존재하지만, compare()와 같은 로컬 컨텍스트 변수 객체는 함수를 실행하는 동안에만 존재한다. compare() 함수를 정의하면 스코프 체인이 생성되고 자바스크립트 인터프리터는 이를 전역 변수 객체와 함께 미리 읽어 함수 내부의 [[Scope]] 프로퍼티에 저장한다. 함수를 호출하면 실행 컨텍스트가 생성되며 함수의 [[Scope]] 프로퍼티에 들어 있는 객체를 복사하여 스코프 체인이 생성된다. 다음에는 변수 객체로 동작하기도 하는 활성화 객체가 생성되어 컨텍스트의 스코프 체인 맨 앞에 위치한다. 


위 예제에서 compare() 함수의 실행 컨텍스트가 스코프 체인 내에 변수 객체를 두 개, 즉 로컬 활성화 객체와 전역 변수 객체를 갖는다. 스코프 체인이란 변수 객체를 가리키는 포인터 목록이며 객체를 직접 포함하는 것은 아니다.


함수에서 변수에 접근할 때마다 스코프 체인에서 해당 이름의 변수를 검색한다. 함수 실행이 끝나면 로컬 활성화 객체는 파괴되고 메모리에는 전역 스코프만 남는다. 하지만, 클로저는 이와 다르게 동작한다.

다른 함수의 내부에 존재하는 함수는 외부 함수의 활성화 객체를 자신의 스코프 체인에 추가한다. 따라서 createComparisonFunction()(회부 함수) 내부에 있는 익명 함수의 스코프 체인에는 외부 함수의 활성화 객체를 가리키는 포인터가 존재하게 된다. 


외부 함수가 실행을 마치고 익명 함수를 반환하면 익명 함수의 스코프 체인은 외부 함수의 활성화 객체와 전역 변수 객체를 포함하도록 초기화된다. 이 때문에 익명 함수는 외부 함수의 변수 전체에 접근할 수 있게 된다. 한 가지 흥미로운 점은 외부 함수가 실행을 마쳤는데도 활성화 객체가 파괴되지 않는 점인데 아직 익명 함수의 스코프 체인에서 이를 참조하기 때문이다. 외부 함수가 실행을 마치면 실행 컨텍스트의 스코프 체인은 파괴되지만 활성화 객체는 익명 함수가 파괴될 때까지 메모리에 남는다.




















저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by 우너효

프로시저

SQL의 기본 명령은 선언적 명령이다. (명령 후 결과)

즉, 데이터베이스에서 절차적 명령을 수행하기 위해서는 스토어드 프로그램을 이용해야 한다.


스토어드 프로그램의 종류

  • 스토어드 함수
    의미 그대로 함수. 날짜, 현재 사용자, 시간 등.
    SELECT 쿼리 문 안에 사용 가능.

  • 스토어드 프로시져
    더 다양한 기능을 제공.
    단, 쿼리 안에서 사용 불가능. 쿼리 외부에서 호출해야 함.

  • 트리거
    기존 프로그래밍 언어의 ‘이벤트 핸들러’와 유사.
    어떤 테이블에 레코드가 추가됐을 때 특정 작업을 수행하는 일 따위를 할 수 있음.

  • 이벤트 핸들러
    트리거와 유사하지만 다소 다름.


스토어드 프로시저의 장점

응용 프로그램의 성능 향상

네트워크 트래픽 감소
여러 개의 쿼리로 처리해야 할 작업을, 단일 쿼리로 처리할 수 있게 되기 때문이다.

보안성 향상
SQL Injection 원천 봉쇄

개발 업무의 구분


스토어드 프로시저의 단점

유지 보수가 어려워진다.
모든 코드가 프로그램 안에 들어있지 않기 때문.

GIT에서 관리가 어렵다.

롤백이 어렵다.

명령 자체의 성능이 감소한다.
특히 mysql에서 성능이 좋지 않다.


— 웹 분야에서 스토어드 프로시져의 사용은 점차 증가하고 있다.


스토어드 프로시져로 Hello World 작성하기

DELIMETER $$ // 구분자를 $$로 변경. ;으로 인한 종결 방지.

CREATE PROCEDURE SP_HELLO()

BEGIN

DECLARE STR CHAR(20) DEFAULT ‘POPI’;

SET STR = ‘HELLO, WORLD’;

SELECT STR;

END $$

DELIMETER ;


CALL SP_HELLO();


기본 변수 사용하기

DECLARE 자료형 [DEFAULT 기본값]

— 기본 변수는 프로시져 내에서만 유효함.


세션 변수

@로 시작하는 변수를 만들면, 세션 변수로 기존 프로그래밍 언어의 전역변수와 비슷한 역할을 하게 된다.

SET @name = ‘woonohyo’;

SELECT NAME INTO @name from user_list limit 1; // @name의 값이 바뀌게 된다.


기본 변수에 값 넣기

DELIMETER $$

CREATE PROCEDURE SP_TEST1()

BEGIN

DECLARE A INT;

SET A = 10;

SET A = A * 2;

SELECT A;

END $$

DELIMITER ;


CALL SP_TEST1();



SELECT INTO 사용하기

쿼리의 결과(스칼라 값)를 변수에 넣을 수 있다.

CREATE PROCEDURE SP_TEST2()

BEGIN

DECLARE A INT;

SELECT COUNT(UID) INTO A FROM USER_INFO;

SELECT A;

END $$

DELIMITER ;


결과값을 테이블에 넣기

CREATE TABLE TEST3(NUM INT);

INSERT INTO TEST3 VALUES(1);

CREATE PROCEDURE SP_TEST3()

BEGIN    

DECLARE A INT DEFAULT 1;

SELECT MAX(NUM) INTO A FROM TEST3;

SET A = A + 1;

INSERT INTO TEST3 VALUES (A);

SELECT * FROM TEST3;

END $$

DELIMITER ;

실행 할 때마다 TEST3의 값이 1씩 증가한다.


매개변수 사용하기

IN parameter: 입력에 사용

OUT parameter: 출력에 사용

 INOUT parameter: 입출력에 사용

CREATE TABLE TEST4 ( 

ID INT PRIMARY KEY AUTO_INCREMENT, 

NAME VARCHAR(20)

);


INSERT INTO TEST4 VALUES (NULL, ‘SHINJI’) (NULL, ‘ASUKA’) (NULL, ‘REI’) (NULL, ‘KAORU');

DELIMTER $$

CREATE PROCEDURE SP_TEST4(IN pname varchar(10))

BEGIN

DECLARE A INT DEFAULT 1;

SELECT * FROM TEST4 WHERE NAME = pname;

END $$

DELIMITER;


CALL SP_TEST4(‘



IF문 사용하기

IF <condition> THEN <statement>

[ELSE IF <condition> THEN <statement>]

[ELSE <statement>]

END IF


WHILE 문 사용하기

WHILE <condition> DO

<statement>

END WHILE



프로시저의 파라미터 중에는 INOUT이 있다. 이는 입/출력 전용임을 뜻한다. 



스토어드 프로시져 실습하기

DELIMITER $$

CREATE PROCEDURE SP_TEST1(IN num INT, INOUT ret INT)

BEGIN

DECLARE n INT;

// 거래 건수가 num 이상인 USER와

SELECT * FROM USER WHERE TRADE_NUM >= num;

// 거래 건수가 num 이상인 MARKET을 선택.

SELECT * FROM MARKET WHERE TRADE_NUM >= num;

SELECT COUNT(*) INTO n FROM USER WHERE TRADE_NUM > num;

SET ret = ret + n;

END $$

DELIMITER ;


SET @n = 10;

CALL SP_TEST1(2, @n); // SP_TEST1(2, 10) 으로 넣으면 INOUT에 상수를 넣었다는 에러 발생.

SELECT @n;



Statement의 생성은 다음과 같이 이루어진다.

CallableStatement cs = c.prepareCall(‘{CALL SP_TEST1(?,?)}’);


저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by 우너효