page.title=SQL 데이터베이스에 데이터 저장하기 page.tags=data storage helpoutsWidget=true trainingnavtop=true @jd:body
데이터베이스에 데이터를 저장하는 작업은 연락처 정보와 같이 반복적이거나 구조적인 데이터에 이상적입니다. 이 클래스에서는 사용자가 SQL 데이터베이스에 대한 기본 사항에 익숙하다는 전제하에 Android에서 SQLite 데이터베이스를 시작하는 데 도움이 되는 유용한 정보를 제공합니다. Android에서 데이터베이스를 사용할 때 필요한 API는 {@link android.database.sqlite} 패키지에 있습니다.
SQL 데이터베이스의 기본 원칙 중 하나는 스키마입니다. 스키마는 데이터베이스의 구성 체계에 대한 공식적인 선언입니다. 스키마는 개발자가 데이터베이스를 생성할 때 사용하는 SQL 문에 반영됩니다. 계약 클래스라고 하는 도우미 클래스를 생성하면 도움이 될 수 있습니다. 계약 클래스는 체계적이고 자기 문서화 방식으로 스키마의 레이아웃을 명시적으로 지정합니다.
계약 클래스는 URI, 테이블 및 컬럼의 이름을 정의하는 상수를 유지하는 컨테이너입니다. 계약 클래스를 사용하면 동일한 패키지 내 모든 클래스에 동일한 상수를 사용할 수 있습니다. 즉, 어느 한 장소에서 컬럼 이름을 변경하면 코드 전체에 변경 사항이 반영됩니다.
계약 클래스를 구성하는 좋은 방법은 클래스의 루트 레벨에 전체 데이터베이스에 전역적인 정의를 추가하는 것입니다. 그런 다음 컬럼을 열거하는 각 테이블에 대해 내부 클래스를 생성합니다.
참고: {@link android.provider.BaseColumns} 인터페이스를 구현함으로써, 내부 클래스는 {@code _ID}라고 하는 기본 키 필드를 상속할 수 있습니다. 커서 어댑터와 같은 일부 Android 클래스의 경우 내부 클래스가 이러한 기본 키 필드를 가지고 있을 것이라 예상합니다. 내부 클래스는 반드시 필요한 것은 아니지만, 데이터베이스가 Android 프레임워크와 조화롭게 작업하는 데 도움이 될 수 있습니다.
예를 들어, 다음 스니펫은 테이블 이름과 단일 테이블의 컬럼 이름을 정의합니다.
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 = "entry"; public static final String COLUMN_NAME_ENTRY_ID = "entryid"; public static final String COLUMN_NAME_TITLE = "title"; public static final String COLUMN_NAME_SUBTITLE = "subtitle"; ... } }
데이터베이스의 모양을 정의한 후에는 데이터베이스 및 테이블을 생성 및 유지하는 메서드를 구현해야 합니다. 다음은 테이블을 생성하고 삭제하는 몇 가지 일반적인 명령문입니다.
private static final String TEXT_TYPE = " TEXT"; private static final String COMMA_SEP = ","; private static final String SQL_CREATE_ENTRIES = "CREATE TABLE " + FeedEntry.TABLE_NAME + " (" + FeedEntry._ID + " INTEGER PRIMARY KEY," + FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP + FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP + ... // Any other options for the CREATE command " )"; private static final String SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;
기기의 내부 저장소에 저장하는 파일과 같이, Android는 데이터베이스를 애플리케이션과 관련된 개인 디스크 공간에 저장합니다. 기본적으로 이 공간은 다른 애플리케이션이 액세스할 수 없기 때문에 저장된 데이터는 안전하게 유지됩니다.
유용한 API 집합이 {@link android.database.sqlite.SQLiteOpenHelper} 클래스에서 제공됩니다. 데이터베이스에 대한 참조를 가져오기 위해 이 클래스를 사용하는 경우, 시스템은 필요한 경우에 한해서만 데이터베이스 생성 및 업데이트와 같이 장시간 실행될 수 있는 작업을 수행하며, 앱이 시작되는 동안에는 이러한 작업을 수행하지 않습니다. {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase} 또는 {@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase}를 호출하기만 하면 됩니다.
참고: 이러한 작업은 장시간 실행될 수도 있기 때문에 {@link android.os.AsyncTask} 또는 {@link android.app.IntentService}와 같이 백그라운드 스레드에서 {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase} 또는 {@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase}를 호출해야 합니다.
{@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()}도 구현해야 하는 경우가 있을 수 있습니다.
다음은 위에 표시된 명령 중 일부를 사용하여 구현한 {@link android.database.sqlite.SQLiteOpenHelper}의 예입니다.
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 = "FeedReader.db"; 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); } }
데이터베이스에 액세스하려면 {@link android.database.sqlite.SQLiteOpenHelper}의 하위 클래스를 인스턴스화합니다.
FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());
{@link android.content.ContentValues} 개체를 {@link android.database.sqlite.SQLiteDatabase#insert insert()} 메서드에 전달하여 데이터를 데이터베이스에 삽입합니다.
// 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);
{@link android.database.sqlite.SQLiteDatabase#insert insert()}의 첫 번째 인수는 테이블 이름입니다. 두 번째 인수는 컬럼 이름을 제공합니다. 프레임워크는 {@link android.content.ContentValues}가 비어있을 경우 여기에 NULL을 삽입할 수 있습니다. 만약 이를 {@code "null"}로 설정할 경우, 값이 없으면 프레임워크가 행을 삽입하지 않습니다.
데이터베이스로부터 정보를 읽어오려면 {@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} 개체로 반환됩니다.
SQLiteDatabase db = mDbHelper.getReadableDatabase(); // Define a projection 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 );
커서 안의 행을 보려면 {@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()}를 호출하여 가져올 수 있습니다. 예를 들면 다음과 같습니다.
cursor.moveToFirst(); long itemId = cursor.getLong( cursor.getColumnIndexOrThrow(FeedEntry._ID) );
테이블에서 행을 삭제하려면 행을 식별하는 선택 기준을 제공해야 합니다. 데이터베이스 API는 SQL 삽입을 방지하는 선택 기준을 생성하는 메커니즘을 제공합니다. 이 메커니즘은 선택 사양을 선택 절과 선택 인수로 나눕니다. 절은 보려는 컬럼을 정의하고, 이를 통해 컬럼 테스트를 결합할 수 있습니다. 인수는 절 안에 묶여 테스트되는 값입니다. 이 결과는 일반 SQL 문과 같이 처리되지 않기 때문에 SQL 삽입의 영향을 받지 않습니다.
// Define 'where' part of query. String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?"; // Specify arguments in placeholder order. String[] selectionArgs = { String.valueOf(rowId) }; // Issue SQL statement. db.delete(table_name, selection, selectionArgs);
데이터베이스 값의 하위 세트를 수정해야 하는 경우, {@link android.database.sqlite.SQLiteDatabase#update update()} 메서드를 사용합니다.
테이블을 업데이트하면 {@link android.database.sqlite.SQLiteDatabase#insert insert()}의 콘텐츠 값 구문과 {@link android.database.sqlite.SQLiteDatabase#delete delete()}의 {@code where} 구문이 결합됩니다.
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 + " LIKE ?"; String[] selectionArgs = { String.valueOf(rowId) }; int count = db.update( FeedReaderDbHelper.FeedEntry.TABLE_NAME, values, selection, selectionArgs);