SQLite数据库存储
创建数据库
Android管理数据库提供了一个SQLiteOpenHelper帮助类。
借助这个类就可以简单地对数据库进行创建和升级。下面学习SQLiteOpenHelper的基本用法。
首先SQLiteOpenHelper是一个抽象类,我们要是用的话,需要创建一个自己的帮助类去继承它。SQLiteOpenHelper中有两个抽象方法。
onCreate()和onUpgrade()
我们必须在自己的帮助类里面重写这两个方法,然后分别在这两个方法中去实现创建,升级数据库的逻辑。
SQLiteOpenHelper中有两个实例方法,
getReadableDatabase()和getWritableDatabase()。
这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。
不同的是,当数据库不可写入的时候(如磁盘空间已满),getReadableDatabase()方法返回的对象将以只读的方式去打开数据库,
而getWritableDatabase()方法则将出现异常。
SQLiteOpenHelper中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可。
这个构造方法中接收4个参数:
第一个参数是Context,必须有它才能对数据库操作。
第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。
第三个参数运行徐我们在查询数据的时候返回一个自定义的Cursor,一般都传入null。
第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作。
构建出SQLiteOpenHelper的实例之后,再调用它的getReadableDatabase()或getWritableDatabase()方法就能够创建数据库了。
数据库文件会存放在/data/data//databases/目录下。
此时,重写的onCreate()方法也会得到执行。所以通常会在这里去处理一些创建表的逻辑。
###下面举一个例子:创建一个DatabaseTest项目
我们创建一个名为BookStore.db的数据库,然后再这个数据库中新建一张Book表。表中有id(主键)、作者、价格、页数、和书名等。
(在这里需要学者学习一下数据库,本人学过两个数据库一个是mysql和oracle。如果没学的话建议可以学一下mysql就可以)
Book表的创建表语句如下:
Create table Book(
id integer primary key autoincrement,
author text,
price real,
pages integer,
name text)
SQLite不想其他的数据库拥有众多复杂的数据类型,它的数据类型很简单。
integer表示整形
real表示浮点型
text表示文本类型
blob表示二进制类型。
primary key将id列设为主键。
autoincrement关键字表示id列是自增长的。
新建MyDatabaseHelper类继承自SQLiteOpenHelper
public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK = "Create table Book("
+"id integer primary key autoincrement,"
+"author text,"
+"price real,"
+"pages integer,"
+"name text)";
private Context mContext;//?
public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
可以看到,把建表语句定义成了一个字符串常量,然后早onCreate方法中调用了SQLiteDatabase的execSQL()方法去执行这条建表语句。
修改activity_main.xml中的代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="net.nyist.lenovo.databasetest.MainActivity"
android:orientation="vertical">
<Button
android:id="@+id/craete_database"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Create database"
/>
</LinearLayout>
布局文件很简单,加入一个按钮,用于创建数据库。
最后修改MainActivity中的代码:
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,1);
Button createDatabase = (Button) findViewById(R.id.craete_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
}
}
这里我们在onCreate()方法中构建了一个MyDatabaseHelper对象,并且通过构造函数的参数将数据库名指定为BookStore.db,版本号指定为1,然后再Create database按钮的点击事件里调用getWritableDatabase()方法。遮阳挡点击Create database按钮时,就会检测到当前程序中没有BookStore.db这个数据库,与实惠创建该数据库并调用MyDatabaseHelper中的onCrewate()方法,这样Book表也就创建了,并弹出提示创建成功。
下面运行程序:
那么怎么证明它们的确创建成功了呢?
adb是Android SDK中自带的一个调试工具,使用这个工具可以直接对连接在电脑上的手机或模拟器进行调试操作,他存放在sdk的platform-tools目录下,如果想要在命令行中使用这个工具,就需要先把它的路径配置到环境变量里。
配置环境变量在这里就不多说了,不会的可以百度。
配置好之后,就可以使用adb工具了。打开命令提示符,输入adb shell,就会进入到设备的控制台。使用cd命令进入到**/data/data/net.nyist.lenovo.databasetest/databases/**目录下,(在这里我的包名是net.nyist.lenovo.databasetes),并使用ls命令查看到该目录里面的文件。
这时候目录下出现了两个数据库文件:
一个正是我们创建的BookStore.db
而另一个BookStore.db-journal:则是为了让数据库能够支持事务而产生的临时文件。
接下来我们就要借助sqlite命令打开数据库:
1.输入sqlite3,后面加上数据库名即可。(我刚开始一直出错是没有加数据库名)。
2.这是就打开BookStore.db数据库,现在就可以对这个数据库中的表进行管理。
3.输入**.table**,可以看到数据库中有两张表。android_metadata表是每个数据库中都会自动生成的,不用管它。而另一张Book表就是我们在MyDatabaseHelper中创建的。
4.还可以通过.schema命令来查看它们的建表语句。
由此证明BookStore数据库和Book表确实已经创建成功。之后输入.exit或.quit命令可以退出数据库的编辑,再输入exit命令就可以退出设备控制台。
#升级数据库
**onUpgrade()**方法适用于对数据库进行升级的,它在真个数据库的管理工作当中起着非常重要的作用。
目前DatabaseTest项目中已经有一张Book表用于存放书的各种详细数据,添加一张Categroy表用于记录图书的分类。
比如Category表中有id(主键)、分类名和分类代码这几个列,那么建表语句就可以写成:
create table Category(
id integer primary key autoincrement,
category_name text,
category_code integer)
接下来我们将这条建表语句添加到MyDatabaseHelper中,代码如下所示:
public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_CATEGORY = "create table Category("
+"id integer primary key autoincrement,"
+"category_name text,"
+"category_code integer)";
public static final String CREATE_BOOK = "Create table Book("
+"id integer primary key autoincrement,"
+"author text,"
+"price real,"
+"pages integer,"
+"name text)";
private Context mContext;//?
public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
db.execSQL(CREATE_CATEGORY);
Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists Book");
db.execSQL("drop table if exists Category");
onCreate(db);
}
}
可以看到,我们在onUpgrade()方法中执行了两条drop语句,如果发现数据库中已经存在Book表或Category表,就将这两张表删除掉,然后再调用onCreate()方法重新创建。这里先将已经存在的表删除掉,因为如果在创建表时发现这张表已经存在了,就会直接报错。
为了让onUpgrade()方法执行,我们可以在SQLiteOpenHelper的构造方法里修改第四个参数,之前传入的是1,现在只要传比1大的数就可以让onUpgrade()方法得到执行。
dbHelper = new MyDatabaseHelper(this,“BookStore.db”,null,2);
添加数据
对数据进行的操作无非就4种:CRUD
1.C:添加(Create)
**2.R:查询(Retrieve)**
**3.U:更新(Update)**
**4.D:删除(Delete)**
前面我们已经知道,调用SQLiteOpenHelper的getReadableDatabase()或getWritableDatabase()方法是可以用于创建和升级数据库的,不仅如此,这两个方法还会返回一个SQLiteDatabase()对象,借助这个对象就可以对数据进行CRUD操作了。
insert():添加数据。接收三个参数
第一个参数:表名,希望向那张表里添加数据,这里就传入该表的名字。
第二个参数:在未指定添加数据的情况下给某些可为空的列自动复制NULL,一般不用这个功能,直接传入null即可。
第三个参数:是一个ContentValues对象,它提供了一系列的put()方法重载,用于向ContentValues中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。
下面看例子:
修改activity_main.xml中的代码:
只添加一个按钮。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
······
<Button
android:id="@+id/add_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add data"
/>
</LinearLayout>
接着修改MainActivity的代码:
```java
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
Button createDatabase = (Button) findViewById(R.id.craete_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
Button addData = (Button) findViewById(R.id.add_data);
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//先获取到SQLiteDatabase对象
SQLiteDatabase db = dbHelper.getWritableDatabase();
//使用ContentValues来对要添加的数据进行组装。
ContentValues values = new ContentValues();
//开始组装第一条数据
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);//插入第一条数据
values.clear();
//开始组装第二条数据
values.put("name","The Lost Symbol");
values.put("author","Dan Brown");
values.put("pages",510);
values.put("price",19.95);
db.insert("Book",null,values);//插入第二条数据
}
});
//调用了两次insert()
}
}
点击一下Adddata按钮,此时两条数据应该都已经添加成功。我们可以证实一下:
更新数据
SQLiteDatabase中也提供一个非常好用的update()方法。用于对数据进行更新 ,这个方法接收4个参数。
第一个参数:表名。
第二个参数:ContentValues对象。
第三个第四个参数用于约束更新某一行或某几行中的数据,不指定的话默认就是更新所有行。
继续修改activity_main.xml代码:
添加一个更新按钮:
<Button
android:id="@+id/update_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Update data"
/>
修改MainActivity中的代码:
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
Button createDatabase = (Button) findViewById(R.id.craete_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
Button addData = (Button) findViewById(R.id.add_data);
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
//开始组装第一条数据
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);//插入第一条数据
values.clear();
//开始组装第二条数据
values.put("name","The Lost Symbol");
values.put("author","Dan Brown");
values.put("pages",510);
values.put("price",19.95);
db.insert("Book",null,values);//插入第二条数据
}
});
Button updatadata = (Button) findViewById(R.id.update_data);
updatadata.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
//构造一个ContentValues对象,并且只它指定了一组数据。
ContentValues values = new ContentValues();
values.put("price",10.99);
db.update("Book",values,"name = ?",new String[]{ "The Da Vinci Code"});
//这里使用了第三第四个参数来指定具体更新哪几行。
//第三个参数对应的是SQLwhere部分,表示更新所有name等于?的行,而?
//是一个占位符,可以通过第四个参数提供的一个字符串数组为第三个
//数中的每个占位符指定相应的内容。
//因此上述代码想表达的意图是将名字是The Da Vinci Code的这本书
//的价格改成10.99
}
});
}
}
运行如下:
删除数据
SQLiteDatabase中提供了一个delete()方法,专门用于产出数据,这个方法接收3个参数。
第一个参数:表名。
第二个参数第三个参数又是用于约束删除某一行或某几行的数据,不指定的话就是默认删除所有行。
修改activity_main.xml
添加删除按钮
<Button
android:id="@+id/delete_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Delete data"
/>
修改MainActivity
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
·······
Button deletedata = (Button) findViewById(R.id.delete_data);
deletedata.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete("Book","page > ?",new String[] {"500"});
}
});
}
}
我们在删除按钮的点击事件里之名删除Book表中的数据,并且通过第二,第三个参数来指定仅删除页数超过500页的书。
运行程序:
查询数据
我们都知道Structured Query Language,翻译成中文就是结构化查询语言。
它的大部分功能都体现在"查"这个字上,而"增删改"只是其中的一小部分功能。
SQLiteDatabase中还提供了一个query()方法用于对数据进行查询。这个方法的参数非常复杂,最短的一个方法重载也需要传入7个参数。
第一个参数:表名。
第二个参数:用于指定去查询那几列,如果不指定则默认查询所有列。
第三个第四个参数:用于约束查询某一行或几行的数据,不指定则默认查询所有行的数据。
第五个参数:用于指定需要去group by的列,不指定则表示不对查询结果进行group by操作。
第六个参数:用于对group by之后的数据进行进一步的过滤,不指定则表示不进行过滤。
第七个参数:用于指定查询结果的排序方式,不指定则表示使用默认的排序方式。
修改:
activity_main.xml代码:
<Button
android:id="@+id/query_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Query Data"
/>
修改MainActivity代码:
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
Button queryButton = (Button) findViewById(R.id.query_data);
queryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
//查询Book中所有的数据
Cursor cursor = db.query("Book",null,null,null,null,null,null,null);
if (cursor.moveToFirst()){
do {
//遍历Cursor对象,取出数据并打印
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
double price = cursor.getDouble(cursor.getColumnIndex("price"));
Log.d("MainActivity","book name is "+name);
Log.d("MainActivity","book author is "+author);
Log.d("MainActivity","book pages is "+pages);
Log.d("MainActivity","book price is"+price);
}while (cursor.moveToNext());
}
cursor.close();
}
});
}
}
运行如下: