天天看点

【移动开发】SQLite数据库使用 数据类型小结

在我们平时做Android项目,不管是应用还是游戏,都会用到SQLite数据库,在这里我还是简单的整理了一下。

1.简介

SQLite 是一个开源的嵌入式关系数据库,实现自包容、零配置、支持事务的SQL数据库引擎。 其特点是高度便携、使用方便、结构紧凑、高效、可靠。 与其他数据库管理系统不同,SQLite 的安装和运行非常简单,在大多数情况下 - 只要确保SQLite的二进制文件存在即可开始创建、连接和使用数据库。如果您正在寻找一个嵌入式数据库项目或解决方案,SQLite是绝对值得考虑。

一般的数据库采用的是固定的静态数据类型,SQLite采用动态数据类型,创建一个表时,可以在 CREATE TABLE 语句中指定某列的数据类型,但是你可以把任何数据类型放入任何列中。当某个值插入到数据库时,SQLite将会检查它的类型,如果该类型与关联的列不匹配,SQLite则会尝试将该值转换成该列的类型,如果不能转换,则该值将作为本身的类型存储,比如可以把一个字符串(String)放入 INTEGER 列。SQLite称这为“弱类型”。但有一个特例,如果是INTEGER PRIMARY KEY,则其他类型不会被转换,会报一个“datatype missmatch”的错误。

在事务处理方面,SQLite通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但只有一个可以写入数据。在某个进程或线程想数据库执行写操作之前,必须获得独占锁。在获得独占锁之后,其他的读或写操作将不会再发生。

此外,SQLite 不支持一些标准的 SQL 功能,特别是外键约束(FOREIGN KEY constrains),嵌套 transcaction 和 RIGHT OUTER JOIN 和 FULL OUTER JOIN, 还有一些 ALTER TABLE 功能。

除了上述功能外,SQLite 是一个完整的 SQL 系统,拥有完整的触发器,交易等等。

2.Android 集成了 SQLite 数据库

Android 在运行时(run-time)集成了 SQLite,所以每个 Android 应用程序都可以使用 SQLite 数据库。对于熟悉 SQL 的开发人员来时,在 Android 开发中使用 SQLite 相当简单。但是,由于 JDBC 会消耗太多的系统资源,所以 JDBC 对于手机这种内存受限设备来说并不合适。因此,Android 提供了一些新的 API 来使用 SQLite 数据库,Android 开发中,程序员需要学使用这些 API。

数据库存储在 data/data/<项目文件夹>/databases/ 下。

A.数据类型

   1.NULL 空值

   2.INTEGER 带符号的整型

   3.REAL 浮点型

   4.TEXT 字符串文本

   5.BLOB 二进制对象

但实际上,sqlite3也接受如下的数据类型:

   smallint 16 位元的整数。

   interger 32 位元的整数。

   decimal(p,s) p 精确值和 s 大小的十进位整数,精确值p是指全部有几个数(digits)大小值,s是指小数点後有几位数。如果没有特别指定,则系统会设为 p=5; s=0 。

   float 32位元的实数。

   double 64位元的实数。

   char(n) n 长度的字串,n不能超过 254。

   varchar(n) 长度不固定且其最大长度为 n 的字串,n不能超过 4000。

   graphic(n) 和 char(n) 一样,不过其单位是两个字元 double-bytes, n不能超过127。这个形态是为了支援两个字元长度的字体,例如中文字。

   vargraphic(n) 可变长度且其最大长度为 n 的双字元字串,n不能超过 2000

   date 包含了 年份、月份、日期。

   time 包含了 小时、分钟、秒。

   timestamp 包含了 年、月、日、时、分、秒、千分之一秒。

   datetime 包含日期时间格式,必须写成'2010-08-05'不能写为'2010-8-5',否则在读取时会产生错误!

B.简单使用

Android平台下数据库相关类:

SQLiteOpenHelper 抽象类:通过从此类继承实现用户类,来提供数据库打开、关闭等操作函数。

       SQLiteDatabase 数据库访问类:执行对数据库的插入记录、查询记录等操作。

       SQLiteCursor 查询结构操作类:用来访问查询结果中的记录。

Activites 可以通过 Content Provider 或者 Service 访问一个数据库。

