Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 數據存儲 (一)SQLite

Android 數據存儲 (一)SQLite

編輯:關於Android編程

最近項目需要用到涉及數據庫SQLite的知識,真正用的時候才發現自己一點都不熟悉。所以打算將其使用方法總結一下,方便自己以後復習。

SQLiteDatabase

\ SQLiteDatabase類用來管理SQLite數據庫。
它有方法可以創建,刪除,執行SQL命令,並執行其它常見的數據庫管理任務。  

1 創建 打開數據庫

SQLiteDatabase類中提供了5 個static方法用來打開一個文件對應的數據庫。

//openDatabase方法打開path文件對應的數據庫。
public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags)
public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,DatabaseErrorHandler errorHandler)
//openOrCreateDatabase 如果不存在則先創建再打開數據庫,如果存在則直接打開。
public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory)
public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory)
public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory,DatabaseErrorHandler errorHandler)

通過文件path 或者file 創建SQLiteDatabase對象。通過此對象就可以操作數據庫了。

 

 

//創建打開數據庫。
SQLiteDatabase mTestDb = SQLiteDatabase.openOrCreateDatabase("/data/data/cn.vn.sqlitedatademo/databases/my.db", null);
要保證文件路徑是已存在,(例如沒有databases文件夾,則會報錯android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database)

 

Activity的父類(不是直接父類)ContextWrapper.java實現了context.java中的如下兩個抽象方法:

SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory)

SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
DatabaseErrorHandler errorHandler)

所以可以在Activity中直接調用這兩個方法來創建數據庫,或者通過它的context來創建數據庫。

 

2 創建表

創建一張表,表名user_info,列為 _id(主鍵並且自動增加)、name(用戶名)、pwd(密碼)、modifyTime(修改時間)。

 

mTestDb.execSQL("CREATE TABLE IF NOT EXISTS user_info(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT,pwd TEXT,modifyTime INTEGER)");

 

3 添加數據

public static void InsertTest(){
    UserBean user = new UserBean();
    user.setName("xiaopihai");
    user.setPwd("12345678");
    user.setModifyTime(System.currentTimeMillis());
    //增加一條數據,INSERT INTO user_info VALUES()因為有4列,所以需要寫4項數據,否則會失敗,
    //第一個數據位null,這是因為它是自動增長的。.
    mTestDb.execSQL("INSERT INTO user_info VALUES(null,'xiaopihai','12345678',"+user.getModifyTime()+")");
    //不可以為主鍵設置數據,因為它是唯一的,不可以與別的相同。否則會報錯
    //SQLiteConstraintException: PRIMARY KEY must be unique (code 19)
    //mTestDb.execSQL("INSERT INTO user_info VALUES(12,'zhangsan','mima1111',"+System.currentTimeMillis()+")");
    //下面是增加一條數據(只設置某個或某幾個內容),默認沒添加的數據時空的。
    mTestDb.execSQL("INSERT INTO user_info(name,pwd) VALUES('lisi','mimajjjj')");
    mTestDb.execSQL("INSERT INTO user_info VALUES(null,?,?,?)",new Object[]{user.getName(),user.getPwd(),user.getModifyTime()});
    mTestDb.execSQL("INSERT INTO user_info(name,pwd) VALUES(?,?)",new Object[]{"lisi","mimajjjj"});
    
    ContentValues values = new ContentValues();
    values.put(UserSQLiteOpenHelper.COL_NAME,"qwerdf");
    //values.put(UserSQLiteOpenHelper.COL_PWD, "qwerdflol");
    values.put(UserSQLiteOpenHelper.COL_TIME, user.getModifyTime());
    mTestDb.insert("user_info", null,values);
}

 

數據庫結果

 

_id|name|pwd|modifyTime
1|xiaopihai|12345678|1466403447668
2|lisi|mimajjjj|
3|xiaopihai|12345678|1466403447668
4|lisi|mimajjjj|
5|qwerdf||1466403447668

數據庫增加有兩種方法:

