유저 생성

1
2
3
CREATE USER '유저명'@'%' IDENTIFIED BY '비밀번호'; -- 모든 아이피 접근
CREATE USER '유저명'@'localhost' IDENTIFIED BY '비밀번호'; -- 로컬호스트 접근
CREATE USER '유저명'@'127.0.0.1' IDENTIFIED BY '비밀번호'; -- 로컬호스트 접근

데이터베이스에 모든 권한 부여

1
2
-- 해당 디비명의 유저의 모든권한 설정
GRANT ALL PRIVILEGES ON 디비명.* TO '유저명'@'%' WITH GRANT OPTION;

권한 적용

1
FLUSH PRIVILEGES;

권한 확인

1
SHOW GRANTS FOR '유저명'@'%';

여담

권한 부여는 쉘상에서 접근해야지 오류가 없다.

부분 권한 또는 부분 테이블로 권한을 제한하고 싶다면, MySQL Grant Syntax를 참조한다.

@Rownum 변수를 사용해 페이징 쿼리를 구현했는데, MySQL 에서는 정상적으로 정렬이 되다가 Maria 로 이관 후에 정렬이 반대로 나오는 경우가 있다.

오류

쿼리

1
2
3
4
5
6
7
8
9
SELECT SQL_CALC_FOUND_ROWS @RNUM:=@RNUM+1 AS ROWNUM, R.* FROM (
SELECT @RNUM:=0, Q.* FROM (

SELECT * FROM TABLE1
WHERE ID = '1'
ORDER BY REG DESC
) Q
) R
LIMIT 0,10

설명

Rownum 변수를 사용해 TABLE1 에서 최신 날짜 순으로 데이터를 가지고 온다.

해결

LIMIT 2^64-1를 서브쿼리 내에 추가해준다.

LIMIT 의 최댓값은 unsigned 64bit-1 이므로 해당 값을 날려준다.

쿼리

1
2
3
4
5
6
7
8
9
10
11
SELECT SQL_CALC_FOUND_ROWS @RNUM:=@RNUM+1 AS ROWNUM, R.* FROM (
SELECT @RNUM:=0, Q.* FROM (

SELECT * FROM TABLE1
WHERE ID = '1'
ORDER BY REG DESC

LIMIT 18446744073709551615
) Q
) R
LIMIT 0,10

원인

Optimizer 가 임시테이블을 만든 후 filesort 하기 때문에 발생한다.

Database Migration 또는 Module 설치시 MySQL 버전을 자주 물어본다.

쿼리

1
2
3
SELECT version();

SHOW variables LIKE 'datadir';

설명

첫번째 쿼리 실행시 버전이 나오고, 두번째 쿼리 실행시 설치 경로가 나온다.

잘못된 업데이트 쿼리를 돌리다가 테이블이 잠길 경우 Lock을 해제해줘야 한다.

쿼리

1
2
3
show processlist

kill ${processid}

설명

show processlist 쿼리를 날리면 현재 database를 사용 중인 프로세스의 목록이 나온다.
목록에서 해당 쿼리를 찾은 뒤 process id를 가지고 kill 쿼리를 실행하면 된다.

MySQL Workbench에서 database 연결 도중 connection using old (pre-4.1.1) authentication protocol refused와 같은 오류가 발생시 다음과 같이 해결하자.

원인

서버에 설치된 MySQL 버전이 5.1보다 낮아서이다.

해결방법

연결시 Advanced 탭에서 Use the old authentification protocol을 체크해주자.

스마트 에디터 같은 에디터를 쓸 대 내용을 텍스트로만 받아야할 경우가 있다.

예제

1
var data = data.replace(/[<][^>]*[>]/g, '');

설명

< > 안의 태그들을 모두 빈값으로 치환한다.

database 에 이미 json 으로 저장된 데이터를 가져와 JSON.parse 메소드로 JSON 데이터를 파싱하는 중에 값이 string 인데도 오류가 나는 경우가 있다.

로그를 확인해보면

1
{"data":"[{"name":"gracefullight"},{"name","daniel"}]"}

[] 배열 기호 앞뒤로 따움표가 들어가 있다.
이중 object 가 있다면 선언문 {} 앞뒤로 따움표가 들어가 파싱 오류가 난다.

원인

jQuery.ajax 의 dataType 을 json 으로 설정해 데이터를 받는데, 이미 json 형태의 string 이 넘어와 두번 치환이 된 것 같다.

다시 json 을 인식할 수 있게 치환해보자

소스

