การจัดเก็บข้อมูล แบบบันทึกลงฐานข้อมูล SQL ของระบบ andorid ตอนที่ 3

เขียนเมื่อ 8 ปีก่อน โดย Ninenik Narkdee
sqlite android sql ฐานข้อมูล

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ sqlite android sql ฐานข้อมูล

ดูแล้ว 9,134 ครั้ง


ได้มีเวลากลับมาศึกษาเกี่ยวกับ Android กันต่อ ห่างหายเนื้อหาสักพัก เช่นเดิม
ข้อมูลทั้งหมดก็จะมาจากเว็บไซต์
 
อันนี้ใครสะดวก ก็สามารถศึกษาไปก่อนได้ เนื่องด้วยผู้เขียนเพิ่งเริ่มศึกษาระบบ Android และต้อง
การทำความเข้าใจกับรายละเอียดต่างๆ ให้ดีก่อน สำหรับในตอนที่ 3 ก็เป้นตอนสุดท้ายของการ
ส่วนการจัดการกับจัดเก็บข้อมูลในระบบ Android  สำหรับตัวอย่างและการประยุกต์ในเนื้อหาตอน
นี้จะยังไม่มี แต่น่าจะได้ใช้ประโยชน์จากเนื้อหาส่วนนี้ในอนาคตอย่างแน่นอน



 
 
การบันทึกข้อมูลลงฐานข้อมูลเหมาะสำหรับการทำซ้ำหรือจัดการโครงสร้างข้อมูล
อย่างเช่น ข้อมูลผู้ติดต่อ โดยในเนื้อหาตอนนี้ จะสมมติว่าเรามีความคุ้นเคยเกี่ยวกับโครงสร้างฐานข้อมูล
SQL มาบ้างแล้ว สำหรับใช้ในการศึกษาเกี่ยวกับฐานข้อมูล SQLite  
สำหรับ APIs ที่จำเป็นจะต้องใช้กับฐานข้อมูลในระบบ Android จะอยู่ใน package ชื่อ android.database.sqlite
 

กำหนดโครงสร้างฐานข้อมูลและ contract

 
หนึ่งในหลักสำคัญของฐานข้อมูล SQL คือ (schema) โครงสร้างข้อมูล 
เป็นรูปแบบการที่จะกำหนดว่าเรา จะจัดการกับฐานข้อมูลนั้นๆ อย่างไร  โครงสร้างข้อมูลจะมีผล
ต่อคำสั่ง SQL ที่ใช้ในการสร้างฐานข้อมูล  เราจะพบว่าการสร้าง class ควบคู่ ที่เรียกว่า contract 
class จะช่วยได้มาก เมื่อมีการกำหนดค่าต่างๆ แบบชัดเจน รูปแบบโครงสร้างของฐานข้อมูลก็จะเป็นระบบขึ้น
 
 
contract class คือ class ที่กำหนดไว้สำหรับเก็บค่าคงที่ในการกำหนดชื่อของ URIs,ตาราง และ คอลัมน์
ซึงอนุญาตให้เราใช้ค่าคงที่นั้นใน class อื่นๆ ที่อยู่ใน package เดียวกัน
สิ่งนี้จะช่วยให้เราเปลี่ยนแปลงชื่อคอลัมน์ได้ในที่เดียวและไม่เสียเวลาในการไล่แก้โค้ดทั้งหมด
 
 
วิธีการที่ดีสำหรับจัดการ contract class คือการกำหนดค่าเป็น global สำหรับฐานข้อมูลทั้งหมดไว้ในระดับ root
ของ class แล้วสร้าง class ภายในสำหรับแต่ละตารางที่เรียกใช้งานคอลัมน์นั้นๆ
 
ข้อสังเกต:: การนำรูปแบบ BaseColumns มาใช้ภายใน class นั้นสามารถสืบทอดจากค่าคีร์หลักที่
เรียกว่า _ID ซึ่งในบางรุ่นของ Android จำเป็นต้องมี แต่ก็ไม่ใช้ว่าต้องมีเสมอไป ซึ่งสิ่งนี้ทำให้การทำงาน
กับฐานข้อมูลเข้ากันได้กับโครงสร้างของระบบ Android โดยรวม
 
 
ยกตัวอย่าง การกำหนดชื่อตาราง และชื่อคอลัมน์ สำหรับหนึ่งตาราง
 
 
public final class FeedReaderContract {
    // ป้องกันการเรียกใช้งาน contract class แบบไม่ตั้งใจ,
    // โดยกำหนดให้ constructor เป็นค่าว่าง.
    public FeedReaderContract() {}

    /* class ภายในที่กำหนดรายละเอียดของตาราง */
    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";
        ...
    }
}
 
 

การสร้างฐานข้อมูลโดยใช้ SQL Helper

 
 
หลังจากที่เราได้กำหนดรูปแบบของฐานข้อมูลแล้ว เราก็จะนำวิธีการสร้างและปรับปรุงฐานข้อมูล
และตาราง นี่คือตัวอย่างโดยทั่วไปของคำสั่งในการสร้างและลบตาราง
 
 
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 ก็เป็นเช่นเดียวกับไฟล์ที่เราทำการบันทึกลงในพื้นที่จัดเก็บภายใน Androd จะเก็บข้อมูลฐานข้อมูล
ในพื้นที่เก็บเฉพาะที่สัมพันธ์กับ App ข้อมูลจะมีความปลอดภัยเพราะว่าโดยค่าเริ่มต้นแล้วพื้นที่นี้จะไม่สามารถ
เรียกดูและเข้าถึงได้จาก App อื่น
 
ชุดของคำสั่ง APIs ที่มีอยู่ใน SQLiteOpenHelper class เมื่อเราใช้งาน class นี้อ้างอิงกับฐานข้อมูล ระบบจะแสดง
การเข้ามาดำเนินการที่ยาวนานสำหรับการสร้างและการอัพเดทฐานข้อมูลเฉพาะในตอนที่จำเป้นต้องใช้และไม่ใช้
ในช่วงตอนที่ App เริ่มทำงาน สิ่งที่เราต้องทำคือการเรียกใช้ getWritableDatabase() หรือ getReadableDatabase()
 
 
ข้อสังเกต:: เพราะเหตุที่ใช้เวลาในการทำงานนาน ตรวจสอบให้ดีว่าเราได้เรียกใช้งาน getWritableDatabase() 
หรือ getReadableDatabase() ในกระบวนการทำงานเบื้องหลัง อย่างเช่น AsyncTask หรือ IntentService
 
 
การใช้งาน SQLiteOpenHelper โดยให้ทำการสร้าง subclass ที่ overrides การเรียกใช้งาน onCreate(), 
onUpgrade() และ onOpen() บางทีเราอาจนำ onDowngrade() มาใช้ก็ได้
 
ตัวอย่าง การนำ SQLiteOpenHelpe มาใช้ตามรูปแบบคำสั่งจากเนื้อหาด้านบนที่กล่าวมา
 
public class FeedReaderDbHelper extends SQLiteOpenHelper {
    // ถ้ามีการเปลี่ยนเปลงโครงสร้างฐานข้อมูล เราต้องทำการเพิ่มค่าของ 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) {
        // ฐานข้อมูลนี้จะทำการแคชเฉพาะกรณีข้อมูลมีการออนไลน์เท่านั้น ดังนั้นเงื่อนไขการ upgrade
        // ก็เพื่อเป็นการยกเลิกข้อมูลเดิม และเริ่มต้นข้อมูลใหม่
        db.execSQL(SQL_DELETE_ENTRIES);
        onCreate(db);
    }
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        onUpgrade(db, oldVersion, newVersion);
    }
}
 
 

การเข้าถึงฐานข้อมูล ผ่าน subclass สำหรับ SQLiteOpenHelper

 
FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());
 
 


การเพิ่มข้อมูลลงในฐานข้อมูล

 
การเพิ่มข้อมูลเข้าไปในฐานข้อมูลด้วยการส่งผ่านค่าของ ContentValues object เข้าไปใน
methoed ที่ชื่อ insert()
 
 
// เรียกฐานข้อมูล ในโหมดสำหรับเขียน
SQLiteDatabase db = mDbHelper.getWritableDatabase();

