SQLite

1.为什么要用SQLite

SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。

  SQLite便携性强,无需开启服务 ,体积小,无需配置,支持事物管理的轻量级数据库,库文件不到350K ,占用内存少,官方给的数据是占用堆内存只有4~100K,又因为是开源的,所以嵌入式,要求体积小的领域用途很广,比如android系统,IOS系统等都采用了SQLite做为数据库。
  它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源世界著名的数据库管理系统来讲,它的处理速度比他们都快。



2.什么是SQLite

SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快。



3.如何创建数据库和数据表

1 SQLite简介

(1)SQLite 轻量级数据库,对多数用户仅仅表现为数据库文件而已占用资源非常低,占用的内存空间可能只需要几百KB,多用于嵌入式产品执行效率高,

(2)SQLite数据库相当于是每个应用的私有数据,应用程序卸载,对应的SQLite文件也被删除,

(3)SQLite是无类型的:即在创建数据库表时可用不用指定字段(列)的数据类型
任意数据类型的数据都可以保存到任意的字段(列)中,但仍然强烈推荐开发人员在创建数据表时指定数据类型,并合理的填充数据,以便于开发人员之间的交流,及可能存在的数据库引擎更换
2 创建数据库和数据表
创建数据库的方式有:
(1)调用openOrCreateDatabase()方法;(不常用)
(2)扩展SQLiteOpenHelper类


方法一openOrCreateDatabase()
·调用ContextWrapper类定义的openOrCreateDatabase()方法即可打开或创建数据库,即:
 如果指定的数据库不存在,则先创建它,然后再打开;
 如果指定的数据已经存在,则直接打开它

该方法的签名如下:
public SQLiteDatabase openOrCreateDatabase(String name,int mode,CursorFactory factory)
参数 1数据库文件名xxx.db,
参数2 文件的操作类型
参数3游标工厂,暂时不需要传入null就行

SQLiteDatabase类

·SQLiteDatabase类是在Android系统中用于执行各种相关操作的类,例如创建数据表,对数据进行增删改查,执行事务等。
调用该类的execSQL()方法执行无需返回结果的SQL指令,该方法签名,如下:
public void execSQL(String sql) throws SQLException
创建数据表:
创建数据表:
·使用一般的创建数据表的SQL语法即可创建数据表,如果表名,字段名可
能与关键字冲突,可使用方括号:
CREATE TABLE [students](
 [_id] INTEGER PRIMARY KEY AUTOINCREMENT,
 [_name]VARCHAR(50) UNIQUE NOT NULL,
[_age] INT NOT NULL DEFAUL 15
)


方法二 扩展SQLiteOpenHelper类(抽象类)

·使用SQLiteOpenHelper类的相关方法也可以获取SQLiteDatabase类的对象,以实现数据表,数据的相关操作;
·SQLiteOpenHelper可更方便的实现数据库的初始化,版本更新等问题。
·SQLiteOpenHelper类是抽象类,并且没有无参的构造方法,因此,开发人员定义其子类时,需要在子类的构造方法中显示的调用给构造方法;
·构造方法签名:
public SQLiteOpenHelper(Context context,String name,CursorFactory factory,int version)
1,上下文对象
2,数据库文件名
3 游标
4 版本(应该一次比一次大,新版本要比老版本数值要大)
·调用SQLiteOpenHelper类的如下方法可获取SQLiteDatabase对象:
   ·public synchronized SQLiteDatabase getReadableDatabase()
   ·public synchronized SQLiteDatebase getWritableDatabase()
子类继承扩展SQLiteOpenHelper类,子类的对象只有调用上面这两个方法中的任意一个
之后才有可能执行子类中的构造方法和重写的方法
(注意区别:getReadableDatabase()扔尝试获取一个可执行写操作的数据库访问对象
(等效于getWritableDatabase()方法)),仅当出现意外时,例如磁盘空间已满,
则获取只读的数据库访问对象。
·当第一次调用以上方法时,onCreate(),onUpgrade()方法可能被调用,
而这两个方法可能耗时比较长的执行时间,因此并不推荐在主线程中调用
以上方法

第一步

创建类DBOpenHelper继承 SQLiteOpenHelper重写里面的构造方法和方法