1
2
3
4
5
6
7
8
9
10
var jsonReplace = function (j) {
if (j) {
j = j
.replace(/\"\[/g, '[')
.replace(/\]\"/g, ']')
.replace(/\"\{/g, '{')
.replace(/\}\"/g, '}');
}
return j;
};

설명

해당 함수로 오류가 나는 json string 을 치환 후에 다시 JSON.parse 를 실행하면 된다.

여담

정규식을 활용해 replace 중첩을 피하게 짤 수 있을 것 같은데…

hasOwnProperty

for-in 구문을 쓸 때 상속된 프로퍼티나 this 구문을 방지하기 위하여 보통 hasOwnProperty 로 체크한다.

1
2
3
4
5
for (prop in obj) {
if (obj.hasOwnProperty(prop)) {
// code...
}
}

문제점

위와 같은 방식은 아래와 같이 hasOwnProperty 가 재정의 된 객체에서 오류를 발생할 수 있다.

소스

1
2
3
4
5
6
7
8
9
10
11
12
13
var obj = {
hasOwnProperty: function () {
return false;
},
data1: 1,
};

for (prop in obj) {
// obj.hasOwnproperty(prop) 의 결과는 항상 false
if (obj.hasOwnproperty(prop)) {
// 이 구문은 실행되지 않는다.
}
}

prototype.hasOwnProperty

따라서 prototype 을 사용해 코딩해야한다.

소스

1
2
3
4
5
6
7
8
9
for (prop in obj) {
// 첫번째 방법
if ({}.hasOwnProperty.call(obj, prop)) {
}

// 두번째 방법
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
}
}

설명

첫번째 방법은 익명 Object 를 생성한 후 obj 와 prop 을 밀어넣는 방식이고
두번째 방법은 기본 Object 의 hasOwnProperty 를 가져와 obj 와 prop 을 밀어넣는 방식이다.

두번째 방법이 새(익명) Object 를 생성하지 않기에 이 방법을 사용하면 된다.

더 자세하게 알고 싶다면 mdn을 참조한다.

javascript throttle 패턴과 debounce 패턴에 대해 알아보자.

Throttle

매 ms 마다 한 번만 호출된다.
mousemove, scroll 같은 이벤트로 호출되는 함수는 이벤트 발생시 무한정 호출되어 성능 저하를 가지고 오는데, 이를 방지할 수 있다.

모바일에서 스크롤링 더보기에 사용할 수 있다.

소스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var throttleFunction = (function () {
'use strict';

var timeWindow = 500; // 여기에 시간(ms)을 지정한다
var lastExecution = new Date(new Date().getTime() - timeWindow);
// ES6 이하일 경우 ...args에 호출할 parameter 만큼 준다 function(arg1, arg2...)
var throttleFunction = function (...args) {
// 여기에 로직을 구현한다
};

return function () {
if (lastExecution.getTime() + timeWindow <= new Date().getTime()) {
lastExecution = new Date();
return throttleFunction.apply(this, arguments);
}
};
})();

// 사용법
throttleFunction(param1, param2);

Debounce

마지막 호출로부터 ms 후에 함수를 한번 호출한다.
지연된 호출을 할 수 있게 해주는데, 호출이 반복되는 동안은 실행을 방지하고, 호출이 멈춘 뒤 지정한 ms 후에 함수를 실행해 성능 저하를 막을 수 있다.

검색 자동완성 기능에 적합하다.

소스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var debounceFunction = (function () {
'use strict';

var timeWindow = 500; // 여기에 시간(ms)을 지정한다
var timeout;
// ES6 이하일 경우 ...args에 호출할 parameter 만큼 준다 function(arg1, arg2...)
var debounceFunction = function (...args) {
// 여기에 로직을 구현한다
};

return function () {
var context = this;
var args = arguments;

clearTimeout(timeout);
timeout = setTimeout(function () {
debounceFunction.apply(context, args);
}, timeWindow);
};
})();

// 사용법
debounceFunction(param1, param2);

여담

즐겨 사용하는 sublime text package 인 javascript patterns에서 참조했다.

lodash를 사용한다면 debounce, throttle로 더 쉽게 사용할 수 있다.

UMD (Universal Module Definition) Pattern 이란
AMD (requireJS), CommonJS (node), 일반 browser 환경에서 통합해서 쓸 수 있는 javascript module pattern 이다.

jQuery, moment, D3 등의 라이브러리에서도 해당 패턴을 사용한다.

예제 - jQeury 종속형

새로 만들 예제의 모듈명은 module1 이고 jQuery 에 종속적이라고 가정한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(function (global, factory) {
if (typeof define === 'function' && define.amd) {
// AMD 환경
define(['exports', 'jquery'], factory);
} else if (
typeof exports === 'object' &&
typeof exports.nodeName !== 'string'
) {
// CommonJS 환경
factory(exports, require('jquery'));
} else {
// 일반 브라우저
factory((global.module1 = global.module1 || {}), global.$);
}
})(this, function (exports, $) {
// module1의 private 기능 구현

// exports에 public function을 붙혀주면 된다.
exports.action = function () {};
});

종속되는 모듈을 추가하려면, AMD 는 배열안에, commonJS 와 일반은 파라미터로 추가한 뒤 12 번째 줄의 콜백함수 안에 원하는 변수로 받으면 된다.

예제 - 기본형

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(function (global, factory) {
if (typeof define === 'function' && define.amd) {
define(['exports'], factory);
} else if (
typeof exports === 'object' &&
typeof exports.nodeName !== 'string'
) {
factory(exports);
} else {
factory((global.module1 = global.module1 || {}));
}
})(this, function (exports) {
exports.action = function () {};
});

즉시실행 함수에 window 객체와 함수를 파라미터로 보내서 전역 객체를 생성하는 방식이다.

예제 - 3 항연산자 사용

1
2
3
4
5
6
7
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.module1 = global.module1 || {})));
}(this, (function (exports) {
exports.action = function () {};
}));

설명

window 객체 안에 모듈이 선언되므로, module1.action(); 으로 바로 호출해 사용하면 된다.

더 자세한 설명을 보고싶다면 umd를 참조하면 된다.