[기사] SQLite를 사용해야 하는 이유[기사] SQLite를 사용해야 하는 이유

Posted at 2019. 2. 22. 11:28 | Posted in 카테고리 없음
반응형




출처 : http://www.itworld.co.kr/news/117213?fbclid=IwAR2njDWPRIZqDYPcyC8FigrKSpV4couJ6G_a1muCqUs0YLGHuM_07oGqhyg




모든 비즈니스 애플리케이션의 내부에는 구조적 데이터를 저장하고 사용하는 나름의 방법이 구현돼 있다. 클라이언트 측 앱이든 웹 프론트엔드를 사용하는 앱이든 에지 디바이스 앱이든 대부분의 경우 내장 데이터베이스가 필요하다.


이런 경우를 위해 설계된 SQLite는 내장 가능한 오픈소스 데이터베이스로, C로 작성됐으며 일반적인 SQL로 쿼리가 가능하다. SQLite는 킬로바이트의 데이터를 저장하든 수 기가바이트의 블롭(blob)을 저장하든 빠른 속도와 이식성, 안정성을 제공하도록 설계됐다.







SQLite의 사용 환경

SQLite의 가장 큰 장점 중 하나는 거의 어디에서나 실행 가능하다는 데 있다. SQLite는 윈도우, 맥OS, 리눅스, iOS, 안드로이드를 비롯한 다양한 플랫폼에 이식됐다. 특히 윈도우 사용자는 일반적인 Win32, UWP, WinRT, 닷넷용으로 사전 컴파일된 바이너리를 사용할 수 있다. 앱의 배포 대상이 무엇이든 십중팔구는 그 대상에 맞는 SQLite가 있거나 C 소스 코드를 해당 타겟으로 이식할 방법이 존재한다고 보면 된다.


SQLite를 사용하는 앱은 C로 작성된 외부 라이브러리를 바인딩하고 작업할 수 있는 수단이 있는 한 특정 언어로 작성하지 않아도 된다. SQLite의 바이너리는 그 자체로 완성되어 있으므로 배포를 위한 특별한 방법이 필요 없으며, 그냥 애플리케이션과 동일한 디렉토리에 넣으면 된다

.

많은 언어에는 SQLite를 위한 고수준 바인딩이 라이브러리로 존재한다. 또한 이 라이브러리를 해당 언어를 위한 다른 데이터베이스 액세스 계층과 함께 사용할 수 있다. 예를 들어 파이썬은 파이썬 인터프리터 기본 버전과 함께 SQLite 라이브러리를 표준 번들 요소로 제공한다. 또한 SQLite를 사용하는 다양한 서드파티 ORM 및 데이터 계층이 있으므로 원시 SQL 문자열(불편할 뿐만 아니라 위험하기도 함)을 통해서만 SQLite에 액세스할 필요도 없다.


마지막으로, SQLite의 소스 코드는 공개돼 있으므로 실질적으로 아무런 제약 없이 다른 프로그램에서 재사용할 수 있다.

 

SQLite의 장점

SQLite의 가장 일반적이며 대표적인 사용례는 전통적인 테이블 지향 관계형 데이터베이스 역할이다. SQLite는 트랜잭션과 원자성 동작을 지원하므로 프로그램 충돌이나 정전이 발생하더라도 데이터베이스가 손상되지 않는다.


SQLite에는 전체 텍스트 인덱싱, JSON 데이터 지원 등 고급 데이터베이스에서 볼 수 있는 여러 기능이 있다. 일반적으로 YAML 또는 XML과 같이 반구조적인 형식으로 저장되는 애플리케이션 데이터는 SQLite 테이블로 저장할 수 있으므로 데이터에 더 쉽게 액세스하고 더 신속하게 처리할 수 있다.


SQLite는 프로그램의 구성 데이터를 저장하는 빠르고 강력한 수단도 제공한다. 개발자는 YAML과 같은 파일 형식을 파싱하는 대신 SQLite를 이러한 파일의 인터페이스로 사용할 수 있다. 대부분의 경우 이 편이 수작업보다 훨씬 더 빠르다. SQLite는 메모리 내 데이터로 작업하거나 외부 파일(CSV 파일 등)을 네이티브 데이터베이스 테이블처럼 사용할 수 있으므로 편리한 데이터 쿼리가 가능하다.