[java] view plain copy
  1. package com.example.sqlite_test;  
  2.   
  3. import android.content.Context;  
  4. import android.database.sqlite.SQLiteDatabase;  
  5. import android.database.sqlite.SQLiteDatabase.CursorFactory;  
  6. import android.database.sqlite.SQLiteOpenHelper;  
  7.   
  8. public class DBOpenHelper extends SQLiteOpenHelper{  
  9.   
  10.     /* 
  11.      * 重写构造方法  
  12.      * */  
  13.     public DBOpenHelper(Context context) {  
  14.   
  15.         super(context, "tarena2.db"null1);  
  16.         // TODO Auto-generated constructor stub  
  17.     }  
  18.   
  19.     @Override  
  20.     public void onCreate(SQLiteDatabase db) {  
  21.         // TODO Auto-generated method stub  
  22.         //创建数据库表students表  
  23.         String sql = "CREATE TABLE [students] ("  
  24.                 +"[_id] INTEGER PRIMARY KEY AUTOINCREMENT,"  
  25.                 + "[_name] VARCHAR(50) UNIQUE NOT NULL,"  
  26.                 +"[_age] INT NOT NULL DEFAULT 16"  
  27.                 +")";  
  28.   
  29.   
  30.         db.execSQL(sql);  
  31.     }  
  32.   
  33.     @Override  
  34.     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
  35.         // TODO Auto-generated method stub  
  36.   
  37.     }  
  38.   
  39. }  

第二步:在MainActivity中

[java] view plain copy
  1. package com.example.sqlite_test;  
  2.   
  3. import android.os.Bundle;  
  4. import android.app.Activity;  
  5. import android.database.sqlite.SQLiteDatabase;  
  6. import android.view.Menu;  
  7.   
  8. public class MainActivity extends Activity {  
  9.   
  10.     @Override  
  11.     protected void onCreate(Bundle savedInstanceState) {  
  12.         super.onCreate(savedInstanceState);  
  13.         setContentView(R.layout.activity_main);  
  14.         DBOpenHelper helper = new DBOpenHelper(this);  
  15.         helper.getReadableDatabase();  
  16.         /* 
  17.          * 下面注释部分是使用第一种方法创建数据库和数据表如果下面的语句执行两次的话就会报错,同一个名字的数据库表(表名相同)不能多次创建会冲突 
  18.  
  19.          * */  
  20.         //创建数据库    
  21.         //      SQLiteDatabase db;  
  22.         //      db = openOrCreateDatabase("tarena.db", MODE_PRIVATE,null);  
  23.         //        
  24.         //              //创建数据库表students表  
  25.         //              String sql = "CREATE TABLE [students] ("  
  26.         //                      +"[_id] INTEGER PRIMARY KEY AUTOINCREMENT,"  
  27.         //                      + "[_name] VARCHAR(50) UNIQUE NOT NULL,"  
  28.         //                      +"[_age] INT NOT NULL DEFAULT 16"  
  29.         //                      +")";  
  30.         //        
  31.         //        
  32.         //              db.execSQL(sql);  
  33.   
  34.   
  35.     }  
  36.   
  37. }  



4.如何添加数据

现在你已经掌握了创建和升级数据库的方法,接下来就该学习一下如何对表中的数据进 行操作了。其实我们可以对数据进行的操作也就无非四种,即 CRUD。其中 C 代表添加

(Create),R 代表查询(Retrieve),U 代表更新(Update),D 代表删除(Delete)。每一种操 作又各自对应了一种 SQL 命令,如果你比较熟悉 SQL 语言的话,一定会知道添加数据时使 用 insert,查询数据时使用 select,更新数据时使用 update,删除数据时使用 delete。但是开 发者的水平总会是参差不齐的,未必每一个人都能非常熟悉地使用 SQL 语言,因此 Android 也是提供了一系列的辅助性方法,使得在 Android 中即使不去编写 SQL 语句,也能轻松完成 所有的 CRUD 操作。

前面我们已经知道,调用 SQLiteOpenHelper 的 getReadableDatabase()或 getWritableDatabase()方法是可以用于创建和升级数据库的,不仅如此,这两个方法还都会返回一个 SQLiteDatabase对象,借助这个对象就可以对数据进行 CRUD 操作了。 那么我们一个一个功能地看,首先学习一下如何向数据库的表中添加数据吧。

SQLiteDatabase 中提供了一个 insert()方法,这个方法就是专门用于添加数据的。它接收三个 参数,第一个参数是表名,我们希望向哪张表里添加数据,这里就传入该表的名字。第二个 参数用于在未指定添加数据的情况下给某些可为空的列自动赋值 NULL,一般我们用不到这 个功能,直接传入 null 即可。第三个参数是一个 ContentValues 对象,它提供了一系列的 put() 方法重载,用于向 ContentValues 中添加数据,只需要将表中的每个列名以及相应的待添加 数据传入即可。

介绍完了基本用法,接下来还是让我们通过例子的方式来亲身体验一下如何添加数据 吧。修改 activity_main.xml 中的代码,如下所示:

 

<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:id="@+id/add_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Add data"

