关于Android数据库的使用,网上和很多书籍上都有相应的介绍,简单的使用,难度不大,但是作为一个持久存储数据的方式,有必要做个总结,以下内容基本参照《第一行代码》中的有关介绍。
概述
Android为了让我们能够更加方便地管理数据库,专门提供了一个SQLiteOpenHelper帮助类,借助这个类就可以非常简单地对数据库进行创建和升级。既然有好东西可以直接使用,那我们自然要尝试一下了,下面我就将对SQLiteOpenHelper的基本用法进行介绍。
首先你要知道SQLiteOpenHelper是一个抽象类,这意味着如果我们想要使用它的话,就需要创建一个自己的帮助类去继承它。SQLiteOpenHelper中有两个抽象方法,分别是onCreate()和onUpgrade(),我们必须在自己的帮助类里面重写这两个方法,然后分别在这两个方法中去实现创建、升级数据库的逻辑。
SQLiteOpenHelper中还有两个非常重要的实例方法,getReadableDatabase()和getWritableDatabase()。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。不同的是,当数据库不可写入的时候(如磁盘空间已满)getReadableDatabase()方法返回的对象将以只读的方式去打开数据库,而getWritableDatabase()方法则将出现异常。
SQLiteOpenHelper中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可。这个构造方法中接收四个参数,第一个参数是Context,这个没什么好说的,必须要有它才能对数据库进行操作。第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。第三个参数允许我们在查询数据的时候返回一个自定义的Cursor,一般都是传入null。第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作。构建出SQLiteOpenHelper的实例之后,再调用它的getReadableDatabase()或getWritableDatabase()方法就能够创建数据库了,数据库文件会存放在/data/data//databases/目录下。
代码
实现Book.java简单数据类,MySQLHelper.java继承自SQLiteOpenHelper,MainActivity.java界面操作
- Layout(只写一个button的,其他button类似):
<Button
android:text="update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/insert"
android:layout_alignParentStart="true"
android:layout_marginTop="17dp"
android:id="@+id/update"
android:onClick="updateDataClick" />
- Book.java
public class Book {
private String name;
private float price;
private int pages;
public Book(float price, String name, int pages) {
this.price = price;
this.name = name;
this.pages = pages;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
}
- MySQLHelper.java
public class MySQLHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK_TABLE= "create table Book (" +
"id integer primary key autoincrement," +
"name text, " +
"price real," +
"pages integer," +
"category_id integer)";
public static final String CREATE_CATEGORY = "create table Category ("
+ "id integer primary key autoincrement, "
+ "category_name text, "
+ "category_code integer)";
private static final String TAG = "MySQLHelper";
private Context mContext;
public MySQLHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
Log.d(TAG,"onCreate");
sqLiteDatabase.execSQL(CREATE_BOOK_TABLE);
sqLiteDatabase.execSQL(CREATE_CATEGORY);
}
//数据库升级的最佳方式
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
Log.d(TAG,"onUpgrade");
//删除数据库中的表
//sqLiteDatabase.execSQL("drop table if exists Book");
Log.d(TAG,"i = "+ i+" i1 = "+i1);
//机智的没有使用break
switch (i){
case 1:
sqLiteDatabase.execSQL(CREATE_CATEGORY);
case 2:
sqLiteDatabase.execSQL("alter table Book add column category_id integer");
default:
}
}
}
- MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final String TAG ="ZYW";
private Button create;
private Button insert;
private Button update;
private Button delete;
private Button select;
private MySQLHelper helper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG,"onCreate");
setContentView(R.layout.activity_main);
init();
//修改version,onUpgrade()方法会被执行到
helper = new MySQLHelper(this,"DataBase.db",null,2);
}
private void init(){
create = (Button) findViewById(R.id.create);
insert = (Button) findViewById(R.id.insert);
update = (Button) findViewById(R.id.update);
delete = (Button) findViewById(R.id.delete);
select = (Button) findViewById(R.id.select);
}
public void createTableClick(View view) {
Log.d(TAG,"createTableClick");
SQLiteDatabase database = helper.getReadableDatabase();
}
public void insertDataClick(View view) {
Log.d(TAG,"insertDataClick");
SQLiteDatabase database = helper.getReadableDatabase();
//法1:Android 接口
/*ContentValues values = new ContentValues();
Book book = new Book((float) 114.5,"<sangeren>",250);
Book book1 = new Book((float) 66.5,"<wanglishiwunian>",350);
Book book2 = new Book((float) 245.5,"<diyihangdaima>",150);
values.put("name",book.getName());
values.put("price",book.getPrice());
values.put("pages",book.getPages());
database.insert("Book",null,values);
values.clear();
values.put("name",book1.getName());
values.put("price",book1.getPrice());
values.put("pages",book1.getPages());
database.insert("Book",null,values);
values.clear();
values.put("name",book2.getName());
values.put("price",book2.getPrice());
values.put("pages",book2.getPages());
database.insert("Book",null,values);*/
//法2:SQLite语句
//同上,id是自增长的,所以也不需要赋值
//(name,pages,price): 发现这个顺序没必要和创建表时的顺序一致,但是要保证后续赋值的一一对应。
//('<xuesanfeihu>',555,120.5): 如果使用双引号的话会报错,需要使用英文单引号
// 不加单引号,运行时会报错:Caused by: android.database.sqlite.SQLiteException: near "<": syntax error (code 1):
//拓展: 转义字符
//String str1 = "\"name\"";//字符串两边含有双引号
//String str2 = "name \"is\" wgb";//字符串中间含有双引号
//String str3 = "\\name";//使用转义字符还可以使字符串包含其他字符
//database.execSQL("insert into Book (name,pages,price) values ('<feihu>',432,32.5)");
//法3:折中方法
database.execSQL("insert into Book (name,pages,price) values (?,?,?)",new String[]{"<ciqiongle>","421","73.2"});
}
public void updateDataClick(View view) {
Log.d(TAG,"updateDataClick");
SQLiteDatabase database = helper.getReadableDatabase();
//法1:Android 接口
/*ContentValues values = new ContentValues();
Book book = new Book((float) 333.5,"<HHH>",222);
values.put("name",book.getName());
values.put("price",book.getPrice());
values.put("pages",book.getPages());
database.insert("Book",null,values);
database.update("Book",values,"price = ?",new String[]{"245.5"});*/
//法2:SQLite语句
//database.execSQL("update Book set price = 321.1 where name = '<ciqiongle>'");
//法3:折中方法
database.execSQL("update Book set price = ? where name = ?",new String[]{"123.4","<ciqiongle>"});
}
public void deleteDataClick(View view) {
Log.d(TAG,"deleteDataClick");
SQLiteDatabase database = helper.getReadableDatabase();
//法1:Android 接口
/*database.delete("Book","name = ?",new String[]{"<sangeren>"});*/
//法2:SQLite语句
//database.execSQL("delete from Book where name = '<HHH>'");
//法3:折中方法
database.execSQL("delete from Book Where name = ?",new String[]{"<feihu>"});
}
public void selectDataClick(View view) {
Log.d(TAG,"selectDataClick");
SQLiteDatabase database = helper.getReadableDatabase();
//"id desc": 表示查询得到的数据,按id降序排列; 升序为"id asc"
//"pages between ? and ?": 测试发现查询得到的数据包含边界
//Cursor cursor = database.query("Book", new String[]{"id","name", "price"}, "pages between ? and ?", new String[]{"150","300"}, null, null, "id desc", null);
//法2:SQLite语句
Cursor cursor = database.rawQuery("select * from Book where pages between ? and ?", new String[]{"150", "300"});
if (cursor.moveToFirst()) {
do {
// new String[]{"name", "price"}代表最终读取数据库中哪几列的数据,
// 如果cursor中没有包含,下面非要去获取,将报错Caused by: java.lang.IllegalStateException:
// Couldn't read row 0, col -1 from CursorWindow.
// 查询得到的数据中没有,你去读,理当报异常,注意点
int id = cursor.getInt(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
float price = cursor.getFloat(cursor.getColumnIndex("price"));
Log.d(TAG,"id = "+id+ " name = "+name+" ; price = "+price);
}while (cursor.moveToNext());
}
//不要忘了
cursor.close();
}
//事务的使用:SQLite数据库是支持事务的,事务的特性可以保证让某一系列的操作要么全部完成,要么一个都不会完成。
public void replaceDataClick(View view) {
Log.d(TAG,"replaceDataClick");
SQLiteDatabase readableDatabase = helper.getReadableDatabase();
//事务开始
readableDatabase.beginTransaction();
try{
readableDatabase.delete("Book",null,null);
if (false) {
//手动抛出一个异常,让事务失败
throw new NullPointerException();
}
readableDatabase.execSQL("insert into Book (name,pages,price) values (?,?,?)",new String[]{"<ciqiongle>","421","73.2"});
//事务执行成功
readableDatabase.setTransactionSuccessful();
}catch (Exception e){
e.printStackTrace();
}finally {
//结束事务
readableDatabase.endTransaction();
}
}
}
关于数据库常用语句介绍:
1、查找一个表返回其中几条记录
select * from table where name= ? limit 0,10;
其中limit 0,10中,0表示从第0条记录开始,10表示向下10条记录。
2、根据条件查找一个表,按某字段进行排序
select * from table where name= ? order by id desc或者 asc 或者不填 ;
desc降序排列,asc升序排列
其中id是表中的字段。
3、查询一个表中,某字段名为X或者Y的所有数据
select * from LocalModelTable where prodCategory = ? or prodCategory = ?;
其中prodCategory为字段,名为X或者Y,返回的是名字为X、Y下的所有数据。
4、更新一条数据到表中
update LocalSchemeTable set Area = ?,BudgetList = ? ,TimeStamp = ? where SchemeID = ?;
5、插入一条记录到表中
insert into LocalSchemeTable (Area, BudgetList,Budget) values (?,?,?);
6、给表添加、删除、修改一列(字段)
alert table table_name add column column_name datatype default 0
举例: alert table student add column age interger default 0
给student表增加一个字段age ,设置默认值为0
7、手动添加一个表
create table if not exists LocalProductInfoTable (Num integer primary key autoincrement,marque text);
其中Num为自增长的编号。text为文本类型。
8、查看数据库中是否有某个表
select count(*) as ‘count’ from sqlite_master where type =’table’ and name = ?;
?为表名。
9、约束
比如有的值不能为空,有的必须给默认值,有的字段的值必须唯一
建表时可以给特定的字段设置一些约束条件,常见的约束有
not null :规定字段的值不能为null
unique :规定字段的值必须唯一
default :指定字段的默认值
(建议:尽量给字段设定严格的约束,以保证数据的规范性)
举例
create table student (id integer, name text not null unique, age integer not null default 1) ;
name字段不能为null,并且唯一
age字段不能为null,并且默认为1
10、添加主键 自增长
主键(Primary Key,简称PK)用来唯一地标识某一条记录,一个表可以有多个主键。只要声明为primary key,就说明是一个主键字段,主键字段默认就包含了not null 和 unique 两个约束。
create table student (id integer primary key, name text, age integer) ;
创建一个student表,设置id为主键。
create table student (id integer primary key autoincrement, name text, age integer) ;
创建一个student表,设置id为主键,并且是自增长类型,需要注意的是,自增长类型主键必须!!!是interger类型的。
11、外键
外键是指本表的某个字段是另外一张表的主键。
拓展
Android开发之SQLite详解
介绍SQLite的内容更详细,丰富。
Android之存储篇SQLite数据库让你彻底学会SQLite的使用
如题。