SQLite는 단일 독립형 바이너리이므로 앱과 함께 배포하고 필요에 따라 앱과 함께 이동하기도 쉽다. SQLite에 의해 생성되는 각 데이터베이스 역시 하나의 파일로 구성되며 SQL 명령으로 이 파일을 압축하거나 최적화할 수 있다.


SQLite용 서드파티 바이너리 확장으로 더 많은 기능을 추가할 수 있다. SQLCipher는 SQLite 데이터베이스 파일에 256비트 AES 암호화를 추가한다. SQLite-Bloomfilter는 특정 필드의 데이터에서 블룸 필터를 생성할 수 있게 해준다.


그 외에도 많은 서드파티 프로젝트가 SQLite를 위한 부가적인 도구를 제공한다. 예를 들어 비주얼 스튜디오 코드 내에서 데이터베이스를 탐색할 수 있게 해주는 비주얼 스튜디오 코드 확장 또는, SQLite용 LiteCLI 인터랙티브 명령줄이 있다. 그 외에도 깃허브의 추천 SQLite 리소스 목록에서 많은 도구를 찾을 수 있다.

 

SQLite vs. MySQL

SQLite와 가장 자주 비교되는 대상은 MySQL(또는 마리아DB)이다. MySQL은 오늘날 애플리케이션 스택의 주된 요소로 광범위하게 사용되는 오픈 소스 데이터베이스 제품이다. SQLite와 MySQL은 비슷한 점 못지않게 차이점도 많으므로 각 사용 사례에 따라 적합한 쪽을 선택하면 된다.


- 데이터 형식

SQLite의 데이터 형식은 비교적 소수다(BLOB, NULL, INTEGER, TEXT). 반면 MySQL(또는 마리아DB)의 경우 날짜와 시간을 위한 전용 데이터 형식, 정수와 실수를 위한 다양한 정밀도를 비롯해 훨씬 더 많은 형식이 있다.


비교적 적은 수의 데이터 형식을 저장하거나 데이터 계층을 사용하여 데이터 검증을 수행하려면 SQLite가 유용하다. 그러나 데이터 계층에서 자체 검증 및 정규화 기능을 제공하도록 하려면 MySQL(또는 마리아DB)을 사용해야 한다.


- 구성 및 튜닝

SQLite에는 최소한의 구성 및 튜닝 옵션만 제공된다. SQLite의 내부 또는 명령줄 플래그는 대부분 극한 사례(edge case)나 하위 호환성 문제와 관련된다. 이는 간소함을 추구하는 SQLite의 원칙에도 부합한다. 즉, 대부분의 사용 사례에서는 기본 옵션으로 충분하다.


MySQL(또는 마리아DB)에는 콜레이션(collation), 인덱싱, 성능 튜닝 등 데이터베이스 및 설치 관련 구성 옵션이 까마득하게 많다. 옵션이 풍부한 만큼 MySQL이 훨씬 더 많은 기능을 제공한다. MySQL을 사용하는 경우 손을 댈 부분이 더 많지만, 그 이유는 대부분 애초에 MySQL을 사용해서 더 많은 일을 하고자 하기 때문이다.


- 단일 사용자 대 복수 사용자 데이터베이스

SQLite는 데스크톱 또는 모바일 앱과 같이 동시 사용자가 한 명인 애플리케이션에 가장 적합하다. MySQL과 마리아DB는 여러 명의 동시 사용자에 대응하도록 설계됐다. 또한 MySQL과 마리아DB는 클러스터 및 수평 확장 솔루션을 제공할 수 있지만 SQLite는 할 수 없다.

 

SQLite vs. 임베디드 베이스

SQLite 외에도 내장 가능한 데이터베이스는 많다. 비슷한 기능을 제공하는 데이터베이스도 여러 개 있지만 중점을 두는 사용 사례나 배포 모델은 각기 다르다.


- 아파치 더비(Apache Derby) : 내장 가능한 SQL 엔진이며 오라클이 자바 DB로 리패키징했다. 더비는 자바로 작성됐고 JVM이 필요하므로 주로 자바 앱에 내장하는 용도에 적합하다.