(一)通過執行sql語句,調用execSQL(String sql) 或者 execSQL(String sql,Object[] bindArgs)方法。

execSQL(String sql) 執行不帶占位符的sql語句

mTestDb.execSQL("INSERT INTO user_info(name,pwd) VALUES('hhohh', 'hidiiiihiihh')");

execSQL(String sql, Object[] bindArgs)執行帶占位符的SQL語句。

mTestDb.execSQL("INSERT INTO user_info(name,pwd) VALUES(?,?)",new Object[]{"lisi","mimajjjj"});

(二)SQLiteDatabase的insert(String table,String nullColumnHack,ContentValuesvalues)方法,
參數1表名稱,
參數2空列的默認值
參數3ContentValues類型的一個封裝了列名稱和列值的Map;

返回值:新插入的行的行號,或-1(如果發生錯誤)。

values中可以存單個或多個數據。

 

ContentValues values = new ContentValues();
values.put(UserSQLiteOpenHelper.COL_NAME,"qwerdf");
//values.put(UserSQLiteOpenHelper.COL_PWD, "qwerdflol");
values.put(UserSQLiteOpenHelper.COL_TIME, user.getModifyTime());
mTestDb.insert("user_info", null,values);}

4 修改數據

 

 

public static void updateTest(){
	mTestDb.execSQL("UPDATE user_info SET name = 'update1' WHERE _id = 1;");
	mTestDb.execSQL("UPDATE user_info SET name =? WHERE _id=?",new Object[]{"update1",1});
	mTestDb.execSQL("UPDATE user_info SET name = 'update2',modifyTime=111 WHERE _id = 2;");
	mTestDb.execSQL("UPDATE user_info SET name =? ,modifyTime =? WHERE _id=?",new Object[]{"update1",111,2});
	
	ContentValues values = new ContentValues();
	values.put("name","update3");
	values.put("pwd", "2222222");
	values.put("modifyTime", 898);
	mTestDb.update("user_info", values, "_id=?", new String[]{String.valueOf(3)});
}
結果:
_id|name|pwd|modifyTime
1|update1|12345678|1466404010484
2|update1|mimajjjj|111
3|update3|2222222|898
4|lisi|mimajjjj|
5|qwerdf||1466404010484

修改數據庫兩種方法:

(一)通過execSQL執行sql語句。

(二)通過方法

public intupdate(Stringtable,ContentValuesvalues,StringwhereClause,String[]whereArgs)

 

在數據庫中更新行的便捷方法。
參數:
更新的表名
map更新的內容。null是有效值將被轉換為NULL。
whereClause可選更新時WHERE子句適用。傳遞null將更新所有行。
返回
受影響的行數,如果沒有返回0。

5 刪除數據

 

 

public static void deleteTest(){
	mTestDb.execSQL("delete from user_info where _id=1");
	//mTestDb.execSQL("delete from user_info where _id=?",new Object[]{1});
	
	mTestDb.delete("user_info", "_id=?", new String[]{String.valueOf(2)});
}
結果:

 

_id|name|pwd|modifyTime
3|update3|2222222|898
4|lisi|mimajjjj|
5|qwerdf||1466404010484

刪除數據庫的兩種方法:

 

修改數據庫兩種方法:

(一)通過execSQL執行sql語句。

(二)通過下面方法

 

public intdelete(Stringtable,StringwhereClause,String[]whereArgs)

參數
表的表從刪除
whereClause選擇時刪除WHERE子句適用。傳遞null將刪除所有行。
返回
受影響的行數,返回刪除的行數,如果沒有返回0。

6 查詢數據

 