/>

</LinearLayout>

可以看到,我们在布局文件中又新增了一个按钮,稍后就会在这个按钮的点击事件里编 写添加数据的逻辑。接着修改 MainActivity 中的代码,如下所示:

 

public class MainActivity extends Activity {

 

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 addData = (Button) findViewById(R.id.add_data);

addData.setOnClickListener(new 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); // 插入第二条数据

}

});

}

 

}

在添加数据按钮的点击事件里面,我们先获取到了 SQLiteDatabase 对象,然后使用 ContentValues 来对要添加的数据进行组装。如果你比较细心的话应该会发现,这里只对 Book 表里其中四列的数据进行了组装,id 那一列没并没给它赋值。这是因为在前面创建表的时候 我们就将 id 列设置为自增长了,它的值会在入库的时候自动生成,所以不需要手动给它赋 值了。接下来调用了 insert()方法将数据添加到表当中,注意这里我们实际上添加了两条数据, 上述代码中使用 ContentValues 分别组装了两次不同的内容,并调用了两次 insert()方法。

好了,现在可以重新运行一下程序了,界面如图 6.21 所示。

 SQLite

图   6.21

 

点击一下 Add data 按钮,此时两条数据应该都已经添加成功了,不过为了证实一下,我 们还是打开 BookStore.db 数据库瞧一瞧。输入 SQL 查询语句 select * from Book,结果如图

6.22 所示。

SQLite

图   6.22

 

由此可以看出,我们刚刚组装的两条数据,都已经准确无误地添加到 Book 表中了。



5.如何删除数据

删除数据对你来说应该就更简单了,因为它所需要用到的知识点你全部已经学过了。 SQLiteDatabase 中提供了一个 delete()方法专门用于删除数据,这个方法接收三个参数,第一 个参数仍然是表名,这个已经没什么好说的了,第二、第三个参数又是用于去约束删除某一 行或某几行的数据,不指定的话默认就是删除所有行。

是不是理解起来很轻松了?那我们就继续动手实践吧,修改 activity_main.xml 中的代码, 如下所示:

 

<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:id="@+id/delete_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Delete data"

/>

</LinearLayout>

仍然是在布局文件中添加了一个按钮,用于删除数据。然后修改 MainActivity 中的代码, 如下所示:

 

public class MainActivity extends Activity {

 

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 deleteButton = (Button) findViewById(R.id.delete_data);

deleteButton.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

SQLiteDatabase db = dbHelper.getWritableDatabase();

db.delete("Book", "pages > ?", new String[] { "500" });

}

});

}

 

}

可以看到,我们在删除按钮的点击事件里指明去删除 Book 表中的数据,并且通过第二、 第三个参数来指定仅删除那些页数超过 500 页的书籍。当然这个需求很奇怪,这里也仅仅是 为了做个测试。你可以先查看一下当前 Book 表里的数据,其中 The Lost Symbol 这本书的页 数超过了 500 页,也就是说当我们点击删除按钮时,这条记录应该会被删除掉。

现在重新运行一下程序,界面如图 6.25 所示。

SQLite

图   6.25

点击一下 Delete data 按钮后,再次输入查询语句查看表中的数据情况,结果如图 6.26所示。

SQLite

图   6.26

 

这样就可以明显地看出,The Lost Symbol 这本书的数据已经被删除了。



6.如何修改数据

步骤1: 采用用SqliteStudio修改数据:

           A.通过数据编辑界面 B.使用Sql语句

步骤2: 启动SublimeText,编写Py文件如下:

UpdateDemo-1.py 及 UpdateDemo-2.py 如下:

[python] view plain copy
  1. import sqlite3    
  2.   
  3. db_filename = 'htxx.db'   
  4. conn=sqlite3.connect(db_filename)  
  5. cursor = conn.cursor()   
  6. sql="select id,name,course,score from class6"    
  7. rows=cursor.execute(sql)  
  8. print("----Before update----")    
  9. print(rows.fetchall())   
  10. cursor.execute('''''update class6 set name='mjb'where name = 'ma' ''')   
  11. print("----After update----")   
  12. rows=cursor.execute(sql)   
  13. print(rows.fetchall())   
  14. conn.commit()  
  15. cursor.close()  
  16. conn.close()  