// สร้างชุดข้อมูล,ให้ชื่อคอลัมน์เป็นค่า 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);

// เพิ่มข้อมูลใหม่, ส่งค่ากลับเป็น primary key ของแถวข้อมูลใหม่
long newRowId;
newRowId = db.insert(
         FeedEntry.TABLE_NAME,
         FeedEntry.COLUMN_NAME_NULLABLE,
         values);
 
 
 
อาร์กิวเมนต์แรกของ insert() คือชื่อของตาราง ตัวที่สองคือชื่อของคอลัมน์ ซี่งสามารถกำหนดค่า
เป็น NULL ได้ในกรณีที่ค่าของ ContentValues เป็นค่าว่าง (ถ้ากำหนดเป็นค่า null ระบบจะทำการเพิ่ม
แถวข้อมูลที่ไม่มีค่าเข้าไปแทน)
 
 
 

การเรียงอ่านข้อมูลจากฐานข้อมูล

 
การอ่านค่าจากฐานข้อมูล จะใช้คำสั่ง query() โดยส่งค่าส่วนที่เลือกกับรูปแบบคอลัมน์ที่ต้องการ
คำสั่งนี้รวมส่วนประกอบของการ insert() และ update() ยกเว้นรายการคอลัมน์ที่กำหนดให้เป็นข้อมูล
ที่ต้องการดึงมาแสดง มากกว่าข้อมูลสำหรับการเพิ่มเข้าไป ผลของการคิวรี่จะคืนค่าเป็น Cursor object
หรือตำแหน่งตัวชี้ของข้อมูล
 
// เรียกฐานข้อมูล ในโหมดสำหรับการอ่าน
SQLiteDatabase db = mDbHelper.getReadableDatabase();

// กำหนดส่่วนของการแสดงที่ระบุคอลัมน์จากฐานข้อมูล
// ที่เราต้องการใช้จริงๆ หลังจากทำการคิวรี่แล้ว
String[] projection = {
    FeedEntry._ID,
    FeedEntry.COLUMN_NAME_TITLE,
    FeedEntry.COLUMN_NAME_UPDATED,
    ...
    };

// ต้องการให้ผลลัพธ์ที่ได้มีการจัดเรียงแบบไหน
String sortOrder =
    FeedEntry.COLUMN_NAME_UPDATED + " DESC";

Cursor c = db.query(
    FeedEntry.TABLE_NAME,  // ตารางที่ต้องการดึง
    projection,                               // คอลัมน์ที่ต้องการส่งค่ากลับ
    selection,                                // คอลัมน์สำหรับเงื่อนไข WHERE 
    selectionArgs,                            // คำสำหรับเงื่อนไข WHERE 
    null,                                     // ไม่มีการจัดกลุ่ม หรือ group ข้อมูล
    null,                                     // ไม่มีการกรองการจัดกลุ่ม
    sortOrder                                 // รูปแบบการจัดเรียง
    );
 
 
เรามาดูที่แภวของข้อมูลในตำแหน่งตัวชี้ข้อมูล โดยเราจะใช้ method ที่ชื่อ moveToFirst() ทุกครั้งก่อนทำการ
อ่านข้อมูลมาแสดง ซึ่งหมายถึงการเลื่อนไปยังตำแหน่งข้อมูลที่ต้องการอ่าน ไปที่รายการแรกของผลลัพธ์ที่ได้
และในแต่ละแถวของข้อมูล เราสามารถอ่านค่าของคอลัมน์ต่างๆ โดยใช้ Cursor เรียกใช้ methoed เช่น
getString() หรือ getLong() ตามชนิดของข้อมูล  สำหรับการรับค่า method แต่ละครั้งเราจะต้องส่งค่าตำแหน่ง
ของคอลัมน์ที่เราได้เตรียมไว้ โดยสามารถเรียกใช้จากคำสั่ง getColumnIndex() หรือ 
getColumnIndexOrThrow() ยกตัวอย่างดังนี้
 
cursor.moveToFirst();  // ไปที่ตำแหน่งแรกของผลลัพธ์ที่ได้
// รับค่าเป็นตัวเลข Long ด้วย method getLong() และส่งค่าตำแหน่งของคอลัมน์ด้วย 
// getColumnIndexOrThrow()
long itemId = cursor.getLong(
    cursor.getColumnIndexOrThrow(FeedEntry._ID)
);
 
 
 
 

การลบข้อมูลจากฐานข้อมูล

 
สำหรับการลบแถวข้อมูลจากตาราง เราจำเป็นต้องเลือกเงื่อนไขเพื่อเป็นการระบุแถวที่ต้องการ
โดย API ของระบบฐานข้อมูลมีเครื่องมือสำหรับกำหนดการสร้างเงื่อนไขนี้ ซึ่งป้องกันการถูกโจมตีด้วย
SQL injection  เป็นเครื่องมือที่แยกส่วนของการเลือกแบบแยกส่วนที่ต้องการเลือกและค่าต้องการ
ตรวจสอบ  โดยเงื่อนไขจะกำหนดเป็นคอลัมน์ที่ต้องการ และยังสามารถรวมกับคอลัมน์ทดสอบได้ด้วย
ส่วนค่าที่ต้องการตรวจสอบก็จะเป้นค่าที่สัมพันธ์กับคอลัมน์ในเงื่อนไข จากผลลัพธ์ที่แตกต่างจากรูปแบบ
คำสั่ง SQL ทั่วไป มันจึงค่อนข้างปลอดภัยต่อการโจมตีด้วย SQL injection
 
 
// กำหนดส่วนของ 'where' ที่ต้องการคิวรี่
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
// ระบุค่าอาร์กิวเมนต์ ที่ต้องการตรวจสอบ
String[] selectionArgs = { String.valueOf(rowId) };
// ทำงานคำสั่ง SQL
db.delete(table_name, selection, selectionArgs);
 

การอัพเดทข้อมูลในฐานข้อมูล

 
เมื่อเราต้องการปรับปรุงบางส่วนของฐานข้อมูล เราจะใช้คำสั่ง update() 
การอัพเดทตาราง ใช้ข้อมูลในรุปแบบเดียวกับการ insert() และใช้เงื่อนไข where คล้ายรูปแบบของ 
คำสั่ง delete()
 
 
// เรียกฐานข้อมูล ในโหมดสำหรับการอ่าน
SQLiteDatabase db = mDbHelper.getReadableDatabase();

// กำหนดชุดข้อมูลสำหรับคอลัมน์ที่ต้องการอัพเดท
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_TITLE, title);

// เงื่อนไขแถวที่ต้องการอัพเดท
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
String[] selectionArgs = { String.valueOf(rowId) };

// ทำคำสั่ง SQL อัเดทข้อมูล
int count = db.update(
    FeedReaderDbHelper.FeedEntry.TABLE_NAME,
    values,
    selection,
    selectionArgs);


 


กด Like หรือ Share เป็นกำลังใจ ให้มีบทความใหม่ๆ เรื่อยๆ น่ะครับ



อ่านต่อที่บทความ













URL สำหรับอ้างอิง





คำแนะนำ และการใช้งาน

สมาชิก กรุณา ล็อกอินเข้าระบบ เพื่อตั้งคำถามใหม่ หรือ ตอบคำถาม สมาชิกใหม่ สมัครสมาชิกได้ที่ สมัครสมาชิก


  • ถาม-ตอบ กรุณา ล็อกอินเข้าระบบ
  • เปลี่ยน


    ( หรือ เข้าใช้งานผ่าน Social Login )







เว็บไซต์ของเราให้บริการเนื้อหาบทความสำหรับนักพัฒนา โดยพึ่งพารายได้เล็กน้อยจากการแสดงโฆษณา โปรดสนับสนุนเว็บไซต์ของเราด้วยการปิดการใช้งานตัวปิดกั้นโฆษณา (Disable Ads Blocker) ขอบคุณครับ