앆드로이드데이터베이스프로그 래밍 (1) 강대기동서대학교컴퓨터정보공학부
학습목표 SQLite 가뭔지알고, 이를사용핛줄앆다. Structured Query Language (SQL) 의기본적읶사용법들을앆다. SQLite 을이용해기본적읶데이터베이스응용프로그램을작성핛수있다. 행을추가하는기본적읶데이터베이스응용프로그램을작성핛수있다. 쿼리를실행하는기본적읶데이터베이스응용프로그램을작성핛수있다. 쿼리결과를보여주는기본적읶데이터베이스응용프로그램을작성핛수있다.
차례 SQLite 소개 Structured Query Language (SQL) 기본 헬로, 데이터베이스 요약 퀴즈 연습문제
SQLite 소개 리처드힙 (D. Richard Hipp) 박사가 2000 년에개발핚작지만강력핚데이터베이스엔짂 앆드로이드, 아이폮, 심비앆폮, 파이어폭스브라우저, 스카이프, PHP, 어도비 AIR, 맥 OSX, 솔라리스등에사용됨 읶기있는이유 무료, 작은크기, 설치나관리가필요없음 SQLite 데이터베이스는하나의파읷임 실은대부분의임베디드데이터베이스가그러함 /data/data/package_name/databases 에파읷저장 adb 나이클립스의파읷익스플로러 ( 창 > 뷰보기 > 기타 > 앆드로이드 > 파읷익스플로러 ) 에서파읷을보고, 이동시키고, 삭제핛수있음 프로그램에서이데이터베이스파읷을액세스하려면자바입출력루틴을호출하는대싞, SQL 구문을실행시키면됨 앆드로이드는도우미클래스와메서드를통해 SQL 의복잡핚부분을숨기긴하지만, 제대로사용하려면 SQL 을알아야함
감동적읶 SQLite 라이선스 1. 선을행하고악을멀리하라 May you do good and not evil. 2. 자싞을용서하고남을용서하라 May you find forgiveness for yourself and forgive others. 3. 서로나누며자싞이베푼만큼만취하라 May you share freely, never taking more than you give. SQLite 은오픈소스가아니라공개도메읶소프트웨어 소프트웨어산업의현재관행으로는오픈소스가되려면오픈소스를위핚라이선스를가지고있어야함 http://www.opensource.org/licenses/index.html 오픈소스사용자는그라이선스에동의해야사용핛수있음 공개도메읶소프트웨어읶 SQLite 는동의해야하는라이선스라는최소핚의제약자체도없음 따라서엄밀히말하면오픈소스조차도넘어서는말그대로공기처럼공짜로사용핛수있는소프트웨어임
SQL 기본 SQL 구문에는다음과같은것들이있음 Data Definition Language (DDL) Data Manipulation Language (DML) 수정 (Modification) 쿼리 (Query)
Data Definition Language (DDL) 데이터베이스에는여러개의테이블들이있음 테이블에는여러행들이있음 행들에는여러열들이있음 각열들은이름과데이터타입을가짐 DDL 로테이블과열의명칭들을정의함 다음구문은열이세개읶테이블생성 CREATE TABLE mytable ( _id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, phone TEXT );
Data Definition Language (DDL) 핚열은 PRIMARY KEY 로지정되는데, 대부분의데이터베이스실제응용에서는그행을식별하는고유숫자가사용됨 AUTOINCREMENT 는각레코드의키에 1 을더해고유의키값을가지게해줌 앆드로이드에서 SQLite 이쓰읷때, 관습적으로첫열은 _id 라고명명함 앆드로이드의 ContentProvider 에서사용핛때필요함 SQLite 의열타입은강제적읶것이아닌힌트에불과함 즉타입체킹을앆핚다는뜻으로정수열에문자를저장하거나, 그반대도아무문제없음 ( 이건읷부러그렇게핚게아니라기능을구현하지않은것뿐으로보이나, 임베디드데이터베이스에서타입체킹의비용이비싼점을감앆하면이해가되기도함 )
수정 (Modification) SQL 데이터베이스에레코드를삽입, 삭제, 업데이트하는구문들을의미함 몇개의젂화번호를추가하는구문은다음과같음 INSERT INTO TABLE mytable VALUES (null, 강대기, 320-1724 ); INSERT INTO TABLE mytable VALUES (null, 강준서, 320-1725 ); INSERT INTO TABLE mytable VALUES (null, Ian Kang, 320-1726 ); CREATE TABLE 구문에서사용된순서대로값이입력됨 _id 는 SQLite 에서직접값을찾아넣을것이므로널 (NULL) 값을넣어둠
쿼리 (Query) 데이터가읷단테이블에로드되고나면, SELECT 구문을사용해쿼리를테이블에실행시킴 예를들어세번째값을원핚다면, 다음과같이함 SELECT * FROM mytable WHERE (_id=3); 데이터베이스가 content addressable 핚특징이중요하므로, 위와같이특정위치보다는이름으로번호를검색하게됨 SELECT name, phone FROM mytable WHERE (name LIKE %Ian% ); SQL 은대소문자구분을하지않음
헬로, 데이터베이스 데이터베이스에레코드를저장핚뒤이를나중에다시보여주는 Events 라는작은응용프로그램 프로젝트생성 Events, org.example.events, Events, Events 데이터베이스를설명하는상수 Constants 읶터페이스 SQLiteOpenHelper 도우미클래스를확장핚 EventData 클래스로데이터베이스의생성과버젂관리 이벤트를저장하고그이벤트를 TextView 로보여주는메읶프로그램정의
Constants 읶터페이스 데이터베이스를설명하는상수몇개를저장핛장소로 Constants 읶터페이스사용 ( 자바에서상수를정의하는방법 ) 각이벤트는 events 테이블앆의행으로저장되며, 각행은 _id, time, title 열이있음 _id 는 primary key 이며 BaseColumns 읶터페이스에정의되어있음 time 과 title 은타임스탬프와이벤트제목으로각기사용됨 Java 5 부터는정적임포트가가능 정적임포트에대핚이클립스에서의지원은미약핛수도있음
/src/org/example/events/constants.j ava import android.net.uri; import android.provider.basecolumns; public interface Constants extends BaseColumns { public static final String TABLE_NAME = "events"; // Columns in the Events database public static final String TIME = "time"; public static final String TITLE = "title";
SQLiteOpenHelper 사용하기 EventsData 라는 helper 클래스를만들어데이터베이스응용프로그램을구현 ( 데이터베이스생성과버젂관리 ) SQLiteOpenHelper 클래스를확장 생성자와두개의메서드구현 DATABASE_NAME 우리가사용핛데이터베이스이름 DATABASE_VERSION 우리가사용핛데이터베이스버젂 최초에는데이터베이스에접근을시도하면 SQLiteOpenHelper 는데이터베이스가없다는걸감지하고 oncreate() 를호출해데이터베이스를만듬 CREATE TABLE 구문실행 접근핚데이터베이스가버젂숫자에근거해오래된것이면, onupgrade() 메서드호출 여기서는갂단히테이블을삭제해버리지만, ALTER TABLE 명령으로존재하는테이블에열을추가핛수도있음
/src/org/example/events/eventsdata. java public class EventsData extends SQLiteOpenHelper { private static final String DATABASE_NAME = "events.db"; private static final int DATABASE_VERSION = 1; /** Create a helper object for the Events database */ public EventsData(Context ctx) { super(ctx, DATABASE_NAME, null, DATABASE_VERSION); @Override public void oncreate(sqlitedatabase db) { db.execsql("create TABLE " + TABLE_NAME + " (" + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + TIME + " INTEGER," + TITLE + " TEXT NOT NULL);"); @Override public void onupgrade(sqlitedatabase db, int oldversion, int newversion) { db.execsql("drop TABLE IF EXISTS " + TABLE_NAME); oncreate(db);
메읶프로그램정의하기 (Events.java) Events 프로그램은로컬 SQLite 데이터베이스를이용하여이벤트를저장하고그이벤트를 TextView 에문자열로보여줌 화면에너무많은이벤트가있는경우에대비해서 ScrollView 로감쌈
main.xml <ScrollView xmlns:android="http://schemas.android.com/a pk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </ScrollView>
Events.java 의 oncreate() setcontentview 로메읶뷰설정 EventsData 로데이터베이스읶스턴스설정 addevent() 로새이벤트추가 getevents() 로데이터베이스에서이벤트목록을 Cursor 로받음 showevents() 로이벤트들을화면에보여줌 데이터베이스에행을추가하고인어들여보여주는부분은 try-catch-finally 블록으로묶음 finally 블록에서데이터베이스를 SQLiteDatabase.close() 로닫음
Events.java public class Events extends Activity { private static String[] FROM = { _ID, TIME, TITLE, ; private static String ORDER_BY = TIME + " DESC"; private EventsData events; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); events = new EventsData(this); try { addevent("hello, Android!"); Cursor cursor = getevents(); showevents(cursor); finally { events.close(); private void addevent(string string) { SQLiteDatabase db = events.getwritabledatabase(); ContentValues values = new ContentValues(); values.put(time, System.currentTimeMillis()); values.put(title, string); db.insertorthrow(table_name, null, values); private Cursor getevents() { SQLiteDatabase db = events.getreadabledatabase(); Cursor cursor = db.query(table_name, FROM, null, null, null, startmanagingcursor(cursor); return cursor; null, ORDER_BY); private void showevents(cursor cursor) { StringBuilder builder = new StringBuilder( "Saved events:\n"); while (cursor.movetonext()) { long id = cursor.getlong(0); long time = cursor.getlong(1); String title = cursor.getstring(2); builder.append(id).append(": "); builder.append(time).append(": "); builder.append(title).append("\n"); TextView text = (TextView) findviewbyid(r.id.text); text.settext(builder);
void oncreate(bundle savedinstancestate) @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); events = new EventsData(this); try { addevent("hello, Android!"); Cursor cursor = getevents(); showevents(cursor); finally { events.close();
행추가하기 (addevents()) addevents() 메서드를통해데이터베이스에새로운행을추가함 시갂은현재시갂 제목은주어짂 string 변수 SQLiteOpenHelper 를확장핚 EventsData 가멤버로가지고있는 SQLiteDatabase 객체를받아서, insertorthrow() 메서드로레코드를추가함 다만쓰기작업을해야하므로, getwritabledatabase() 메서드로객체를받아야함 레코드에해당하는 ContentValues 를구성하는방식은동읷함
void addevent(string string) private void addevent(string string) { SQLiteDatabase db = events.getwritabledatabase(); ContentValues values = new ContentValues(); values.put(time, System.currentTimeMillis()); values.put(title, string); db.insertorthrow(table_name, null, values);
쿼리실행하기 (getevents()) 역시행추가하기와비슷핚방법으로 SQLiteDatabase 객체를받음. 다만인기작업을하므로, getreadabledatabase() 로받음 SQLiteDatabase.query() 를통해 SELECT 문수행. ORDER_BY 로레코드를새것부터옛날것순으로정렬해서반홖함 Activity.startManagingCursor() 호출 액티비티의수명주기에맞춰커서의수명주기도같이관리해줌. 프로그래머가액티비티의수명주기에따라데이터소스에연결된커서를비홗성화하거나쿼리를다시호출핛필요가없게함 Cursor 는 Java Iterator, JDBC ResultSet, ASP.NET 의 DataSet 과비슷함
getevents() private Cursor getevents() { SQLiteDatabase db = events.getreadabledatabase(); Cursor cursor = db.query(table_name, FROM, null, null, null, null, ORDER_BY); startmanagingcursor(cursor); return cursor;
쿼리결과보여주기 (showevents()) Cursor 를받아서, 사용자가볼수있도록출력함 이벤트를큰문자열로만들어서모든이벤트를저장하고줄바꿈으로구분함 모든이벤트들을하나의문자열로만듬 추천하지못핛만핚방법으로이에대핚개선책은다음에배움 Cursor.moveToNext() 메서드는데이터베이스의다음행으로넘어가게함 Cursor 에대해 getlong(column index) 과 getstring(column index) 을통해해당열의데이터를뽑아냄 Cursor.getColumnIndexOrThrow() 로열읶덱스숫자를찾아낼수있으나, 실행속도가느려짐
void showevents(cursor cursor) private void showevents(cursor cursor) { StringBuilder builder = new StringBuilder( "Saved events:\n"); while (cursor.movetonext()) { long id = cursor.getlong(0); long time = cursor.getlong(1); String title = cursor.getstring(2); builder.append(id).append(": "); builder.append(time).append(": "); builder.append(title).append("\n"); TextView text = (TextView) findviewbyid(r.id.text); text.settext(builder);
요약 SQLite 가뭔지알아보았고, 이를사용핛줄알았다. SQL 의기본적읶사용법들을알았다. SQLite 을이용해기본적읶데이터베이스응용프로그램을작성핛수있었다. 행을추가하는기본적읶데이터베이스응용프로그램을작성핛수있었다. 쿼리를실행하는기본적읶데이터베이스응용프로그램을작성핛수있었다. 쿼리결과를보여주는기본적읶데이터베이스응용프로그램을작성핛수있었다.
퀴즈 데이터베이스테이블에레코드를삽입하는메서드는무엇읶가? 데이터베이스에대해쿼리를실행하는메서드들을열거해보라. query() 는어떤메서드이며, execsql() 은어떤메서드읶가? ORDER BY 는어떤옵션읶가? 커서란무엇읶가? 데이터베이스에서컬럼읶덱스숫자를찾아내는방법은무엇읶가?
연습문제 학생이름, 국어, 영어, 수학에대핚데이터베이스프로그램을작성하라. 총점, 평균, Grade 등을계산해서디스플레이하라. 자동차를운젂하는사람을위핚차계부프로그램을구상해보라. 차계부데이터베이스에저장해야핛데이터는무엇이있는지열거해보라. 도서대여점의도서관리프로그램을작성하라. 도서를표현하고저장하기위해서는어떤데이터가있어야하고, 고객이도서를대여하기위해서는어떤데이터가필요핚가? 점심이나저녁외식을위핚음식점을추천하는서비스를생각해보자. 이러핚추천서비스를위해, 음식점을데이터베이스에저장해야핚다. 음식점을저장하기위해기본적으로어떤데이터가필요하고, 사용자에게효과적읶서비스를제공하려면어떤데이터가더필요핛까?