您的位置:首页 > 移动开发 > Android开发

Android:数据持久化(2/2) SQLite

2015-10-27 00:00 531 查看
摘要: 详细介绍了SQLite的使用,包括数据库的创建、CRUD操作。(事务操作以及升级数据库的best practice会在之后补上)

Abstract 概述

之前的随笔记录了普通文本文件和SharedPreferences两种保存数据的方式,现在来谈一谈用SQLite这个Android自带的数据库。

对SQLite的操作,从整体上来说分两步:

自定义一个Helper类,继承自***SQLiteOpenHelper***,用于获取数据库的实例对象(或者说用于打开数据库的助手类);

通过该Helper类的对象,获取具体的数据库对象来进行CRUD操作;

Description 具体内容

1. 自定义Helper类

借助该Helper类的对象,我们才能获取数据库对象进行操作。

自定义Helper类的要求:

继承SQLiteOpenHelper类;

覆写(Override)
onCreate()
onUpgrade()
两个方法;

public class MyDBHelper extends SQLiteOpenHelper {

public static final String BOOK_STORE = "BookStore.db";
public static final String BOOK_TABLE = "Book";

private Context context;

public static final String CREATE_BOOK = "create table Book (id integer primary key autoincrement, name text, author text, price real, cover text)";

public MyDBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
this.context = context;
}

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
Toast.makeText(context, "Database created.", Toast.LENGTH_SHORT).show();
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Toast.makeText(context, "Just upgraded.", Toast.LENGTH_SHORT);
}
}

说明:

继承了SQLiteOpenHelper;

覆写了onCreate(),该方法在helper第一次获取数据库对象时调用,即创建Book表;

覆写了构造器(构造方法/Constructor),取得调用该实例的context,以便内部使用(如这里的Toast.makeText()需要该参数);

注意:文中用到的文件都是使用Android Studio的默认定义,如MainActivity.java, activity_main.xml等。

2. 获取数据库对象

2. 0 通过adb工具查看数据库内容

在SKD下有一个platform-tools文件夹,里面有一个adb的工具可查看sqlite的数据。
该部分为可选内容,不使用该工具也可以进行开发,只是查看资料会相当不便,所以还是建议学会使用。

配置环境变量,将platform-tools 目录加入到PATH中;

运行App,在启动模拟器后,可以在cmd/terminal中输入
adb shell
启动adb(可通过
exit
来退出);

切换目录到数据库所在文件夹:
cd /data/data/com.scv.lawrence.databasetesting/databases
(此处以Nexus为例,在真机上测试如小米等,目录很有可能不一样);

通过
ls
命令可以看到当前所有数据库(参考下面2.1的内容),此时使用
sqlite3 databaseName
命令可以打开该数据库。如2.1中创建了一个名为BookStore.db的数据库,含有一个Book表,则在adb shell中使用
ls
时能看到BookStore.db,
sqlite3 BookStore.db


在进入了sqlite3的环境后,可使用
.schema
来查看创建表所执行的SQL语句,可使用
.table
来查看所有表的名称,可使用
.exit
来返回adb shell,同样可使用各种sqlite支持的SQL语句;

2. 1 创建数据库

在布局文件中定义一个按钮。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Create DB"
android:id="@+id/create_db"/>
<LinearLayout/>

在代码中(MainActivity.java)中对按钮的点击事件进行监听绑定,通过定义数据库的名称及版本号来创建Helper类的实例,并通过getWritable()获取该数据库的实例。

Button createDB = (Button) findViewById(R.id.create_db);
createDB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteOpenHelper helper = new MyDBHelper(MainActivity.this, MyDBHelper.BOOK_STORE, null, 1);//首先要获取相应数据库的helper,才能进行下一步操作
SQLiteDatabase db = helper.getWritableDatabase();//第一次执行这个方法,会自动调用helper中定义的onCreate()
}
});

第一次点击创建数据库的按钮,
onCreate()
中的
Toast.makeText()
会提示消息表示执行了该方法,第二次点击开始不再有提示,不再执行onCreate();

2. 2 更新数据库

在获取Helper对象时必须传入数据库的名称和版本号,如果传入的版本号高于以前的版本号,则会自动执行
onUpgrade()


SQLiteOpenHelper helper = new MyDBHelper(MainActivity.this, MyDBHelper.BOOK_STORE, null, 2);
upgradeDB = (Button) findViewById(R.id.upgrade_db);
upgradeDB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = helper.getWritableDatabase();//由于helper中的第4个参数,版本信息version高于之前,故调用onUpgrade()
}
});


3. CRUD操作

CRUD即增(Create)删(Delete)改(Update)查(Retrieve),均可使用执行SQL或调用api两种版本来执行;

3. 1 Create 插入数据

将要插入的数据放入ContentValues的对象中;

调用SQLiteDatabase对象的insert();

定义了两个EditText来输入书名和作者,点击按钮进行插入。(activity_main.xml)

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="book name"
android:id="@+id/name"/>

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="author"
android:id="@+id/author"/>

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="create"
android:id="@+id/create"/>

MainActivity.java

Button createBtn = (Button) findViewById(R.id.create);
createBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String bName = nameEdit.getText().toString();
String author = authorEdit.getText().toString();

ContentValues values = new ContentValues();
values.put("name", bName);
values.put("author", author);

SQLiteDatabase db = helper.getWritableDatabase();
db.insert(MyDBHelper.BOOK_TABLE, null, values);//与下面的SQL语句等价,且为了避免SQL注入攻击,必须使用传参的形式,不能自行拼装SQL语句。
//db.execSQL("INSERT INTO Book (name, author) VALUES (?, ?)", new Object[]{bName, author});

values.clear();//清空ContentValues对象的内容,为下次修改作准备
Toast.makeText(MainActivity.this, "Data inserted.", Toast.LENGTH_SHORT).show();
nameEdit.setText(null);
authorEdit.setText(null);
}
});

3. 2 Update 更新数据

和insert()一样,以ContentValues对象来保存要更新的内容;

update()比insert()多了WHERE条件及相应参数;

在布局文件(activity_main.xml)中加入按钮进行update()的绑定:

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="update"
android:id="@+id/update"/>

MainActivity.java

Button updateBtn = (Button) findViewById(R.id.update);
updateBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ContentValues values = new ContentValues();
values.put("author", "updated Author");
values.put("price", 23.33);

SQLiteDatabase db = helper.getWritableDatabase();
db.update(MyDBHelper.BOOK_TABLE, values, "id=?", new String[]{"1"});//等价于下面的SQL语句
//db.execSQL("UPDATE Book SET author=?,price=? WHERE id=?", new Object[]{"updated SQL", 23.33, 1});
values.clear();
Toast.makeText(MainActivity.this, "Data updated.", Toast.LENGTH_SHORT).show();
}
});

3. 3 Delete 删除数据

delete()只需要传入表的名称和WHERE条件及相应参数即可;

Button deleteBtn = (Button) findViewById(R.id.delete);
deleteBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = helper.getWritableDatabase();
db.delete(MyDBHelper.BOOK_TABLE, "id=?", new String[]{"3"});//等价于下面的SQL语句
//db.execSQL("DELETE FROM Book WHERE id=?;", new Object[]{1});//auto-boxing
}
});

3. 4 Retrieve 查询数据

查询的结果就是一张表格,需要使用Cursor对象的
moveToNext()
指向表格的每一行,在每一行中;

Button retrieveBtn = (Button) findViewById(R.id.retrieve);
retrieveBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = helper.getWritableDatabase();
//      Cursor cursor = db.rawQuery("SELECT name, author, price FROM Book",null,null);//与下面的query()等价,然而要求API必须在16以上
Cursor cursor = db.query(MyDBHelper.BOOK_TABLE, null, null, null, null, null, null);

if(cursor.moveToNext()){
do{
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
double price = cursor.getDouble(cursor.getColumnIndex("price"));

Log.i(TAG, name + ", " + author + ", " + price);
}while(cursor.moveToNext());
}

}

});

虽然
query()
的参数很多,但只要将其视作完整的
SELECT
语句的拆分,就会很方便理解:

query(from_table, select_columns, where, whereArgs, group_by, having, order_by)


至少出版了一本书且每本书的售价在50以上,返回作者名字及作品数:

SELECT author, count(name)
FROM Book
WHERE price>50
GROUP BY author
HAVING count(name)>1
ORDER BY author

等价于:

db.query(MyDBHelper.BOOK_TABLE, "author, count(name)", "price>?", new String[]{"50"}, "author", "count(name)>1", "author");


Reference 参考

《第一行代码:Android》郭霖(著)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android SQLite