- 파이어버드 임베디드(Firebird Embedded) : 크로스 플랫폼이며 많은 고급 기능을 자랑하는 파이어버드 데이터베이스는 클라이언트 애플리케이션에 내장 가능한 라이브러리 형태로 제공된다. 기능은 SQLite와 비슷하지만 사용자 커뮤니티와 지원 기반은 SQLite 쪽이 훨씬 더 넓다.


- 렐름(Realm) : 고성능 관계형 데이터베이스로 모바일 환경, 주로 안드로이드에 맞게 설계됐지만 윈도우와 같은 데스크톱 환경도 지원할 수 있다. 단, 렐름은 객체 기반이며 SQL 쿼리를 사용하지 않는다. SQL을 사용하지 않는 편을 선호하는 경우 적합하지만 SQL이 익숙하고 편안한 사람에게는 적합하지 않다.


- 비스타DB(VistaDB) : 닷넷 런타임용 내장 데이터베이스다. 비스타DB는 닷넷의 다양한 변형에 맞는 여러 버전으로 제공되며, 전체 데이터베이스 암호화와 같은 엔터프라이즈 기능을 다수 제공한다. 오픈소스가 아닌 상용 제품이다.


- 버클리 DB(Berkeley DB) : 오라클 프로젝트로, 명목상 키/값 저장소지만 최근 버전에서는 SQL 쿼리를 처리하기 위한 방편으로 SQLite를 사용한다. 여러 개의 동시 쓰기 작업을 처리하는 기능 등 버클리 DB 기반 데이터베이스 엔진의 향상된 성능은 SQLite가 따라가지 못하는 부분이다.

 

SQLite가 적합하지 않은 경우

SQLite는 설계 원칙상 잘 맞는 시나리오와 그렇지 않은 시나리오가 뚜렷이 구분된다. SQLite가 적합하지 않은 경우는 다음과 같다.


- SQLite가 지원하지 않는 기능을 사용하는 앱. SQLite는 여러 가지 관계형 데이터베이스 기능을 지원하지 않으며 많은 경우 앞으로도 지원할 예정이 없다. 대체로 코너 케이스에 해당하는 기능이지만, 그 기능이 필요하다면 사용할 수 없다.


- 수평 확장 설계가 필요한 앱. SQLite 인스턴스는 단일체이며 독립적이고, 인스턴스 간 기본 동기화 기능이 없다. 또한 여러 개를 연합하거나 클러스터를 만들 수 없다. 따라서 수평 확장 설계를 사용하는 애플리케이션에서는 SQLite를 사용할 수 없다.


- 여러 연결에서의 동시 쓰기 작업을 실행하는 앱. SQLite는 쓰기 작업 시 데이터베이스를 잠그므로 여러 동시 쓰기 작업이 실행되는 앱에서는 성능 문제가 발생할 수 있다. 다만 여러 동시 읽기 작업을 실행하는 앱은 대체로 빠르게 실행된다. SQLite 3.7.0 이상은 여러 쓰기 작업의 속도를 높이기 위한 로그 선행 기입(Write-Ahead Logging)을 제공하지만 몇 가지 제약이 따른다. 대안으로는 위에 언급한 버클리 DB가 있다.


- 강한 데이터 형식 지정이 필요한 앱. SQLite의 데이터 형식은 비교적 소수다. 예를 들어 기본 datetime 형식이 없다. 따라서 애플리케이션에서 이러한 형식을 처리해야 한다. 애플리케이션이 아닌 데이터베이스에서 datetime 값을 위한 입력을 정규화하고 제약하고자 한다면 SQLite는 적합하지 않다.






반응형
//

[PHP] 배열인지 아닌지를 확인하는 is_array() 함수[PHP] 배열인지 아닌지를 확인하는 is_array() 함수

Posted at 2019. 2. 21. 10:40 | Posted in PHP
반응형




■ 해당 변수가 배열인지 아닌지를 체크하는 is_array( ) 함수




# 소스 코드

<?php

