반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 받은 트랙백

글 보관함


Databases on the client side


이번에 다루는 챕터는 jQuery Mobile 에서 제공하는 기능은 아닙니다. HTML5에서 제공하는 기능을 jQuery Mobile 이 활용하는 겁니다. HTML5는 요즘 브라우저에서 대부분 지원하고 있습니다. 특해 대부분의 스마트 폰이나 tablet 들의 브라우저에서도 지원하구 있습니다.


이 기능은 jQuery Mobile 의 기능과 같이 사용되면 아주 유용합니다. 원격 서버가 아닌 local database 에 저장된 데이터에 접근하기 위해 jQuery Mobile 과 함께 사용하는 자바스크립트 프로그램으로 그 기능을 구현할 수 있습니다.


HTML5 offers two types of data storage on the client:


  •  SQL로 만들어진 브라우저 내의 데이터베이스. 저장할 데이터가 많을 경우 이 저장방법을 사용할 수 있습니다.

  • localStorage and sessionStorage objects를 통한 저장공간. string 으로 만들어진 정보를 저장합니다. 데이터베이스보다 제한사항들이 적습니다. 그리고 구현하기가 간단합니다. 적은 양의 정보를 저장하는데 사용합니다.


Permanent storage and session storage


permanent storage 와 session storage의 다른 점은 저장기간에 있습니다.

permanent storage에서는 정보를 유저가 지울 때까지 저장합니다. 즉 그 application이 close 되도 phone 을 껐다가 켜도 그 데이터는 유지가 됩니다.


session storage는 정보가 그 세션의 context 내에서만 저장됩니다. 즉 세션에 저장된 정보는 우리가 만든 사이트의 모든 페이지에서 접근할 수 있지만 그 기간은 application 이 run 하고 있을 때 만입니다. 이 application 이 닫히거나 다른데로 넘어가 버리면 즉 세션이 끝나버리면 그 정보는 없어집니다.


이 두 기능을 구현하기 위해서는 다음 두개의 JavaScript 객체들을 사용하시면 됩니다. : localStorage and sessionStorage:


  • localStorage allows permanent storage,

  • sessionStorage allows storage in the session.


예를 들어 성과 이름을 저장하려면 아래와 같이 하시면 됩니다.


Permanent storage


localStorage.lname = "Sarrion";

localStorage.fname = "Eric";


Session storage


sessionStorage.lname = "Sarrion";

sessionStorage.fname = "Eric";


Using a database


위에서 본 Permanent storage 와 temporary storage 는 SQL 을 사용하는 데이터베이스에서 제공하는 많은 기능들을 제공하지는 않습니다.

이런 데이터베이스를 이용하려면 HTML5 에서 제공하는 SQL 데이터베이스를 자바스크립트를 사용해서 활용하시면 됩니다.


Creating the database



첫번째로 데이터베이스에 대한 access 를 생성합니다. 이게 첫번째로 실행될 경우 그 데이터베이스는 빈 DB 가 되겠죠.


Create access to the database


var db = openDatabase ("Test", "1.0", "Test", 65535);



위 소스에서는 string size 를 65,535 bytes 로 지정했습니다.


Using the database


일단 데이터베이스가 생성됐으면 이제 사용하시기만 하면 됩니다.


  • Creating tables,

  • Inserting data into tables,

  • Retrieving data from the tables,

  • Deleting data,

  • Eventually deleting tables.


데이터 관리하는 방법은 간단합니다. db object 가 recover 됐다면 이제 SQL 명령문을 사용하시면 됩니다.


Using the database


var db = openDatabase ("Test", "1.0", "Test", 65535);

db.transaction (function (transaction) 

{

  var sql = SQL query;

  transaction.executeSql (sql, [parameters] / undefined, 

  function ()

  

    // JavaScript code to execute if the query was successful

    // ...

  }, 

  function ()

  

    // JavaScript code to execute if the query failed

    // ...

  } );

});



parameters들은 배열 형태이고 SQL query 안에서 "?" 로 replace 됩니다. 이 파라미터들은 "?" 가 없으면 사용할 필요가 없습니다.


이어지는 두 함수들옵션인데요 둘 중 하나가 indicated 되지 않았다면 undefined replace 되어야 합니다. 첫번째 함수는 트랜잭션이 성공했을 때 실행되고 두번째 함수는 실패 했을 때 실행됩니다.