public List findAll() {
		List userList = new ArrayList();
		//查詢表中的所有數據。
		Cursor cursor = mDB.query(UserSQLiteOpenHelper.DATABASE_TABLE_USER,
				null, null, null, null, null, UserSQLiteOpenHelper.COL_TIME
						+ " desc");    //order by modifytime 降序

		if (null != cursor) {
			while (cursor.moveToNext()) {
				UserBean user = new UserBean();
				user.set_id(cursor.getLong(cursor
						.getColumnIndex(UserSQLiteOpenHelper.COL_ID)));
				user.setName(cursor.getString(cursor
						.getColumnIndex(UserSQLiteOpenHelper.COL_NAME)));
				user.setPwd(cursor.getString(cursor
						.getColumnIndex(UserSQLiteOpenHelper.COL_PWD)));
				user.setModifyTime(cursor.getLong(cursor
						.getColumnIndex(UserSQLiteOpenHelper.COL_TIME)));
				userList.add(user);
			}
			cursor.close();
		}
		return userList;
	}

 

 

//某個或某些查詢
//模糊查詢			
		Cursor cursor = mDB.query(UserSQLiteOpenHelper.DATABASE_TABLE_USER,
				null, UserSQLiteOpenHelper.COL_NAME + " like?"+" and "+UserSQLiteOpenHelper.COL_ID+" >?",
				new String[] {"%"+name+"%",2+""}, null, null, UserSQLiteOpenHelper.COL_ID
				+ " desc");
		
//		Cursor cursor = mDB.query(UserSQLiteOpenHelper.DATABASE_TABLE_USER,
//			null, UserSQLiteOpenHelper.COL_NAME + " =?",
//			new String[] {name}, null, null, UserSQLiteOpenHelper.COL_ID
//			+ " desc");
		
		//多個條件查詢
//		Cursor cursor = mDB.query(UserSQLiteOpenHelper.DATABASE_TABLE_USER,
//				null, UserSQLiteOpenHelper.COL_NAME + " like?"+" and "+UserSQLiteOpenHelper.COL_ID+" >?",
//				new String[] {"%"+name+"%",2+""}, null, null, UserSQLiteOpenHelper.COL_ID
//				+ " desc");

 



\

 

這是SqliteDatabase提供的幾種方法,可以適當選用,進行查詢。

 

SQLiteOpenHelper

\

\

SQLiteOpenHelper類(抽象類),一個輔助類來管理數據庫的建立和版本管理。

可以創建一個它的子類,實現onCreate(SQLiteDatabase),onUpgrade(SQLiteDatabase, int, int)以及可選的方法onOpen(SQLiteDatabase),它主要是打開數據庫(如果已存在),如果沒存在則創建並打開。根據需要進行升級。

對其子類進行初始化時UserSQLiteOpenHelper.getInstance(context),這時並沒有建立數據庫。

 

public static UserSQLiteOpenHelper getInstance(Context context) {
		if (null == mInstance) {
			mInstance = new UserSQLiteOpenHelper(context);
			mContext = context;
		}
		return mInstance;
	}

	private UserSQLiteOpenHelper(Context context) {
		//這時並沒有建立數據庫。
		super(context, REMOTE_LIVE_DATABASE_NAME, null, version);
}

看父類SQLiteOpenHelper類源碼

 

 

public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
        this(context, name, factory, version, null);
    }
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
            DatabaseErrorHandler errorHandler) {
        if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);


        mContext = context;
        mName = name;
        mFactory = factory;
        mNewVersion = version;
        mErrorHandler = errorHandler;
    }

先是調方法SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version),然後掉到方法SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version),該方法中要求我們傳遞的version必須大於等於1,否則會報錯IllegalArgumentException異常。這個方法中並沒有為我們創建並打開數據庫,只是存了5個變量的值而已。

 

那什麼時候才會創建數據庫呢?

SQliteOpenHelper

 

