数据存储之数据库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