두번째 함수의 return 은 중요한 의미가 있죠. request 가 실패했다는 의미이니까요. 이렇게 request 가 실패 했을 때 그 트랜잭션의 request 들을 rollback 하는 부분을 구현해야 합니다. 실패 했을 때 제대로 rollback 하기 위해 해당 함수의 마지막에 true return 하면 됩니다. 그렇지 않다면 성공했다고 간주하게 됩니다.


Example of using a database


customers table로 데이터베이스를 관리할 겁니다. 그러려면 테이블을 생성하고 그 안에 내용을 넣고 지우고 보여주고 하는 기능들을 구현해야죠.


Managing a database of clients locally


<!DOCTYPE html> 

<html> 

<head> 

  <meta name=viewport content="user-scalable=no,width=device-width" />

  <link rel=stylesheet href=jquery.mobile/jquery.mobile.css />

  <script src=jquery.js></script>

  <script src=jquery.mobile/jquery.mobile.js></script>

</head> 


<body> 


<div data-role=page id=home>

  <div data-role=header>

    <h1>Home</h1>

  </div>


  <div data-role=content>

    <a href=# data-role=button id=create> Create customers table </a>

    <a href=# data-role=button id=remove> Delete customers table </a>

    <span> Last name </span>

    <input type=text id=lname>

    <span> First name </span>

    <input type=text id=fname>

    <a href=# data-role=button id=insert> Insert the customer </a>

    <a href=# data-role=button id=list> List customers </a>

  </div>

</div>


<div data-role=page id=win2 data-add-back-btn=true>

  <div data-role=header>

    <h1>List of customers</h1>

  </div>


  <div data-role=content>

  </div>

</div>


</body>

</html>


<script>


var db = openDatabase ("Test", "1.0", "Test", 65535);


$("#create").bind ("click", function (event)

{

  db.transaction (function (transaction) 

  {

    var sql = "CREATE TABLE customers " +

        " (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " +

        "lname VARCHAR(100) NOT NULL, " + 

        "fname VARCHAR(100) NOT NULL)"

    transaction.executeSql (sql, undefined, function ()

    

      alert ("Table created");

    }, error);

  });

});


$("#remove").bind ("click", function (event)

{

  if (!confirm ("Delete table?", "")) return;;

  db.transaction (function (transaction) 

  {

    var sql = "DROP TABLE customers";

    transaction.executeSql (sql, undefined, ok, error);

  });

});


$("#insert").bind ("click", function (event)

{

  var lname = $("#lname").val ();

  var fname = $("#fname").val ();

  

  db.transaction (function (transaction) 

  {

    var sql = "INSERT INTO customers (lname, fname) VALUES (?, ?)";

    transaction.executeSql (sql, [lname, fname], function ()

    

      alert ("Customer inserted");

    }, error);

  });

});


$("#list").bind ("click", function (event)

{

  db.transaction (function (transaction) 

  {

    var sql = "SELECT * FROM customers";

    transaction.executeSql (sql, undefined, 

    function (transaction, result)

    {

      var html = "<ul>";

      if (result.rows.length)

      {

        for (var i = 0; i < result.rows.length; i++) 

        {

          var row = result.rows.item (i);

          var lname = row.lname;

          var fname = row.fname;

          html += "<li>" + lname + "&nbsp;" + fname + "</li>";

        }

      }

      else

      {

        html += "<li> No customer </li>";

      }

      

      html += "</ul>";

      

      $("#win2").unbind ().bind ("pagebeforeshow", function ()

      {

        var $content = $("#win2 div:jqmData(role=content)");

        $content.html (html);

        var $ul = $content.find ("ul");

        $ul.listview ();

      });

      

      $.mobile.changePage ($("#win2"));

      

    }, error);

  });

});


function ok ()

{

}


function error (transaction, err) 

{

  alert ("DB error : " + err.message);

  return false;

}


</script>


tistory573_01.html


쿼리가 데이터베이스에서 기록들을 return 할 경우 자바스크립트 함수는 ResultSet object 에 해당하는 result parameter를 성공적으로 수행했을 때 실행됩니다. 이 쿼리에 의해 생성된 자료들을 담고 있는 rows property 가 생기게 됩니다.


Access to the records returned by a SELECT


for (var i = 0; i < result.rows.length; i++) 