$idol = array(

  "twice" => "sana"

, "redvelvet" => "wendy"

, "lovelyz" => "kei"

, "momoland" => "dasiy"

);

// is_array는 배열인 경우 1을 리턴한다.

if(is_array($idol) == 1) {

echo "$idol은 배열입니다.";

} else {

echo "$idol은 배열이 아닙니다.";

}

?> 




# 출력 결과







반응형
//

[Node.js] Node.js 채팅방 제작[Node.js] Node.js 채팅방 제작

Posted at 2019. 2. 12. 00:44 | Posted in Node.js
반응형





해당 채팅은 의 코드를 필자의 사용목적에 맞게 변경한 것이다.

 

 -. 채팅방 기능 추가

 -. 채팅방 입장기능 추가

 -. 전역변수에 접속한 사용자 값을 담고 퇴장시 socket.io의 값을 대조하여 퇴장 이벤트 실행

    (퇴장이벤트를 위해 사용하는데 실 운영시에는 DB 및 저장소 기능을 사용하는것을 권장한다.)




 socket.chatting.app.js

// 모듈을 추출한다. - http://localhost:52273
var http = require("http");
var fs = require("fs");
var socketio = require("socket.io");

// 웹 서버를 생성한다.
var server = http.createServer(function(request, response) {

    // HTMLPage.html 파일을 읽는다.
    fs.readFile("node_chatting.html", function(error, data) {

        response.writeHead(200, {"Content-Type" : "text/html"});
        response.end(data);
    });
}).listen(52273, function() {

    console.log("Server Running at http://127.0.0.1:52273");
});

// 소켓 서버를 만든다.
var io = socketio.listen(server);

// 접속한 사용자의 방이름, 사용자명, socket.id값을 저장할 전역변수
const loginIds = new Array();

io.sockets.on("connection", function(socket) {

    // 채팅방 입시 실행
    socket.on("access", function(data) {

        // console.log(io.sockets.adapter.rooms);

        socket.leave(socket.id);
        socket.join(data.room);

        loginIds.push({
              socket : socket.id  // 생성된 socket.id
            , room : data.room  // 접속한 채팅방의 이름
            , user : data.name   // 접속자의 유저의 이름
        });

        // 사용자가 페이지 새로고침시 loginIds 변수에 값이 누적되지 않게 동일한 사용자의 socket.id 값을 삭제한다.
        for(var num in loginIds) {

            // 사용자 이름이 같으면서, 기존소켓아이디와 현재 소켓아이디가 다른 값이 있는지 찾아낸다.
            if(loginIds[num]['user'] == data.name && loginIds[num]['socket'] != socket.id) {
               
                // loginIds의 해당 순서의 값을 삭제한다.
                loginIds.splice(num, 1);
            }
        }

        // 클라이언트의 Contact 이벤트를 실행하여 입장한 사용자의 정보를 출력한다.
        io.sockets.in(data.room).emit("contact", {
              count : io.sockets.adapter.rooms[data.room].length
            , name : data.name
            , message : data.name + "님이 채팅방에 들어왔습니다."
        });
    });

    // 채팅방 퇴장시 실행(Node.js에서 사용자의 Disconnect 이벤트는 사용자가 방을 나감과 동시에 이루어진다.)
    socket.on("disconnect", function() {

        var room = "";
        var name = "";
        var socket = "";
        var count = 0;
       
        // disconnect 이벤트중 socket.io의 정보를 꺼내는데는 에러가 발생하고,
        // 실행중인 node.js Application이 종료된다.
        // 이에따라 try ~ catch ~ finally 로 예외처리해준다.
        try {
           
            // 생성된 방의 수만큼 반복문을 돌린다.
            for(var key in io.sockets.adapter.rooms) {

                // loginIds 배열의 값만큼 반복문을 돌린다.
                var members = loginIds.filter(function(chat) {
                    return chat.room === key;
                });
   
                // 현재 소켓 방의 length와 members 배열의 갯수가 일치하지 않는경우
                if(io.sockets.adapter.rooms[key].length != members.length) {
               
                    // 반복문으로 loginIds에 해당 socket.id값의 존재 여부를 확인한다.
                    for(var num in loginIds) {

                        // 일치하는 socket.id의 정보가 없을경우 그 사용자가 방에서 퇴장한것을 알 수 있다.
                        if(io.sockets.adapter.rooms[key].sockets.hasOwnProperty(loginIds[num]['socket']) == false) {

                            // 퇴장한 사용자의 정보를 변수에 담는다.
                            room = key;
                            name = loginIds[num]['user'];

                            // loginIds 배열에서 퇴장한 사용자의 정보를 삭제한다.
                            loginIds.splice(num, 1);
                        }
                    }
                   
                    // 해당 방의 인원수를 다시 구한다.
                    count = io.sockets.adapter.rooms[key].length;
                }
            }

        } catch(exception) {

            console.log(exception);

        } finally {

            // 클라이언트의 Contact 이벤트를 실행하여 이탈한 사용자가 누군지 알린다.
            io.sockets.in(room).emit("contact", {
                  count : count
                , name : name
                , message : name + "님이 채팅방에서 나갔습니다."
            });
           
        }
      });

    // 메세지 전송 이벤트
    socket.on("message", function(data) {

        // 클라이언트의 Message 이벤트를 발생시킨다.
        io.sockets.in(data.room).emit("message", data);
    });
});





 node_chatting.html

<html>
<head>
<title>:: socket.io.chat ::</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" />
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<script type="text/javascript">

    // HTML 문서가 모두 준비되면
    jQuery(document).ready(function() {

        var socket = io.connect();

        // 채팅 창으로 접속 및 전환
        jQuery("#startChatting").click(function() {
            socket.emit("access", {
                  room : jQuery("#inputRoom").val()
                , name : jQuery("#inputName").val()
            });

            location.href = "#chatpage";
            jQuery("#roomName").html(jQuery("#inputRoom").val());
        });

        // 이벤트를 연결합니다.
        socket.on("message", function(data) {

            pushMessage(data.name, data.message, data.date);
        });

        // 채팅방 접속 or 퇴장시 실행되는 알림 메세지
        socket.on("contact", function(data) {
        
            jQuery("#userCount").html(data.count);
            pushMessage(data.name, data.message, new Date().toUTCString());
        });

        // 채팅 메시지를 전송한다.
        jQuery("#submit").click(function() {

            socket.emit("message", {
                  room : jQuery("#inputRoom").val()
                , name : jQuery("#inputName").val()
                , message : jQuery("#inputMessage").val()
                , date : new Date().toUTCString()
            });

            jQuery("#inputMessage").val("");
        });
        });

    function pushMessage(pushName, pushMsg, pushDate) {

        // 입력할 문자 메시지
        var output = "";
        output += "<li>";
        output += "<h3>" + pushName + "</h3>";
        output += "<p>" + pushMsg + "</p>";
        output += "<p>" + pushDate + "</p>";
        output += "</li>";

        // 문서 객체를 추가합니다.
        jQuery(output).prependTo("#content");
        jQuery("#content").listview('refresh');
    };
</script>
</head>
<body>
<div data-role="page">
    <div data-role="header">
        <h1>Socket.io Chat</h1>
    </div>
    <div data-role="content">
        <h3>입장할 방의 이름과 닉네임을 지정해 주세요</h3>
        <div data-role="fieldcontain">
            <label for="textinput">방 이름</label>
            <input id="inputRoom" value=""/>
        </div>
        <div data-role="fieldcontain">
            <label for="textinput">닉 네임</label>
            <input id="inputName" value=""/>
        </div>
        <input type ="button" id="startChatting" value="채팅 시작"/>
        </div>
</div>
<div data-role="page" id="chatpage">
    <div data-role="header">
        <h1>
            <span id="roomName"></span>
            &nbsp;:&nbsp;
            <span id="userCount">0</span>
        </h1>
    </div>
    <div data-role="content">
              <input id="inputMessage" value=""/>
              <input type="button" id="submit" value="입력"/>
              <ul id="content" data-role="listview" data-inset="true"></ul>
        </div>
</div>
</body>
</html>





※ 위 설명에서 말한대로 모던 웹을 위한 Node.js 프로그래밍 코드의 내용을 바탕으로 만들었습니다.

   실 서비스에서는 접속한 사용자의 값을 DB 및 따로 저장소를 만들어 운영하는것을 권장합니다.


