數據存儲之數據庫SQLite
SQLite簡介
SQLite是一種輕量級的基於文件的數據庫管理系統,是由C語言編寫,實現了標準的SQL中CRUD操作,具有小巧、高效的特點。
SQLite內部支持的數據類型:
- NULL 值是一個 NULL 值。
- INTEGER 值是一個帶符號的整數,根據值的大小存儲在 1、2、3、4、6 或 8 字節中。
- REAL 值是一個浮點值,存儲爲 8 字節的 IEEE 浮點數字。
- TEXT 值是一個文本字符串,使用數據庫編碼(UTF-8、UTF-16BE 或 UTF-16LE)存儲。
- BLOB 值是一個 blob 數據,完全根據它的輸入存儲。
和INTEGER親和的數據類型:
- INT
- INTEGER
- TINYINT
- SMALLINT
- MEDIUMINT
- BIGINT
- UNSIGNED BIG INT
- INT2
- INT8
和TEXT親和的數據類型
- CHARACTER(20)
- VARCHAR(255)
- VARYING CHARACTER(255)
- NCHAR(55)
- NATIVE CHARACTER(70)
- NVARCHAR(100)
- TEXT
- CLOB
和NONE親和的數據類型
- BLOB
- no datatype specified
和REAL親和的數據類型
- REAL
- DOUBLE
- DOUBLE PRECISION
- FLOAT
和NUMERIC親和的數據類型
- NUMERIC
- DECIMAL(10,5)
- BOOLEAN
- DATE
- DATETIME
Boolean 數據類型
SQLite 沒有單獨的 Boolean 存儲類。相反,布爾值被存儲爲整數 0(false)和 1(true)。
Date 與 Time 數據類型
SQLite 沒有一個單獨的用於存儲日期和/或時間的存儲類,但 SQLite 能夠把日期和時間存儲爲 TEXT、REAL 或 INTEGER 值。
存儲類 日期格式
TEXT 格式爲 "YYYY-MM-DD HH:MM:SS.SSS" 的日期。
REAL 從公元前 4714 年 11 月 24 日格林尼治時間的正午開始算起的天數。
INTEGER 從 1970-01-01 00:00:00 UTC 算起的秒數。
您可以以任何上述格式來存儲日期和時間,並且可以使用內置的日期和時間函數來自由轉換不同格式。
更多SQLite內容可以查看SQLite教程。
添加數據庫文件到項目中
數據庫文件添加到assets目錄下如圖:
assets:存放資源文件,比方說mp3、視頻文件、數據庫文件
從文件夾中(assets目錄)拷貝數據庫文件(到files目錄)
/**
* 拷貝數據庫文件
* @param daName 數據庫db文件 xxx.db
*/
private void copyDB(String daName) {
//拿到數據庫文件
//data/data/包名/files/
File filesDir = getFilesDir();
Log.d(TAG,"路徑:" + filesDir.getAbsolutePath());
File destFile = new File(getFilesDir(),daName);//獲取路徑,要拷貝的目標地址
//數據庫已經存在就不再拷貝
if(destFile.exists()){
Log.d(TAG,"數據庫:" + daName + "已存在!");
return;
}
FileOutputStream out = null;
InputStream in = null;
try {
in = getAssets().open(daName);
out = new FileOutputStream(destFile);
//讀數據
int len=0;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
創建及使用數據庫
創建的數據庫在/data/data/包名/databases目錄中
root@android:/data/data/com.jeff.appmanager # ls
ls
cache
databases
lib
root@android:/data/data/com.jeff.appmanager # cd databases
cd databases
root@android:/data/data/com.jeff.appmanager/databases # ls
ls
AppLock.db 數據庫文件
AppLock.db-journal 日誌文件
1.定義自己的SQLiteOpenHelper
SQLiteOpenHelper內部方法
繼承SQLiteOpenHelper的子類必須擁有以下以下三種方法:
- 構造方法 創建數據庫
- onCreate() 重寫方法,用於創建表
- onUpgrade() 重寫方法,用於數據庫的升級
另外還有兩個重要的實例方法:
這兩個方法都可以創建或打開一個現有的數據庫(如果數據庫存在就直接打開,否則就創建一個新的數據庫),並返回一個可對數據庫進行讀寫操作的對象。
- getReadableDataBase() 返回的對象以只讀的方式打開數據庫
- getWritableDataBase() 返回的對象對數據庫可讀可寫,但在數據庫不可寫入時會報出異常
書本數據庫實例
public class BookOpenHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK = "create table Book ("
+ "id integer primary key autoincrement, "
+ "name text,"
+ "author text, "
+ "pages integer, "
+ "price real)";//1.0
public static final String CREATE_CATEGORY = "create table Category ("
+ "id integer primary key autoincrement, "
+ "category_name text)";//1.1
public static final String UPDATE_BOOK = "create table Book ("
+ "id integer primary key autoincrement, "
+ "name text,"
+ "author text, "
+ "pages integer, "
+ "price real,"
+ "category_id integer)";//2.0
private Context mContext;
/**
* 構造方法創建指定name數據庫
*
* @param context 上下文
* @param name 數據庫名稱
* @param factory 一般爲空
* @param version 數據庫版本
*/
public BookOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
/**
* 構造方法直接構造一個數據庫名BookStore.db的數據庫
*
* @param context 上下文
*/
public BookOpenHelper(Context context) {
super(context, "BookStore.db", null, 1);
mContext=context;
}
/***
* 創建數據庫時調用,如果數據庫已存在不調用
* @param db SQLiteDatabase對象
*/
@Override
public void onCreate(SQLiteDatabase db) {
//App版本1.1時加入Category表。若用戶首次建庫兩張表同時建立,若軟件升級會在onUpgrade建立Category表
db.execSQL(CREATE_BOOK);//數據庫1.0
db.execSQL(CREATE_CATEGORY);//數據庫1.1
Toast.makeText(mContext, "數據庫創建成功", Toast.LENGTH_SHORT).show();
}
/**
* 升級數據庫
*
* @param db SQLiteDatabase對象
* @param oldVersion 數據庫舊版本號
* @param newVersion 數據庫新版號
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//針對數據庫1.1版本,數據庫一旦存在onCreate方法不再調用,Category表無法在onCreate方法中創建
//根據數據庫版本執行Category表的創建語句
switch (oldVersion) {
case 1:
db.execSQL(CREATE_CATEGORY);
break;
case 2:
//數據庫2.0 創建Book表,相對1.0版本增加了category_id列
db.execSQL("alert table Book add column category_id integer");
break;
default:
}
//過於暴力不建議
// db.execSQL("drop table if exists Book");
// db.execSQL("drop table if exists Category");
// onCreate(db);
}
}
操作SQLite的主要類SQLiteDataBase
openDatabase()方法,打開指定路徑的數據庫
public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
return openDatabase(path, factory, flags, null);
}
insert()方法,插入數據
public long insert(String table, String nullColumnHack, ContentValues values) {
try {
return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
} catch (SQLException e) {
Log.e(TAG, "Error inserting " + values, e);
return -1;
}
}
update()方法,修改數據
public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
return updateWithOnConflict(table, values, whereClause, whereArgs, CONFLICT_NONE);
}
query()方法,查詢數據
//Query the given table, returning a Cursor over the result set
public Cursor query(String table, String[] columns, String selection,
String[] selectionArgs, String groupBy, String having,
String orderBy) {
return query(false, table, columns, selection, selectionArgs, groupBy,
having, orderBy, null /* limit */);
}
//Query the given table, returning a Cursor over the result set
public Cursor query(String table, String[] columns, String selection,
String[] selectionArgs, String groupBy, String having,
String orderBy, String limit) {
return query(false, table, columns, selection, selectionArgs, groupBy,
having, orderBy, limit);
}
delete()方法,刪除數據
public int delete(String table, String whereClause, String[] whereArgs) {
acquireReference();
try {
SQLiteStatement statement = new SQLiteStatement(this, "DELETE FROM " + table +
(!TextUtils.isEmpty(whereClause) ? " WHERE " + whereClause : ""), whereArgs);
try {
return statement.executeUpdateDelete();
} finally {
statement.close();
}
} finally {
releaseReference();
}
}
execSQL()方法,執行SQL語句
//Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE。
public void execSQL(String sql, Object[] bindArgs) throws SQLException {
if (bindArgs == null) {
throw new IllegalArgumentException("Empty bindArgs");
}
executeSql(sql, bindArgs);
}
//Execute a single SQL statement that is NOT a SELECT
or any other SQL statement that returns data.
public void execSQL(String sql) throws SQLException {
executeSql(sql, null);
}
rawQuery()方法,使用SQL語句查詢
//Runs the provided SQL and returns a Cursor over the result set.
public Cursor rawQuery(String sql, String[] selectionArgs) {
return rawQueryWithFactory(null, sql, selectionArgs, null, null);
}
//Runs the provided SQL and returns a Cursor over the result set
public Cursor rawQuery(String sql, String[] selectionArgs,
CancellationSignal cancellationSignal) {
return rawQueryWithFactory(null, sql, selectionArgs, null, cancellationSignal);
}
查詢病毒病毒數據庫
public class AntivirusDao {
public static boolean isVirus(String md5) {
String path = "/data/data/包名/files/antivirus.db";
boolean result = false;
//打開病毒數據庫
SQLiteDatabase db = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
Cursor cursor = db.rawQuery("select * from datable where md5=?", new String[]{md5});
if (cursor.moveToNext()) {
result = true;
}
cursor.close();
db.close();
return result;
}
}
操作書本數據庫(封裝了對數據庫的各種操作方法)
public class BookDao {
private final String TAG = "BookDao";
private BookOpenHelper mHelper; //BookOpenHelper實例對象
private Context mContent;
/**
* 構造方法,創建BookOpenHelper實例
*
* @param context 上下文
*/
public BookDao(Context context) {
this.mHelper = new BookOpenHelper(context);
mContent=context;
}
/**
* 添加數據
* @param name
* @param author
* @param pages
* @param price
*/
public void add(String name,String author,int pages,float price) {
SQLiteDatabase db = mHelper.getWritableDatabase();
ContentValues values = new ContentValues();
// 開始組裝第一條數據
values.put("name", name);
values.put("author", author);
values.put("pages", pages);
values.put("price", price);
db.insert("Book", null, values);
Toast.makeText(mContent, "數據添加成功", Toast.LENGTH_SHORT).show();
// values.clear();
// // 開始組裝第二條數據
// values.put("name", "The Da Vinci Code");
// values.put("author", "Dan Brown");
// values.put("pages", 454);
// values.put("price", 16.96);
// db.insert("Book", null, values);
db.close();
}
/**
* 修改數據
*
* @param id 數據id
* @param name 書名
* @param author 作者
* @param pages 頁數
* @param price 價格
*/
public void update(int id, String name, String author, int pages, float price) {
SQLiteDatabase db = mHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", name);
values.put("author", author);
values.put("pages", pages);
values.put("price", price);
db.update("Book", values, "id=?", new String[]{String.valueOf(id)});
Toast.makeText(mContent, "數據修改成功", Toast.LENGTH_SHORT).show();
db.close();
}
/**
* 刪除數據
* db.delete()
* @param table 表名
* @param whereClause 約束條件
* @param whereArgs 約束值
*/
public void delete(int id) {
SQLiteDatabase db = mHelper.getWritableDatabase();
db.delete("Book", "id=?", new String[]{String.valueOf(id)});
Toast.makeText(mContent, "刪除成功", Toast.LENGTH_SHORT).show();
db.close();
}
/**
* 查詢數據庫中全部數據
* db.query()
* @param table 表名
* @param columns 指定列名
* @param selection 約束條件
* @param selectionArgs 約束值
* @param groupBy groupBy
* @param having having
* @param orderBy orderBy
*/
public List<BookBean> searchAll() {
//查詢數據庫內容,返回只讀類型的SQLiteDatabase對象
SQLiteDatabase db = mHelper.getReadableDatabase();
//打開指定路徑的數據庫如: path = "/data/data/包名/files/antivirus.db"
// SQLiteDatabase db = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
List<BookBean> bookList = new ArrayList<>();
Cursor cursor = db.query("Book", null, null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
//遍歷Cursor對象
int id = cursor.getInt(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
float price = cursor.getFloat(cursor.getColumnIndex("price"));
Log.d(TAG, "searchAll: " + id + " " + name + " " + author + " " + pages + " " + price);
BookBean book = new BookBean();
book.setId(id);
book.setName(name);
book.setAuthor(author);
book.setPages(pages);
book.setPrice(price);
bookList.add(book);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
return bookList;
}
//**************************************************************
//使用SQL操作數據庫
/**
* 添加數據,更新數據,刪除數據
*
* @param sql SQL語句
* @param bindArgs 一般爲空
*/
public void execSQL(String sql, String bindArgs) {
SQLiteDatabase db = mHelper.getWritableDatabase();
db.execSQL(sql, new String[]{bindArgs});
db.close();
}
/**
* 重載方法執行SQL語句
* @param sql
*/
public void execSQL(String sql) {
SQLiteDatabase db = mHelper.getWritableDatabase();
db.execSQL(sql);
db.close();
}
/**
* 使用SQL語句查詢數據
*
* @param sql SQL語句
* @param selectionArgs 約束值
*/
public void rawQuery(String sql, String selectionArgs) {
SQLiteDatabase db = mHelper.getReadableDatabase();
Cursor cursor=db.rawQuery(sql, new String[]{selectionArgs});
if (cursor.moveToFirst()) {
do {
//遍歷Cursor對象
int id = cursor.getInt(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
float price = cursor.getFloat(cursor.getColumnIndex("price"));
Log.d(TAG, "rawQuery: " + id + " " + name + " " + author + " " + pages + " " + price);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
}
/**
* 重載方法,使用SQL語句查詢
* @param sql
*/
public void rawQuery(String sql) {
SQLiteDatabase db = mHelper.getReadableDatabase();
Cursor cursor=db.rawQuery(sql, null);
if (cursor.moveToFirst()) {
do {
//遍歷Cursor對象
int id = cursor.getInt(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
float price = cursor.getFloat(cursor.getColumnIndex("price"));
Log.d(TAG, "rawQuery: " + id + " " + name + " " + author + " " + pages + " " + price);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
}
}
**在activity中調用
dao = new BookDao(this);即可創建數據庫,並通過dao對象對數據庫執行操作**
Cursor對象(查詢數據庫返回的對象)
這是一個接口,該接口爲數據庫查詢返回的結果集提供隨機讀寫訪問
從Cursor對象中讀取數據:
XXX name= cursor.getXXX(getColumnIndex(String columnName));
兩個重要方法:
int getColumnIndex(String columnName);
XXX getXXX(int columnIndex);
XXX getXXX(int columnIndex)方法具體有:
- String getString(int columnIndex);
- short getShort(int columnIndex);
- int getInt(int columnIndex);
- long getLong(int columnIndex);
- float getFloat(int columnIndex);
- double getDouble(int columnIndex);
實例
Cursor cursor=db.rawQuery(sql, null);
if (cursor.moveToFirst()) {
do {
//遍歷Cursor對象
int id = cursor.getInt(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
float price = cursor.getFloat(cursor.getColumnIndex("price"));
Log.d(TAG, "rawQuery: " + id + " " + name + " " + author + " " + pages + " " + price);
} while (cursor.moveToNext());
}
cursor.close();//最後需要關閉cursor