{

  var row = result.rows.item (i);

  var lname = row.lname;

  var fname = row.fname;

  html += "<li>" + lname + "&nbsp;" + fname + "</li>";

}


이 프로그램에서 흥미로운 부분은 리스트를 display 하는 부분 입니다. 화면의 content 로 insert 하기 위해 <ul> list HTML 코드를 사용했습니다. 리스트를 listview () method를 사용해서 listview component 로 변환하는 것은 화면에 들어갈 리스트가 이미 생성돼 있을 때에만 가능합니다.
pagebeforeshow event 가 그 당시 화면이 생성돼 있는지 여부를 체크할 수 있도록 해 줍니다.


unbind () method가 bind () method 이 전에 사용된 점을 유념하세요. bind () method를 성공적으로 call 하면 perform 해야할 일들이 쌓이게 됩니다. (만약 리스트가 여러번 display 되야 하는 경우에요.) unbind ()
method를 call 하면 이전에 add 됐던 모든 이벤트 핸들러들을 remove 합니다.  그러니까 마지막에 우리가 bind ()로 추가한 것만 남게 되죠.


이 소스를 실행시키면 아래와 같은 화면을 보실 수가 있을 겁니다.





customers table 생성의 다른 action 들은 이 테이블이 아직 생성되지 않았을 경우 에러 메세지를 보여줄 겁니다.  일단 생성되면 다른 action들을 취할 수 있습니다. 두개의 클라이언트를 생성하고 list 해 보죠. 해당 버튼을 잘 눌러서요.



Improving the program (continued)


위의 프로그램을 조금 더 개선 시키겠습니다. 리스트에서 한개의 client 를 remove 할 수 있도록요. 이것을 하려면 리스트 아이템에 swipe movement (right)을 감지할 수 있도록 해야 할 겁니다. 오른쪽으로 문지르면 그 아이템이 리스트에서 지워질겁니다. 더불어서 데이터베이스에서도 그 정보가 지워질 거구요.


아래에 이를 위한 구문이 있습니다.


Allow the removal of an item in the list


$("#list").bind ("click", function (event)

{

  db.transaction (function (transaction) 

  {

    var sql = "SELECT * FROM customers";

    transaction.executeSql (sql, undefined, 

    function (transaction, result)

    {

      var html = "<ul>";

      if (result.rows.length)

      {

        for (var i = 0; i < result.rows.length; i++) 

        {

          var row = result.rows.item (i);

          var lname = row.lname;

          var fname = row.fname;

          var id = row.id;

          html += "<li data-icon=false " + "id=" + id + ">";

          html +=   "<a href=#>";

          html +=      lname + "&nbsp;" + fname; 

          html +=   "</a>"; 

          html += "</li>";

        }

      }

      else

      {

        html += "<li> No customer </li>";

      }

      

      html += "</ul>";

      

      $("#win2").unbind ().bind ("pagebeforeshow", function ()

      {

        var $content = $("#win2 div:jqmData(role=content)");

        $content.html (html);

        var $ul = $content.find ("ul");

        $ul.listview ();

        

        $("li").bind ("swiperight", function (event)

        {

          var id = $(this).attr ("id");

          if (!id) return;

          

          $(this).remove ();

          

          db.transaction (function (transaction) 

          {

            var sql = "DELETE FROM customers WHERE id=?";

            transaction.executeSql (sql, [id], function ()

            

              alert ("Customer deleted");

            }, error);

          });

        });        

      });

      

      $.mobile.changePage ($("#win2"));

      

    }, error);

  });

});


<li> list item 은 리스트 아이템에 <a> element 가 삽입되면서 높이가 더 커질 겁니다. 리스트 아이템의 id attribute 는 데이터베이스 안에 있는 client 의 identifier 입니다. 이것으로 해당 client 가 어느 리스트 아이템과 연관된 건지 알수 있습니다. 그래서 해당 리스트 아이템을 지울 때 데이터베이스의 해당 데이터도 지울 수 있는 거죠.


그리고 이제 각 리스트 아이템별로 swiperight event handler 를 연결 시킵니다. 이 이벤트가 발생하면 display 된 해당 리스트 아이템이 remove 될 겁니다. 그리고 나서 데이터베이스의 해당 id 를 가지고 있는 데이터가 지워질 겁니다.



반응형

Comment