C.创建数据库

Android不自动提供数据库。在 Android 应用程序中使用 SQLite,必须自己创建数据库,然后创建表、索引,填充数据。Android 提供了 SQLiteOpenHelper 帮助你创建一个数据库,你只要继承 SQLiteOpenHelper 类,就可以轻松的创建数据库。

SQLiteOpenHelper 类根据开发应用程序的需要,封装了创建和更新数据库使用的逻辑。SQLiteOpenHelper 的子类,至少需要实现三个方法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

<code>package</code> <code>com.dandan.fm.db;</code>

<code>import</code> <code>android.content.Context;</code>

<code>import</code> <code>android.database.sqlite.SQLiteDatabase;</code>

<code>import</code> <code>android.database.sqlite.SQLiteDatabase.CursorFactory;</code>

<code>import</code> <code>android.database.sqlite.SQLiteOpenHelper;</code>

<code>/**</code>

<code> </code><code>* 可以通过SQLiteOpenHelper的以下两个方法来或得SQLiteDatabase的对象:</code>

<code> </code><code>* getReadableDatabase() 创建或者打开一个查询数据库</code>

<code> </code><code>* getWritableDatabase() 创建或者打开一个可写数据库</code>

<code> </code><code>*/</code>

<code>public</code> <code>class</code> <code>DBHelper </code><code>extends</code> <code>SQLiteOpenHelper {</code>

<code>    </code><code>/**</code>

<code>     </code><code>* 构造函数,必须实现</code>

<code>     </code><code>* @param context 上下文路径</code>

<code>     </code><code>* @param name 数据库名称</code>

<code>     </code><code>* @param factory 可选游标工厂,通常为NULL</code>

<code>     </code><code>* @param version 当前数据库版本号</code>

<code>     </code><code>*/</code>

<code>    </code><code>public</code> <code>DBHelper(Context context, </code><code>String</code> <code>name, CursorFactory factory,</code><code>int</code> <code>version) {</code>

<code>        </code><code>super</code><code>(context, name, factory, version);</code>

<code>    </code><code>}</code>

<code>                                                                                                                                                                                                                                                                                                                        </code> 

<code>    </code><code>//数据库第一次创建时会调用,一般在其中创建数据库表</code>

<code>    </code><code>@Override</code>

<code>    </code><code>public</code> <code>void</code> <code>onCreate(SQLiteDatabase db) {</code>

<code>        </code><code>//使用execSQL()方法执行DDL语句,如果没有异常,这个方法没有返回值</code>

<code>        </code><code>db.execSQL(</code><code>"create table user(id INTEGER PRIMARY KEY AUTOINCREMENT,"</code> <code>+ </code><code>"name varchar(20), address TEXT)"</code><code>);</code>

<code>    </code><code>//当数据库需要修改的时候,Android系统会主动的调用这个方法。</code>

<code>    </code><code>public</code> <code>void</code> <code>onUpgrade(SQLiteDatabase db, </code><code>int</code> <code>oldVersion, </code><code>int</code> <code>newVersion) {</code>

<code>    </code><code>//数据库版本升级时,更新数据库操作</code>

<code>    </code><code>//打开数据库时的回调函数,一般不会用</code>

<code>    </code><code>public</code> <code>void</code> <code>onOpen(SQLiteDatabase db) {</code>

<code>        </code><code>super</code><code>.onOpen(db);</code>

<code>    </code><code>public</code> <code>synchronized </code><code>void</code> <code>close() {</code>

<code>        </code><code>super</code><code>.close();</code>

<code>}</code>

说明:

创建表和索引

<code>db.execSQL(</code><code>"create table user(id INTEGER PRIMARY KEY AUTOINCREMENT,"</code> <code>+</code>

<code> </code><code>"name varchar(20), address TEXT)"</code><code>);</code>

给表添加数据

 有两种方式添加数据:

       1.向上面创建表一样,可以使用execSQL方法执行 INSERT, UPDATE, DELETE 等语句来更新表的数据。execSQL适用于        所有不需要返回结果的SQL语句。如:

<code>db.execSQL(</code><code>"INSERT INTO user (name, address) VALUES ('woniu',"</code> <code>+</code>

<code>"'http://http://smallwoniu.blog.51cto.com/')"</code><code>);</code>

2.SQLiteDatabase 对象的 insert(), update(), delete() 方法。这些方法把 SQL 语句的一部分作为参数。如:

<code>private</code> <code>SQLiteDatabase mDataBase = </code><code>null</code><code>;</code>

<code>private</code> <code>static</code> <code>final</code> <code>String</code> <code>USER_TABLE = </code><code>"user"</code><code>;</code>

<code>                                                                                                                                                                                                </code> 

<code>public</code> <code>void</code> <code>getDB() {</code>

<code>    </code><code>//创建DBHelper对象</code>

<code>    </code><code>DBHelper db = </code><code>new</code> <code>DBHelper(</code><code>this</code><code>, USER_TABLE, </code><code>null</code><code>, </code><code>1</code><code>);</code>

<code>    </code><code>//获取可写SQLiteDatabase</code>

<code>    </code><code>mDataBase = db.getWritableDatabase();</code>

<code>public</code> <code>void</code> <code>insert() {</code>

<code>    </code><code>//ContentValues对象,向其中插入键值对,键是数据库列名,值是插入到这一列的值</code>

<code>    </code><code>ContentValues cv = </code><code>new</code> <code>ContentValues();</code>

<code>    </code><code>cv.put(</code><code>"name"</code><code>, </code><code>"LiuMing"</code><code>);</code>

<code>    </code><code>cv.put(</code><code>"address"</code><code>, </code><code>"ShangHai"</code><code>);</code>

<code>    </code><code>mDataBase.insert(USER_TABLE, </code><code>null</code><code>, cv);</code>

<code>public</code> <code>int</code> <code>update() {</code>

<code>    </code><code>cv.put(</code><code>"name"</code><code>, </code><code>"MaLi"</code><code>);</code>

<code>    </code><code>//第三个参数where语句,相当于sql语句中where后面的语句,?是占位符</code>

<code>    </code><code>//第四个参数是占位符的值</code>

<code>    </code><code>return</code> <code>mDataBase.update(USER_TABLE, cv, </code><code>"id = ?"</code><code>, </code><code>new</code> <code>String</code><code>[]{</code><code>"1"</code><code>});</code>

<code>public</code> <code>int</code> <code>delete</code><code>() {</code>

<code>    </code><code>//和udate()类似</code>

<code>    </code><code>return</code> <code>mDataBase.</code><code>delete</code><code>(USER_TABLE, </code><code>"id = ? and name = ?"</code><code>,</code>

<code>        </code><code>new</code> <code>String</code><code>[]{</code><code>"1"</code><code>, </code><code>"MaLi"</code><code>});</code>

查询数据库

       与INSERT,UPDATE,DELETE类似,有两种方法从数据库中查询数据。

<code> </code><code>* 使用rawQuery()直接调用SELECT语句,最简单的查询方法</code>

<code> </code><code>* 如果查询是动态的,使用rawQuery就会非常复杂</code>

<code> </code><code>* @return Cursor可以迭代查询结果</code>

<code>public</code> <code>Cursor rawQuery() {</code>

<code>    </code><code>return</code> <code>mDataBase.rawQuery(</code><code>"select * from user where id = ? and name = ?"</code><code>, </code><code>new</code> <code>String</code><code>[]{</code><code>"1"</code><code>, </code><code>"LiuMing"</code><code>});</code>

<code>//使用SELECT语句段构建查询,SELECT语句内容做为query()方法的参数</code>

<code>public</code> <code>Cursor query() {</code>

<code>    </code><code>String</code><code>[] columns = {</code><code>"name"</code><code>, </code><code>"address"</code><code>};</code>

<code>    </code><code>//第二个参数: 要查询的列名</code>

<code>    </code><code>//第三个参数:where语句</code>

<code>    </code><code>//第三个参数:where语句中占位符的值</code>

<code>    </code><code>//第四个参数:对查询结果进行分组</code>

<code>    </code><code>//第五个参数:对分组结果进行限制</code>

<code>    </code><code>//第六个参数:对查询结果进行排序</code>

<code>    </code><code>return</code> <code>mDataBase.query(USER_TABLE, columns, </code><code>"id = ?"</code><code>, </code><code>new</code> <code>String</code><code>[] {</code><code>"1"</code><code>},</code><code>null</code><code>, </code><code>null</code><code>, </code><code>null</code><code>);</code>

   最后着重提及一下使用游标,不管如何执行查询,都会返回一个Cursor,Curosr主要方法如下:

getCount():

获得结果集中有多少记录。

moveToFirst():

移动到第一行。

moveToNext():

移动到下一行,可遍历所有记录。

isAfterLast():

判断是否最后一行。

getColumnNames():

返回字段名。

getColumnCount():

返回字段号。

getString(),getInt():

得到给定字段当前记录的值。

requery():

重新执行查询得到游标。

close():

释放游标资源。

<code>/** 查询记事本表的所有记录 **/</code>

<code>    </code><code>public</code> <code>ArrayList&lt;HashMap&lt;</code><code>String</code><code>, </code><code>Object</code><code>&gt;&gt; getWriteAllCount() {</code>

<code>        </code><code>// 打开数据库</code>

<code>        </code><code>openDatabase();</code>

<code>        </code><code>ArrayList&lt;HashMap&lt;</code><code>String</code><code>, </code><code>Object</code><code>&gt;&gt; data = </code><code>null</code><code>; </code><code>// 接收数据</code>

<code>        </code><code>// Cursor----ResultSet:用于接收数据库数据列表</code>

<code>        </code><code>Cursor cursor = db.query(DBInfo.Table.TB_WRITE_NAME, </code><code>null</code><code>, </code><code>null</code><code>, </code><code>null</code><code>,</code><code>null</code><code>, </code><code>null</code><code>, </code><code>null</code><code>);</code>

<code>        </code><code>if</code> <code>(</code><code>null</code> <code>!= cursor &amp;&amp; cursor.getCount() &gt; </code><code>0</code><code>) {</code>

<code>            </code><code>data = </code><code>new</code> <code>ArrayList&lt;HashMap&lt;</code><code>String</code><code>, </code><code>Object</code><code>&gt;&gt;();</code>

<code>            </code><code>while</code> <code>(cursor.moveToNext()) {</code>

<code>                </code><code>HashMap&lt;</code><code>String</code><code>, </code><code>Object</code><code>&gt; map = </code><code>new</code> <code>HashMap&lt;</code><code>String</code><code>, </code><code>Object</code><code>&gt;();</code>

<code>                </code><code>map.put(</code><code>"title"</code><code>,cursor.getString(cursor.getColumnIndex(</code><code>"title"</code><code>)));</code>

<code>                </code><code>map.put(</code><code>"content"</code><code>,cursor.getString(cursor.getColumnIndex(</code><code>"content"</code><code>)));</code>

<code>                </code><code>map.put(</code><code>"imagePath"</code><code>,cursor.getString(cursor.getColumnIndex(</code><code>"imagePath"</code><code>)));</code>

<code>                </code><code>map.put(</code><code>"time"</code><code>, cursor.getString(cursor.getColumnIndex(</code><code>"time"</code><code>)));</code>

<code>                </code><code>map.put(</code><code>"color"</code><code>,cursor.getString(cursor.getColumnIndex(</code><code>"color"</code><code>)));</code>

<code>                </code><code>map.put(</code><code>"background"</code><code>,cursor.getInt(cursor.getColumnIndex(</code><code>"background"</code><code>)));</code>

<code>                </code><code>map.put(</code><code>"lock"</code><code>,cursor.getInt(cursor.getColumnIndex(</code><code>"lock"</code><code>)));</code>

<code>                </code><code>data.add(map);</code>

<code>            </code><code>}</code>

<code>        </code><code>}</code>

<code>        </code><code>cursor.close();</code>

<code>        </code><code>db.close(); </code><code>// 用完记得要关闭哦</code>

<code>        </code><code>return</code> <code>data;</code>

当然,如果我们遇到大量反复对数据库进行操作时,我们可以使用异步加载数据库(可以看我的下一篇博客),改善加的用户体验效果

<b>     本文转自zhf651555765 51CTO博客,原文链接:http://blog.51cto.com/smallwoniu/1249999</b><b>,如需转载请自行联系原作者</b>