[python] view plain copy
  1. #-*- coding:utf-8 -*-  
  2. # 导入模块  
  3. import sqlite3    
  4.   
  5.   
  6. def sql_execute(inputs=[]):  
  7.     for item in inputs:  
  8.         temp=(item[1],item[3],item[0],item[2])  
  9.         cursor.execute("update class6 set name=?,score=? where name=? and course=? ", temp)  
  10.     conn.commit()  
  11.   
  12. db_filename = 'htxx.db'   
  13. inputs = [('majianbo','majianbo','math',66.88)]  
  14. conn=sqlite3.connect(db_filename)  
  15. cursor = conn.cursor()   
  16. sql="select * from class6"    
  17. rows=cursor.execute(sql)  
  18. print("----Before update----")    
  19. print(rows.fetchall())   
  20. sql_execute(inputs)  
  21. print("----After update----")   
  22. rows=cursor.execute(sql)   
  23. print(rows.fetchall())   
  24. conn.commit()  
  25. cursor.close()  
  26. conn.close()  



7.如何查询数据

我们都知道 SQL 的全称是 Structured Query Language,翻译成中文就是结构化查询语言。 它的大部功能都是体现在“查”这个字上的,而“增删改”只是其中的一小部分功能。由于 SQL 查询涉及的内容实在是太多了,因此在这里我不准备对它展开来讲解,而是只会介绍 Android 上的查询功能。如果你对 SQL 语言非常感兴趣,可以找一本专门介绍 SQL 的书进 行学习。

相信你已经猜到了,SQLiteDatabase 中还提供了一个 query()方法用于对数据进行查询。 这个方法的参数非常复杂,最短的一个方法重载也需要传入七个参数。那我们就先来看一下 这七个参数各自的含义吧,第一个参数不用说,当然还是表名,表示我们希望从哪张表中查 询数据。第二个参数用于指定去查询哪几列,如果不指定则默认查询所有列。第三、第四个 参数用于去约束查询某一行或某几行的数据,不指定则默认是查询所有行的数据。第五个参 数用于指定需要去 group by 的列,不指定则表示不对查询结果进行 group by 操作。第六个参 数用于对 group by 之后的数据进行进一步的过滤,不指定则表示不进行过滤。第七个参数用 于指定查询结果的排序方式,不指定则表示使用默认的排序方式。更多详细的内容可以参考 下表。其他几个 query()方法的重载其实也大同小异,你可以自己去研究一下,这里就不再 进行介绍了。

 

 

 

query()方法参数

对应 SQL 部分

描述

table

from table_name

指定查询的表名

columns

select column1, column2

指定查询的列名

selection

where column = value

指定 where 的约束条件

selectionArgs

-

为 where 中的占位符提供具体的值

groupBy

group by column

指定需要 group by 的列

having

having column = value

对 group by 后的结果进一步约束

orderBy

order by column1, column2

指定查询结果的排序方式

 

 

虽然 query()方法的参数非常多,但是不要对它产生畏惧,因为我们不必为每条查询语

句都指定上所有的参数,多数情况下只需要传入少数几个参数就可以完成查询操作了。调用

query()方法后会返回一个 Cursor 对象,查询到的所有数据都将从这个对象中取出。 下面还是让我们通过例子的方式来体验一下查询数据的具体用法,修改 activity_main.xml

中的代码,如下所示:

 

<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:id="@+id/query_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Query data"/>

</LinearLayout>

这个已经没什么好说的了,添加了一个按钮用于查询数据。然后修改 MainActivity 中的 代码,如下所示:

 

public class MainActivity extends Activity {

 

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 OnClickListener() {

@Override

public void onClick(View v) {

SQLiteDatabase db = dbHelper.getWritableDatabase();

// 查询Book表中所有的数据

Cursor cursor = db.query("Book", 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();

 

 

}

可以看到,我们首先在查询按钮的点击事件里面调用了 SQLiteDatabase 的 query()方法 去查询数据。这里的 query()方法非常简单,只是使用了第一个参数指明去查询 Book 表,后 面的参数全部为 null。这就表示希望查询这张表中的所有数据,虽然这张表中目前只剩下一 条数据了。查询完之后就得到了一个 Cursor 对象,接着我们调用它的 moveToFirst()方法将数据的指针移动到第一行的位置,然后进入了一个循环当中,去遍历查询到的每一行数据。在这个循环中可以通过 Cursor 的 getColumnIndex()方法获取到某一列在表中对应的位置索引, 然后将这个索引传入到相应的取值方法中,就可以得到从数据库中读取到的数据了。接着我 们使用 Log 的方式将取出的数据打印出来,借此来检查一下读取工作有没有成功完成。最后 别忘了调用 close()方法来关闭 Cursor。

好了,现在再次重新运行程序,界面如图 6.27 所示。

SQLite

图   6.27

 

点击一下 Query data 按钮后,查看 LogCat 的打印内容,结果如图 6.28 所示。

 SQLite

图   6.28

 

可以看到,这里已经将 Book 表中唯一的一条数据成功地读取出来了。