public SQLiteDatabase getWritableDatabase() {
        synchronized (this) {
            return getDatabaseLocked(true);
        }
    }

    public SQLiteDatabase getReadableDatabase() {
        synchronized (this) {
            return getDatabaseLocked(false);
        }
    }

    private SQLiteDatabase getDatabaseLocked(boolean writable) {
        if (mDatabase != null) {
            if (!mDatabase.isOpen()) {
                // Darn!  The user closed the database by calling mDatabase.close().
                mDatabase = null;
            } else if (!writable || !mDatabase.isReadOnly()) {
                // The database is already open for business.
                return mDatabase;
            }
        }

        if (mIsInitializing) {
            throw new IllegalStateException("getDatabase called recursively");
        }

        SQLiteDatabase db = mDatabase;
        try {
            mIsInitializing = true;

            if (db != null) {
                if (writable && db.isReadOnly()) {
                    db.reopenReadWrite();
                }
            } else if (mName == null) {
                db = SQLiteDatabase.create(null);
            } else {
                try {
                    if (DEBUG_STRICT_READONLY && !writable) {
                        final String path = mContext.getDatabasePath(mName).getPath();
                        db = SQLiteDatabase.openDatabase(path, mFactory,
                                SQLiteDatabase.OPEN_READONLY, mErrorHandler);
                    } else {
                        db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
                                Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
                                mFactory, mErrorHandler);
                    }
                } catch (SQLiteException ex) {
                    if (writable) {
                        throw ex;
                    }
                    Log.e(TAG, "Couldn't open " + mName
                            + " for writing (will try read-only):", ex);
                    final String path = mContext.getDatabasePath(mName).getPath();
                    db = SQLiteDatabase.openDatabase(path, mFactory,
                            SQLiteDatabase.OPEN_READONLY, mErrorHandler);
                }
            }

            onConfigure(db);

            final int version = db.getVersion();
            if (version != mNewVersion) {
                if (db.isReadOnly()) {
                    throw new SQLiteException("Can't upgrade read-only database from version " +
                            db.getVersion() + " to " + mNewVersion + ": " + mName);
                }

                db.beginTransaction();
                try {
                    if (version == 0) {
                        onCreate(db);
                    } else {
                        if (version > mNewVersion) {
                            onDowngrade(db, version, mNewVersion);
                        } else {
                            onUpgrade(db, version, mNewVersion);
                        }
                    }
                    db.setVersion(mNewVersion);
                    db.setTransactionSuccessful();
                } finally {
                    db.endTransaction();
                }
            }

            onOpen(db);

            if (db.isReadOnly()) {
                Log.w(TAG, "Opened " + mName + " in read-only mode");
            }

            mDatabase = db;
            return db;
        } finally {
            mIsInitializing = false;
            if (db != null && db != mDatabase) {
                db.close();
            }
        }
    }

查看SQLiteOpenHelper源碼中,發現只有getDatabaseLocked()中才會創建數據庫,也就是第一次調用SQLiteOpenHelper.getWritableDatabase()或SQLiteOpenHelper.getReadableDatabase()時才回真正的創建數據庫。此方法創建的數據庫地址為:/data/data/包名/databases/

onConfigure(db)

創建數據庫後,調用onConfigure(db),這個方法裡面可以設置數據庫連接的一些參數,如setLocale() 、setMaximumSize()、setForeignKeyConstraintsEnabled()。

onCreate(db)

再向下會走到onCreate(db)方法中,onCreate只在數據庫第一次創建的時候會調用,調用之前version = 0,之後就會設置新的version,所以此方法不會再走了。在onCreate()方法中,主要用來創建表。

之後使用時可以通過設置SQLiteOpenHelper 中的mNewVersion,然後調用getReadableDatabase()或getWritableDatabase(),當mNewVersion大於數據庫的version,則會調用onUpgrade來升級。而當mNewVersion小於數據庫的version,則調用onDwongrade來降級。然後再將此版本號設置為數據庫的版本號。

db.setVersion(mNewVersion)

 

如何設置mNewVersion呢?

 

查看SQLiteOpenHelper中只有構造方法中設置了mNewVersion,所有只能通過這兩個方法才可以。(子類調用父類的這兩個方法。。)

public SQLiteOpenHelper (Context context, String name, SQLiteDatabase.CursorFactory factory, int version)
public SQLiteOpenHelper (Context context, String name, SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler)

onOpen()每次打開數據庫會調用,選用,不是必須的。

demo下載鏈接:http://download.csdn.net/detail/vnanyesheshou/9581418

效果圖:

\

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved