`
yuanlanjun
  • 浏览: 1184300 次
文章分类
社区版块
存档分类
最新评论

android 数据存储和访问方式三:SQLite数据库详解

 
阅读更多

一、SQLite数据库简介和基础知识
在Android平台上,集成了一个嵌入式关系型数据库——SQLite(轻量级数据库)。SQLite第一个Alpha版本诞生于2000年5月。它是遵守ACID的关联式数据库管理系统,包含在一个相对小的C库中,同时是D.RichardHipp建立的公有领域项目。SQLite3支持NULL、INTEGER、REAL(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)数据类型,虽然支持的数据类型只有五种,但实际上SQLite3也接受varchar(n)、char(n)、decimal(p,s)等数据类型,只不过在运算或保存时会转换成对应的五种数据类型。SQLite最大的特点是可以把各种类型的数据保存到任何字段中,而不用关心字段声明的数据类型是什么。例如:可以在INTEGER类型的字段中存放字符串,或者在布尔型字段中存放浮点数,或者在字符型字段中存放日期型。但有一种情况例外:定义为INTEGER PRIMARY KEY的字段只能存储64位整数,当向这种字段保存除整数以外的数据时,将会产生错误。此外,SQLite在解析CREATE TABLE语句时,会忽略CREATE TABLE语句中在字段名后面的数据类型信息,例如下面语句中会忽略name字段的类型信息:create table person(personid integer primary key autoincrement, name varchar(20), age integer)即使指定了字段的数据长度,该字段仍然可以保存超过指定长度的内容。
SQLite可以解析大部分标准SQL语句,例如:
查询语句:
select * from 表名 where 条件子句 group by 分组子句 having ... order by 排序子句;
select * from person;
select * from person order by personid desc;
select name from person group by name having count(*)>1;
分页语句与MySQL类似,例如通过SQL语句获取5条记录,跳过前面3条记录:
select * from person limit 5 offset 3;
或者
select * from person limit 3,5;
插入语句:insert into 表名(字段列表) values(值列表)。例如:insert into person(name, age) values('网星',3);
更新语句:update 表名 set 字段名=值 where 条件子句。例如:update person set name='网星' where personid=10;
删除语句:delete from 表名 where 条件子句。例如:delete from person where personid=10;

SQLite官方网站
http://www.sqlite.org/
http://www.sqlite.org/download.html
SQLite中文社区
http://www.sqlite.com.cn/
PC端的SQLite数据库管理工具
SQLite Database Browser
http://sourceforge.net/projects/sqlitebrowser/
http://sourceforge.net/projects/sqlitebrowser/files/sqlitebrowser/2.0%20beta1/
SQLite Expert
http://www.sqliteexpert.com/
SQLite Developer
http://www.sqlitedeveloper.com/
SQLiteSpy
http://www.yunqa.de/delphi/doku.php/products/sqlitespy/index


二、操作SQLite数据库
为了便于操作数据库,在Android系统里提供了一个名为SQLiteOpenHelper的抽象类,必须继承它才能使用,它是通过对数据库版本进行管理。为了实现对数据库版本进行管理,SQLiteOpenHelper类提供了两个重要的方法,分别是onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion),前者用于初次使用软件时生成数据库表,后者用于升级软件时更新数据库表结构。

当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动创建数据库,接着调用onCreate()方法,onCreate()方法在初次创建数据库时才会被调用,在该方法中可以生成数据库表结构及添加一些应用中使用到的初始化数据。onUpgrade()方法在数据库的版本发生变化时会被调用,一般在软件升级时才需改变版本号,而数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的变更,修改了数据库表结构,这时候就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2(有同学问设置为3行不行?当然可以,如果你愿意,设置为100也行),并且在onUpgrade()方法里面实现表结构的更新。当软件的版本升级次数比较多,这时在onUpgrade()方法里面可以根据原版号和目标版本号进行判断,然后作出相应的表结构及数据更新。

SQLiteOpenHelper类的getWritableDatabase()和getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase实例。getWritableDatabase()方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若继续使用getWritableDatabase()打开数据库就会出错。getReadableDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。

①:编写实现SQLiteOpenHelper类的子类DBOpenHelper
必须显式调用父类的构造方法:super(context, DATABASE_NAME, null, DATABASE_VERSION);
参数2是数据库名称,例如"xawx",可以没有后缀名,也可以有,例如"xawx.db"。
参数3是游标工厂,可以设为null使用默认的游标工厂。
参数4是版本号,例如是"1"。
数据库的位置:/data/data/<package_name>/databases/xawx.db

②:创建数据库表
在onCreate(SQLiteDatabase db)方法中添加如下代码:
db.execSQL("create table person(personid integer primary key autoincrement, name varchar(20), age integer)");

SQLiteDatabase sQLiteDatabase = DBOpenHelper.getWritableDatabase();//第一次调用该方法就会创建数据库
第一次调用getWritableDatabase()或getReadableDatabase()方法后,SQLiteOpenHelper会缓存当前的SQLiteDatabase实例,SQLiteDatabase实例正常情况下会维持数据库的打开状态,所以你不再需要SQLiteDatabase实例时,请及时调用close()方法释放资源。一旦SQLiteDatabase实例被缓存,多次调用getWritableDatabase()或getReadableDatabase()方法得到的都是同一实例。

③:通过SQLiteDatabase进行增删改查。
CRUD是指增加(Create)、查询(Retrieve)、更新(Update)和删除(Delete)几个单词的首字母简写。
第一种方式:SQLiteDatabase.execSQL(" ")、rawQuery(" ");
execSQL()方法可以执行insert、delete、update和CREATE TABLE之类有更改行为的SQL语句;rawQuery()方法用于执行select语句。rawQuery()方法的第一个参数为select语句,第二个参数为select语句中占位符参数的值,如果select语句没有使用占位符,第二个参数设置为null。rawQuery()方法返回Cursor对象,Cursor是结果集游标,用于对结果集进行随机访问,Cursor与JDBC中的ResultSet作用很相似。使用moveToNext()方法可以将游标从当前行移动到下一行,如果已经移过了结果集的最后一行,返回结果为false,否则为true。另外Cursor还有常用的moveToPrevious()方法(用于将游标从当前行移动到上一行,如果已经移过了结果集的第一行,返回值为false,否则为true)、moveToFirst()方法(用于将游标移动到结果集的第一行,如果结果集为空,返回值为false,否则为true)和moveToLast()方法(用于将游标移动到结果集的最后一行,如果结果集为空,返回值为false,否则为true)。

第二种方式:SQLiteDatabase.insert(" ")、delete(" ")、update(" ")和query(" ");
各个字段的数据使用ContentValues进行存放。ContentValues类似于Map,它提供了存取数据对应的put(String key, Xxx value)和getAsXxx(String key)方法, key为字段名称,value为字段值,Xxx指的是各种常用的数据类型,如:String、Integer等。


三、SQLite数据库中的事务操作
使用SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction()方法时会检查事务的标志是否为成功,如果程序执行到endTransaction()之前调用了setTransactionSuccessful()方法设置事务的标志为成功则提交事务,如果没有调用setTransactionSuccessful()方法则回滚事务。使用如下:
SQLiteDatabase db = ....;
db.beginTransaction();//开始事务
try {
db.execSQL("insert into person(name, age) values(?,?)", new Object[]{"张三", 5});
db.execSQL("update person set name=? where personid=?", new Object[]{"李四", 1});
db.setTransactionSuccessful();//调用此方法会在执行到endTransaction()时提交当前事务,如果不调用此方法则回滚事务。
} finally {
db.endTransaction();//结束事务。由事务的标志决定是提交事务,还是回滚事务
}
db.close();
上面两条SQL语句在同一个事务中执行。


四、使用ListView组件列表显示数据
ListView由多个Item组成,Item可以自定义。每个Item由ImageView(图片)和TextView(文本)组成。
首先定义Item显示界面。
item.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="80dip"
android:layout_height="wrap_content"
//android:text="1"
android:id="@+id/id"
/>
<TextView
android:layout_width="100dip"
android:layout_height="wrap_content"
//android:text="lisi"
android:id="@+id/name"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
//android:text="22"
android:id="@+id/age"
/>
</LinearLayout>
其次定义主界面。
main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="添加数据"
android:id="@+id/insertbutton"
/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="80dip"
android:layout_height="wrap_content"
android:text="ID"
/>
<TextView
android:layout_width="100dip"
android:layout_height="wrap_content"
android:text="姓名"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="年龄"
/>
</LinearLayout>
<ListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/listView"
/>
</LinearLayout>
然后把数据绑定到ListView中,并为Item指定界面。
//可以使用SimpleAdapter
List<Person> persons = personService.selectByPage(0, 5);
//创建Map对象
List<Map<String, Object>> data = new ArrayList<Map<String,Object>>();
for(Person person : persons){
Map<String, Object> item = new HashMap<String, Object>();
item.put("id", person.getId());
item.put("name", person.getName());
item.put("age", person.getAge());
data.add(item);
}
ListView listView = (ListView) this.findViewById(R.id.listView);
SimpleAdapter adapter = new SimpleAdapter(this, data, R.layout.item,
new String[]{"id", "name", "age"}, new int[]{R.id.id, R.id.name, R.id.age});
listView.setAdapter(adapter);

listView.setOnItemClickListener(new OnItemClickListener(){
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//parent:当前点击的ListView对象
//view:当前点击的条目所绑定的view
//position:绑定数据的位置
//id:view在ListView中的id
ListView aListView = (ListView) parent;
Map<String, Object> item = (Map<String, Object>) aListView.getItemAtPosition(position);
Toast.makeText(MainActivity.this, item.get("id").toString(), 1).show();
}
});


//也可以使用SimpleCursorAdapter
/*ListView listView = (ListView) this.findViewById(R.id.listView);
Cursor cursor = personService.selectCursorByPage(0, 5);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item, cursor,
new String[]{"_id", "name", "age"}, new int[]{R.id.id, R.id.name, R.id.age});
listView.setAdapter(adapter);

listView.setOnItemClickListener(new OnItemClickListener(){
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//parent:当前点击的ListView对象
//view:当前点击的条目所绑定的view
//position:绑定数据的位置
//id:view在ListView中的id
ListView aListView = (ListView) parent;
Cursor item = (Cursor) aListView.getItemAtPosition(position);
int personid = item.getInt(item.getColumnIndex("_id"));
Toast.makeText(MainActivity.this, personid + "", 1).show();
}
});*/
当使用SimpleCursorAdapter时,可能会出现以下异常信息:
SimpleCursorAdapter:ERROR/AndroidRuntime(344): Caused by: java.lang.IllegalArgumentException: column '_id' does not exist。
如何解决上述异常?
方法1:创建表时直接定义表的主键列名为"_id"。
方法2:在查询时为表的主键指定别名为"_id"。

分享到:
评论

相关推荐

    Android编程操作嵌入式关系型SQLite数据库实例详解

    本文实例分析了Android编程操作嵌入式关系型SQLite数据库的方法。分享给大家供大家参考,具体如下: SQLite特点 1.Android平台中嵌入了一个关系型数据库SQLite,和其他数据库不同的是SQLite存储数据时不区分类型 ...

    详解Android数据存储—使用SQLite数据库

    Android提供了3种操作数据的方式,SharedPreference(共享首选项)、文件存储以及SQLite数据库。 SQLite数据库文件被保存在/data/data/package_name/databases目录下。 一、创建和删除表 1.创建表 创建表的SQL语句...

    Android SQLite数据库增删改查操作的使用详解

    一、使用嵌入式关系型SQLite数据库存储数据 在Android平台上,集成了一个嵌入式关系型数据库——SQLite,SQLite3支持NULL、INTEGER、REAL(浮点数字)、 TEXT(字符串文本)和BLOB(二进制对象)数据类型,虽然它支持的...

    详解Android中一些SQLite的增删改查操作

    在Android开发中经常要涉及到对数据的操作。Android本身提供了四种数据存储方式。包括:SharePreference,SQLite,Content ...SharedPreference: 除SQLite数据库外,另一种常用的数据存储方式,其本质就是一个xml

    android 数据存储技术 详解

    android 数据存储技术 详解,会对大家有帮助的。里面包含了SharedPreference,文件存储,SQLITE,ContentProvider 的相应的源码例子。

    Android SQLite数据库彻底掌握数据存储

    主要介绍了 Android SQLite数据库的相关资料,这里对Android SQLlite做了详细介绍,需要的朋友可以参考下

    详解Android数据存储之SQLCipher数据库加密

    最近研究了Android Sqlite数据库以及ContentProvider程序间数据共享,我们清晰的知道Sqlite数据库默认存放位置data/data/pakage/database目录下,对于已经ROOT的手机来说的没有任何安全性可以,一旦被利用将会导致...

    Flutter持久化存储之数据库存储(sqflite)详解

    数据库存储是我们常用的存储方式之一,对大批量数据有增、删、改、查操作需求时,我们就会想到使用数据库,Flutter中提供了一个sqflite插件供我们用于大量数据执行CRUD操作。本篇我们就来一起学习sqflite的使用。 ...

    Android中SQLite 使用方法详解

    现在的主流移动设备像android、iPhone等都使用SQLite作为复杂数据的存储引擎,在我们为移动设备开发应用程序时,也许就要使用到SQLite来存储我们大量的数据,所以我们就需要掌握移动设备上的SQLite开发技巧。...

    详解Android轻量型数据库SQLite

    数据库是Android存储方案的核心,在Andorid中SQLite非常轻量,而且执行sql语句甚至比MySQL还要快。 SQLiteDatabase 是 Android 中操作数据库的核心类之一,使用SQLiteDatabase可以打开数据库,也可以对数据库进行...

    Android使用Realm数据库实现App中的收藏功能(代码详解)

    其中前四种都是缓存数据到本地,这篇主要讲的是使用第三种方式来实现App中的收藏功能,不过不用Android原生自带SQLite数据库来存储数据,而是使用第三方的Realm数据库来来存储数据。 Realm 本质上是一个嵌入式数据库...

    Android入门到精通源代码.

    9.3 使用SQLite数据库存储数据 9.3.1 SQLite数据库简介 9.3.2 SQLite数据库操作 9.3.3 使用SQLiteDatabase对象操作数据库 9.3.4 Cursor的使用 9.4 使用ContentProvider 9.4.1 定义ContentProvider 9.4.2 使用...

    浅谈Android游戏开发之详解SQLite存储

    早期由原名为"Android"的公司开发,谷歌在2005年收购"Android.Inc"后,继续进行对Android系统开发运营,它采用了软件堆层(software stack,又名以软件叠层)的架构,主要分为三部分。底层Linux内核只提供基本功能,...

    Android游戏开发之详解SQLite存储

    本篇主要是向大家介绍一种适合游戏数据存储的方式:SQLite轻量级数据库

    Android数据库LitePal的基本用法详解

    正好项目用了这种数据存储方式,特地写一篇加深印象,在我看来,LitePal是使用最简单,集成最方便的数据库,没有之一。 LitePal 简介 LitePal 是一款开源的 Android 数据库框架,它采用了对象关系映射(ORM)的模式...

    Android个人手机通讯录开发详解

    数据存储:SQLite 数据库 开发工具:Android Studio 二、Phone Module 简介 1. 界面展示 2. 文件结构简单分析 三、个人手机通讯录代码实现 1. 清单文件 (AndroidManifest.xml) &lt;?xml version=1.0 encoding=...

    Android实例代码

    第8章、Android的数据存储和IO 8.1、使用SharedPreferences:SharedPreferences; Editor; 8.2、File存储:openFileOutput和openFileInput; 读写SD卡文件; 8.3、SQLite数据库:SQL语句; SQLiteDatabase; ...

    Android基础知识详解

    SQLite数据库6.4 103 ContentProvider、ContentResolver 6.5 105 Intent 106 用Intent启动Activity,并在Activity之间传递数据 106 调用其他应用程序中的Activity(打电话、浏览网页、发Email等) 109 接收和发送广播 ...

Global site tag (gtag.js) - Google Analytics