blob: e7ca16681e0ecc2d6dacc168af6156ca48c05b77 [file] [log] [blame]
page.title=SQL 데이터베이스에 데이터 저장하기
page.tags=data storage
helpoutsWidget=true
trainingnavtop=true
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2> 과정에서 다루는 내용</h2>
<ol>
<li><a href="#DefineContract">스키마 계약 정의하기</a></li>
<li><a href="#DbHelper">SQL Helper 사용하여 데이터베이스 생성하기</a></li>
<li><a href="#WriteDbRow">데이터베이스에 정보 삽입하기</a></li>
<li><a href="#ReadDbRow">데이터베이스에서 정보 읽어오기</a></li>
<li><a href="#DeleteDbRow">데이터베이스에서 정보 삭제하기</a></li>
<li><a href="#UpdateDbRow">데이터베이스 업데이트하기</a></li>
</ol>
<h2>필독 항목</h2>
<ul>
<li><a href="{@docRoot}guide/topics/data/data-storage.html#db">데이터베이스 사용하기</a></li>
</ul>
<!--
<h2>Try it out</h2>
<div class="download-box">
<a href="{@docRoot}shareables/training/Sample.zip" class="button">Download the sample</a>
<p class="filename">Sample.zip</p>
</div>
-->
</div>
</div>
<p>데이터베이스에 데이터를 저장하는 작업은
연락처 정보와 같이 반복적이거나 구조적인 데이터에 이상적입니다. 클래스에서는 사용자가 SQL 데이터베이스에 대한 기본 사항에
익숙하다는 전제하에
Android에서 SQLite 데이터베이스를 시작하는 도움이 되는 유용한 정보를 제공합니다. Android에서
데이터베이스를 사용할 필요한 API {@link android.database.sqlite} 패키지에 있습니다.</p>
<h2 id="DefineContract">스키마 계약 정의하기</h2>
<p>SQL 데이터베이스의 기본 원칙 하나는 스키마입니다. 스키마는 데이터베이스의 구성 체계에 대한 공식적인
선언입니다. 스키마는 개발자가 데이터베이스를 생성할 사용하는 SQL
문에 반영됩니다. <em>계약</em> 클래스라고 하는
도우미 클래스를 생성하면 도움이 있습니다. 계약 클래스는 체계적이고
자기 문서화 방식으로 스키마의 레이아웃을 명시적으로 지정합니다.</p>
<p>계약 클래스는 URI, 테이블
컬럼의 이름을 정의하는 상수를 유지하는 컨테이너입니다. 계약 클래스를 사용하면 동일한 패키지
모든 클래스에 동일한 상수를 사용할 있습니다. 즉, 어느 장소에서 컬럼
이름을 변경하면 코드 전체에 변경 사항이 반영됩니다.</p>
<p>계약 클래스를 구성하는 좋은 방법은 클래스의 루트 레벨에 전체 데이터베이스에
전역적인 정의를 추가하는 것입니다. 그런 다음 컬럼을 열거하는 테이블에 대해 내부
클래스를 생성합니다.</p>
<p class="note"><strong>참고:</strong> {@link
android.provider.BaseColumns} 인터페이스를 구현함으로써, 내부 클래스는 {@code _ID}라고 하는 기본
필드를 상속할 있습니다. 커서 어댑터와 같은 일부 Android 클래스의 경우
내부 클래스가 이러한 기본 필드를 가지고 있을 것이라 예상합니다. 내부 클래스는 반드시 필요한 것은 아니지만, 데이터베이스가
Android 프레임워크와 조화롭게 작업하는 도움이 있습니다.</p>
<p>예를 들어, 다음 스니펫은 테이블 이름과
단일 테이블의 컬럼 이름을 정의합니다.</p>
<pre>
public final class FeedReaderContract {
// To prevent someone from accidentally instantiating the contract class,
// give it an empty constructor.
public FeedReaderContract() {}
/* Inner class that defines the table contents */
public static abstract class FeedEntry implements BaseColumns {
public static final String TABLE_NAME = &quot;entry&quot;;
public static final String COLUMN_NAME_ENTRY_ID = &quot;entryid&quot;;
public static final String COLUMN_NAME_TITLE = &quot;title&quot;;
public static final String COLUMN_NAME_SUBTITLE = &quot;subtitle&quot;;
...
}
}
</pre>
<h2 id="DbHelper">SQL Helper 사용하여 데이터베이스 생성하기</h2>
<p>데이터베이스의 모양을 정의한 후에는 데이터베이스 테이블을 생성 유지하는
메서드를 구현해야 합니다. 다음은 테이블을 생성하고 삭제하는 가지 일반적인
명령문입니다.</P>
<pre>
private static final String TEXT_TYPE = &quot; TEXT&quot;;
private static final String COMMA_SEP = &quot;,&quot;;
private static final String SQL_CREATE_ENTRIES =
&quot;CREATE TABLE &quot; + FeedEntry.TABLE_NAME + &quot; (&quot; +
FeedEntry._ID + &quot; INTEGER PRIMARY KEY,&quot; +
FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP +
FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +
... // Any other options for the CREATE command
&quot; )&quot;;
private static final String SQL_DELETE_ENTRIES =
&quot;DROP TABLE IF EXISTS &quot; + FeedEntry.TABLE_NAME;
</pre>
<p>기기의 <a href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">내부
저장소</a>에 저장하는 파일과 같이, Android 데이터베이스를
애플리케이션과 관련된 개인 디스크 공간에 저장합니다. 기본적으로 공간은 다른 애플리케이션이
액세스할 없기 때문에 저장된 데이터는 안전하게 유지됩니다.</p>
<p>유용한 API 집합이 {@link
android.database.sqlite.SQLiteOpenHelper} 클래스에서 제공됩니다.
데이터베이스에 대한 참조를 가져오기 위해 클래스를 사용하는 경우, 시스템은
필요한 경우에 한해서만 데이터베이스 생성 업데이트와 같이
장시간 실행될 있는 작업을
수행하며, <em>앱이 시작되는 동안에는 이러한 작업을 수행하지 않습니다</em>.
{@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase} 또는
{@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase}를 호출하기만 하면 됩니다.</p>
<p class="note"><strong>참고:</strong> 이러한 작업은 장시간 실행될 수도 있기 때문에
{@link android.os.AsyncTask} 또는 {@link android.app.IntentService}와 같이 백그라운드 스레드에서 {@link
android.database.sqlite.SQLiteOpenHelper#getWritableDatabase} 또는 {@link
android.database.sqlite.SQLiteOpenHelper#getReadableDatabase}를
호출해야 합니다.</p>
<p>{@link android.database.sqlite.SQLiteOpenHelper}를 사용하려면 {@link
android.database.sqlite.SQLiteOpenHelper#onCreate onCreate()}, {@link
android.database.sqlite.SQLiteOpenHelper#onUpgrade onUpgrade()} 및 {@link
android.database.sqlite.SQLiteOpenHelper#onOpen onOpen()} 콜백 메서드를
재정의하는 하위 클래스를 생성합니다. 반드시 필요한 것은 아니지만
{@link android.database.sqlite.SQLiteOpenHelper#onDowngrade onDowngrade()}도 구현해야 하는
경우가 있을 있습니다.</p>
<p>다음은 위에 표시된 명령 일부를 사용하여 구현한 {@link
android.database.sqlite.SQLiteOpenHelper}의 예입니다.</p>
<pre>
public class FeedReaderDbHelper extends SQLiteOpenHelper {
// If you change the database schema, you must increment the database version.
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = &quot;FeedReader.db&quot;;
public FeedReaderDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_ENTRIES);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// This database is only a cache for online data, so its upgrade policy is
// to simply to discard the data and start over
db.execSQL(SQL_DELETE_ENTRIES);
onCreate(db);
}
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onUpgrade(db, oldVersion, newVersion);
}
}
</pre>
<p>데이터베이스에 액세스하려면 {@link
android.database.sqlite.SQLiteOpenHelper}의 하위 클래스를 인스턴스화합니다.</p>
<pre>
FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());
</pre>
<h2 id="WriteDbRow">데이터베이스에 정보 삽입하기</h2>
<p>{@link android.content.ContentValues}
개체를 {@link android.database.sqlite.SQLiteDatabase#insert insert()} 메서드에 전달하여 데이터를 데이터베이스에 삽입합니다.</p>
<pre>
// Gets the data repository in write mode
SQLiteDatabase db = mDbHelper.getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_ENTRY_ID, id);
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
values.put(FeedEntry.COLUMN_NAME_CONTENT, content);
// Insert the new row, returning the primary key value of the new row
long newRowId;
newRowId = db.insert(
FeedEntry.TABLE_NAME,
FeedEntry.COLUMN_NAME_NULLABLE,
values);
</pre>
<p>{@link android.database.sqlite.SQLiteDatabase#insert insert()}의
번째 인수는 테이블 이름입니다. 번째 인수는
컬럼 이름을 제공합니다. 프레임워크는 {@link android.content.ContentValues}가 비어있을 경우
여기에 NULL 삽입할 있습니다. 만약 이를 {@code "null"}로 설정할 경우,
값이 없으면 프레임워크가 행을 삽입하지 않습니다.</p>
<h2 id="ReadDbRow">데이터베이스에서 정보 읽어오기</h2>
<p>데이터베이스로부터 정보를 읽어오려면 {@link android.database.sqlite.SQLiteDatabase#query query()}
메서드를 사용하고, 선택 기준과 원하는 컬럼을 전달합니다.
메서드는 {@link android.database.sqlite.SQLiteDatabase#insert insert()}
{@link android.database.sqlite.SQLiteDatabase#update update()} 요소를 결합합니다. 단, 삽입하려는 데이터보다는 가져오려는 데이터를
정의하는 컬럼 목록은 예외입니다. 쿼리 결과는
{@link android.database.Cursor} 개체로 반환됩니다.</p>
<pre>
SQLiteDatabase db = mDbHelper.getReadableDatabase();
// Define a <em>projection</em> that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
FeedEntry._ID,
FeedEntry.COLUMN_NAME_TITLE,
FeedEntry.COLUMN_NAME_UPDATED,
...
};
// How you want the results sorted in the resulting Cursor
String sortOrder =
FeedEntry.COLUMN_NAME_UPDATED + " DESC";
Cursor c = db.query(
FeedEntry.TABLE_NAME, // The table to query
projection, // The columns to return
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder // The sort order
);
</pre>
<p>커서 안의 행을 보려면 {@link android.database.Cursor} 이동
메서드 하나를 사용합니다. 메서드는 값을 읽어오기 전에 항상 먼저 호출해야 합니다. 일반적으로 결과의
처음 항목에 "읽기 위치" 배치하는 {@link android.database.Cursor#moveToFirst}를 먼저
호출해야 합니다. {@link android.database.Cursor#getString
getString()} 또는 {@link android.database.Cursor#getLong getLong()}과 같은 {@link android.database.Cursor} 가져오기 메서드
하나를 호출하여 행에 대한 컬럼 값을 읽어올 있습니다. 가져오기 메서드 각각에 대해
원하는 컬럼의 인덱스 위치를 전달해야 하며, 이는
{@link android.database.Cursor#getColumnIndex getColumnIndex()} 또는
{@link android.database.Cursor#getColumnIndexOrThrow getColumnIndexOrThrow()}를 호출하여 가져올 수 있습니다.
예를 들면 다음과 같습니다.</p>
<pre>
cursor.moveToFirst();
long itemId = cursor.getLong(
cursor.getColumnIndexOrThrow(FeedEntry._ID)
);
</pre>
<h2 id="DeleteDbRow">데이터베이스에서 정보 삭제하기</h2>
<p>테이블에서 행을 삭제하려면 행을
식별하는 선택 기준을 제공해야 합니다. 데이터베이스 API SQL 삽입을 방지하는 선택
기준을 생성하는 메커니즘을 제공합니다. 메커니즘은
선택 사양을 선택 절과 선택 인수로 나눕니다. 절은
보려는 컬럼을 정의하고, 이를 통해 컬럼
테스트를 결합할 있습니다. 인수는 안에 묶여 테스트되는 값입니다.
결과는 일반 SQL 문과 같이 처리되지 않기 때문에 SQL 삽입의
영향을 받지 않습니다.</p>
<pre>
// Define 'where' part of query.
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + &quot; LIKE ?&quot;;
// Specify arguments in placeholder order.
String[] selectionArgs = { String.valueOf(rowId) };
// Issue SQL statement.
db.delete(table_name, selection, selectionArgs);
</pre>
<h2 id="UpdateDbRow">데이터베이스 업데이트하기</h2>
<p>데이터베이스 값의 하위 세트를 수정해야 하는 경우, {@link
android.database.sqlite.SQLiteDatabase#update update()} 메서드를 사용합니다.</p>
<p>테이블을 업데이트하면 {@link
android.database.sqlite.SQLiteDatabase#insert insert()}의 콘텐츠 값 구문과
{@link android.database.sqlite.SQLiteDatabase#delete delete()}의 {@code where} 구문이 결합됩니다.</p>
<pre>
SQLiteDatabase db = mDbHelper.getReadableDatabase();
// New value for one column
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
// Which row to update, based on the ID
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + &quot; LIKE ?&quot;;
String[] selectionArgs = { String.valueOf(rowId) };
int count = db.update(
FeedReaderDbHelper.FeedEntry.TABLE_NAME,
values,
selection,
selectionArgs);
</pre>