※ 혹 개선의 여지가 있음을 아시는 분은 댓글로 남겨주시면 참고하겠습니다.






반응형
//

[jQuery] 화면 단위로 끊어서 마우스 휠로 이동하기[jQuery] 화면 단위로 끊어서 마우스 휠로 이동하기

Posted at 2019. 1. 31. 18:16 | Posted in JavaScript & jQuery/jQuery
반응형




참고 : http://2nusa.blogspot.com/2016/10/jquery-mouse-wheel.html





■ 한화면 단위로 끊어서 마우스 휠 이동시키기





해당코드는 jQuery 한화면 단위 Mouse Wheel 이동 포스팅을 가져와서 만든 내용이다.


위포스팅의 코드를 그대로 사용할 수 없는 상황이 되었기에 필요 부분을 수정하여 포스팅한다.

(파이어 폭스 브라우저에서 에러 발생 및 콘솔창 발생 에러 예외처리)




# 소스코드

<html>

<head>

<title>MouseWheel</title>

<style type="text/css">

    html,body{ margin:0;padding:0;width:100%;height:100%;}

    .box{ width:100%;height:100%;position:relative;color:#FFFFFF;font-size:24pt;}

</style>

<script type="text/javascript" src="http://code.jquery.com/jquery-1.12.4.min.js"></script>

<script type="text/javascript">

    jQuery(document).on("ready", function() {
        jQuery(".box").each(function () {
            
            // 개별적으로 Wheel 이벤트 적용
            jQuery(this).on("mousewheel DOMMouseScroll", function(event) {

                var delta = 0;
                var moveTop = null;
                var boxMax = jQuery(".box").length - 1;

                var winEvent = "";

                  
                if(!winEvent) {
                    winEvent = window.event;
                }

                if(winEvent.wheelDelta) {

                    delta = winEvent.wheelDelta / 120;
                    if(window.opera) {
                        delta = -delta;
                    }
                }

               
                else if(winEvent.detail) {
                    delta = -winEvent.detail / 3;
                }
                
                // 마우스휠을 위에서 아래로 이동
                if(delta < 0) {

                    // 마지막 BOX 보다 순서값이 작은 경우에 실행
                    if(jQuery(this).index() < boxMax) {
                        
                        console.log("▼");
                        if(jQuery(this).next() != undefined) {
                            moveTop = jQuery(this).next().offset().top;
                        }
                    }

                    // 마지막 BOX보다 더 아래로 내려가려고 하는경우 알림창 출력
                    else {
                        alert("마지막 페이지 입니다.");
                        return false;
                    }
                }

                // 마우스휠을 아래에서 위로 이동
                else {

                    // 첫번째 BOX 보다 순서값이 큰 경우에 실행
                    if(jQuery(this).index() > 0) {

                        console.log("▲");
                        if(jQuery(this).prev() != undefined) {
                            moveTop = jQuery(this).prev().offset().top;
                        }
                    }

                    // 첫번째 BOX 더 위로 올라가려고 하는 경우 알림창 출력
                    else {
                        alert("첫번째 페이지 입니다.");
                        return false;
                    }
                }

                // 화면 이동 0.8초(800)
                jQuery("html,body").stop().animate({
                    scrollTop : moveTop + "px"
                }
                , {
                    duration: 800, complete : function () { }
                });
            });
        });
    });
</script>
</head>
<body>
    <div class="box" style="background-color:#FF0000;">1</div>
    <div class="box" style="background-color:#FF4500;">2</div>
    <div class="box" style="background-color:#FFFF00;">3</div>
    <div class="box" style="background-color:#008000;">4</div>
    <div class="box" style="background-color:#0000FF;">5</div>
    <div class="box" style="background-color:#4B0082;">6</div>
    <div class="box" style="background-color:#EE82EE;">7</div>
</body>
</html>




# 출력결과



마우스 휠로 스크롤을 하며 상, 하 스크롤을 진행하다보면.


위 이미지와 같이 자동으로 다음 화면으로 이어지는 것을 확인할 수 있다.










반응형
//