首页 > 代码库 > Android开发之SQLite数据库详解

Android开发之SQLite数据库详解

Android开发之SQLite数据库详解


请尊重他人的劳动成果,转载请注明出处:Android开发之SQLite数据库详解 

http://blog.csdn.net/fengyuzhengfan/article/details/40194393

Android系统集成了一个轻量级的数据库:SQLite, SQLite并不想成为像OracleMySQL那样的专业数据库。SQLite只是一个嵌入式的数据库引擎,专门适用于资源有限的设备上(如手机、PDA等)适量数据存取。

虽然SQLite支持绝大部分SQL92语法,也允许开发者使用SQL语句操作数据库中的数据,但SQLite并不像OradeMySQL数据库那样需要安装、启动服务器进程,SQLite数据库只是一个文件。

从本质上来看,SQLite的操作方式只是一种更为便捷的文件操作。后面我们会看到,当应用程序创建或打开一个SQLite数据库时,其实只是打开一个文件准备读写,因此有人说SQLite有点像MicrosoftAccess (实际上SQLite功能要强大得多)。

1.SQLiteDatabase  简介

Android提供了SQLiteDatabase 代表一个数据库(底层就是一个数据库文件>,一旦应用程序获得了代表指定数据库的SQLiteDatabase 对象,接下来就可通过SQLiteDatabase 对象来管理、操作数据库了。

2.打开获取创建SQLiteDatabase的方法:

1)staticSQLiteDatabase  openDatabase(Stringpath,SQLiteDatabase .CursorFactory factory, intflags):打开path文件所代表的SQLite数据库。

2)staticSQLiteDatabase  openOrCreateDatabase(File file,SQLiteDatabase  .CursorFactory factory):打开或创建(如果不存在)file文件所代表的SQLite数据库。

3)staticSQLiteDatabase  openOrCreateDatabase(String path,SQLiteDatabase .CursorFactory factory):打开或创建(如果不存在)path文件所代表的SQLite数据库。

3.操作SQLiteDatabase 的方法主要有:

1)execSQL(Stringsql, Object[] bindArgs):执行带占位符的 SQL语句。

2)execSQL(String sql):执行 SQL语句。

3)insert(Stringtable, String nullColumnHack,ContentValues values):向执行表中插入数据。

4)update(Stringtable, ContentValues values, String whereClause, String[] whereArgs):吏新指定表中的特定数据。

5)delete(Stringtable, String whereClause, String[] whareArgs):删除指定表中的特定数据。

6)Cursorquery(String table, String[]columns, String selection, String[] selection Args,String groupBy, String having,String orderBy):对执行数据表执行査询。

7)Cursorquery(String table, String[] columns, String selection, String[] selectionArgs,String groupBy, String having, String orderBy, String limit}:对执行数据表执行査询。Limit参数控制最多査询几条记录(用于控制分页的参数)。

8)Cursorquery(boolean distinct, String table, String[] columns, String selection,String[] selectionArgs, String  groupBy, String having, String orderBy, String  limit)对指定表执行査询语句。其中第一个参数控制是否去除重复值。

9)rawQuery(Stringsql, String[] selectionArgs):执行带占位符的 SQL查询。

10)beginTransaction():开始事务。

11)endTransaction():结束事务。

 

从上面的方法不难看出,其实SQLiteDatabase的作用有点类似于JDBCConnection口,但SQLiteDatabase提供的方法更多:比如insertupdatedeletequery等方法,其实这些方法完全可通过执行SQL语句来完成,但Android考虑到部分开发者对SQL语法不熟悉,所以提供这些方法帮助开发者以更简单的方式来操作数据表的数据。

4.操作Cursor

上面査询方法都是返回一个Cursor对象,Android中的Cursor类似干JDBCResultSet Cursor同样提供了如下方法来移动査询结果的记录指针。

 

1)move(int offset):将记录指针向上或向下移动指定的行数。offset为正数就向下移动;为负数就是向上移动。

2)booleanmoveToFirst():将记录指针移动到第一行,如果移动成功则返回true

3)booleanmoveToLast():将记录指针移动到最后一行,如果移动成功则返回true

4)booleanmoveToNext():将记录指针移动到下一行,如果移动成功则返回true

5)booleanmoveToPosition(int position):将记录指针移动到指定的行,如果移动成功则返回true

6)booleanmoveToPrevious():将记录指针移动到上一行,如果移动成功则返回true

—旦将记录指针移动到指定行之后,接下来就可以调用CursorgetXxx()方法获取该行的指定列的数据。

其实如果大家具有JDBC编程的经验,完全可以把SQLiteDatabase当成JDBC :ConnectionStatement的混合体因为SQLiteDatabase 既代表了与数据库的连接,也可直接用于执行SQL操作;而AndroidCursor则可当成ResultSet,而且Cursor提供了更多便捷的方法来操作结果集。

5.创建数据库和表

前面已经讲到,使用SQLiteDatabase的静态方法即可打开或创建数据库,例如如下代码:

SQLiteDatabase.openOrCreateDatabase(“/mnt/db/temp.db3”,null)

上面的代码就用于打开或创建一个SQLite数据库,如果/mnt/db/目录下的temp.db3文件 (该文件就是一个数据库)存在,那么程序就是打开该数据库:如果该文件不存在,则上面的代码将会在该目录下创建temp.db3文件(即对应于数据库)

上面的代码中没有指定SQLiteDatabase.CursorFactory参数,该参数是一个用于返回 Cursor的工厂,如果指定该参数为null,则意味着使用默认的工厂。

上面的代码即可返回一个SQLiteDatabase对象,该对象的execSQL可执行任意的SQL语句。

通过如下代码在程序中创建数据表:

//定义建表语句

create tabletb_news(

id integer primarykey autoincrement,

title varchar(100)not null,

content varchar(2000));

在程序中执行上面的代码即可在数据库中创建一个数据表。

6.使用SQL语句操作SQLite数据库

正如前面提到的,SQLiteDatabaseexecSQL方法可执行任意SQL语句,包括带占位符SQL语句。但由于该方法没有返回值,一般用于执行DDL语句或DML语句;如果需要执行査询语句,则可调用SQLiteDatabase  rawQuery(String sqlString[] selectionArgs)方法。例如如下代码可用于执行DML语句,

//执行插入语句

String sql ="insert into tb_news(title,content,publishDate)values(?,?,?)";

db.execSQL(sql,new Object[]{news.getTitle(),news.getContent(),news.getPublishDate()});

提示:SQLite允许把各种类型的数据保存到任何类型字段中,开发者可以不用关心声明该字段所使用的数据类型。例如程序可以把字符串类型的值存INTEGER类型的字段中,也可以把数值类型的值存入布尔类型的字段中……但有一种情况例外:定义为INTEGERPRIMARY KEY的字段只能存储64位整数,当向这种字段保存除整数以外的其他类型的数据时,SQLite会产生错误。

由于SQLite允许存入数据时忽略底层数据列实际的数据类型,因此在编写建表语句时可以柯略数据列后面的类型声明,例如如下SQL语句对于SQLite也是正确的。

create table my_test

(_id integer primary key autoincrement,

name,pwd)

7.使用Android数据库操作的操作数据库

AndroidSQLiteDatabase 提供了 insertupatedelete query 语句来操作数据库。

1.使用insert方法插入记录

SQLiteDatabase  insert方法的签名为 longinsert (String table, String nullColumnHack ContentValuesvalues),这个插入方法的参数说明如下。

table:代表想插入数据的表名。

nullColumnHack:代表强行插入null值的数据列的列名。

values:代表一行记录的数据。

insert方法插入的一行记录使用ComentValues存放,ContentValues类似于Map,它提供 put<StringkeyXxxvalue>其中key为数据列的列名,该方法用于存入数据、getAsXxx(String key)方法用于取出数据。

例如如下语句:

ContentValues values = new ContentValues();

values.put ("name” , “孙悟空”);

values.put(“age”, 500);

//返回新添记录的行号,该行号是一个内部值,与主键1^1无关,发生铕误返回一1

long rowid = db.insert("person_in”,null,values);

不管第三个参数是否包含数据,执行insert()方法总会添加一条记录,如果第三个参数为空,会添加一条除主键之外其他宇段值都为null的记录。

insert()方法的底层实际上依然是通过构造insert SQL语句来进行插入的,因此它生成的 SQL语句总是形如下面的语句:

//ContentValue key-value对的数值决定了下面的key-value.

insert into <表名>(key1,key 2...) values(valuel , value2 ...)

此时如果第三个参数为null或其中key-value对的数量为0,由于insert方法还会按此方式生成一条insert语句,此时的insert语句为:

insert into <表名>()values()

上面的SQL语句显然有问题,为了满足SQL语法的需要,insert语句必须给定一个列名,如:insert intoperson(name)values(null),这个name列名就由第二个参数来指定。由此可见,ComentValuesnull或它包含的key-value对的数量为()时,第二个参数就会起作用了。

一般来说,第二个参数指定的列名不应该是主键列的列名,也不应该是非空列的列名,否则强行往这些数据列插入nul会引发异常。

2.使用update方法更新记录

SQLiteDatabase  update方法的签名为update(String table, ContentValues values, String whereClause, String[]whereArs),这个更新方法的参数说明如下:

table:代表想更新数据的表名。

values:代表想更新的数据。

whereClause:满足该whereClause子句的记录将会被更新。

whereArgs:用于为whereClause子句传入参数。

该方法返回受此update语句影响的记录的条数。

实例:

ContentValues values=new ContentValues();

      values.put("title", news.getTitle());

      values.put("content", news.getContent());

      db.update("tb_news", values, "id=?",new String[]{String.valueOf(news.getId())});

3.使用delete方法删除记录

SQLiteDatabase  delete方法的签名为delete(String table , String whereClause, String[]whereArgs),这个删除的参数说明如下。

table:代表想删除数据的表名。

whereClause:满足该whereClause子句的记录将会被删除。

whereArgs:用于为whereClause子句传入参数。

该方法返回受此delete语句影响的记录的条数。

实例:

db=helper.getWritableDatabase();

      db.execSQL("delete from tb_news where id=?",new String[]{String.valueOf(newsId)});

使用query方法查询记录

SQLiteDatabase  query方法的签名为 Cursorquery(boolean distinct, String tableString[]

columns, String selection, Stringl]selecrionArgs, String groupBy, String having. String orderBy, String limit),这个query方法的参数说明如下,

distinct:指定是否去除重复记录,

table:执行査询数据的表名。

columns:要査询出来的列名。相当于select语句select关键字后面的部分s

selection:査询条件子句,相当于select语句where关键字后面的部分,在条件子

句中允许使用占位符。

selectionArgs:用于为selection子句中占位符传入参数值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。

groupBy:用于控制分组?相当于select语句group by关键字后面的部分

having:用于对分组进行过滤。相当于select语句having关键字后面的部分

orderBy:用于对记录进行排序。相当于select语句order by关键字后面的部分,如:personid desc, age asc;

limit:用于进行分页,相当于select语句limit关键字后面的部分。

实例:

/**

 *获取分页数据

 *@param currentPage当前页码

 *@param pageSize每页显示的数据量

 *@return

 */

public List<News> getNewsByPage(int currentPage,int pageSize) {

   db=helper.getReadableDatabase();

   List<News>list=newArrayList<News>();

   String start=String.valueOf((currentPage-1)*pageSize);

   Cursor cursor=db.query(true,"tb_news",null,null,null,null,null,"id asc",start+","+String.valueOf(pageSize));

//    Stringsql="select* from tb_news order by id asc limit ?,?";

//    Cursorcursor=db.rawQuery(sql, new String[]{start,String.valueOf(pageSize)});

   while(cursor.moveToNext()){

      intid=cursor.getInt(cursor.getColumnIndex("id"));

      Stringtitle=cursor.getString(cursor.getColumnIndex("title"));

      Stringcontent=cursor.getString(cursor.getColumnIndex("content"));       

      StringdateString=cursor.getString(cursor.getColumnIndex("publishDate"));

      Date publishDate=null;

      try {

          publishDate= Utils.convertStr2Date(dateString);

      }catch (ParseException e) {

          //TODO Auto-generated catch block

          e.printStackTrace();

      }                

      list.add(new News(id, title,content, publishDate));

   }

   return list;

   

   

}

8.事务

SQLiteDatabase中包含如下两个方法来控制事务。

beginTransaction():开始事务。

endTransaction():结束事务。

除此之外,SQLileDatabase还提供了如下方法来判断当前上下文是否处于事务环境中》

inTransaction():如果当前上下文处于事务中,则返回true:否则返回false

当程序执行endTiansaction()方法时将会结束事务——那到底是提交事务呢,还是回滚事务呢?这取决于SQLiteDatabase是否调用了 setTransactionSuccessful()方法来设置事务标志, 如果程序事务执行中调用该方法设置了事务成功则提交事务,否则程序将会回滾事务。示例代码如下:

//事务处理

publicvoid tran(int id1,int id2,int des){

   SQLiteDatabase db =helper.getWritableDatabase();

   //按照这个语法格式写事务

   db.beginTransaction();//开始事务

   try{

      db.execSQL("update tb_news set account=account - ? whereid=?",new Integer[]{des,id1});

//        inti = 1 / 0;

      db.execSQL("update tb_news set account=account + ? whereid=?",new Integer[]{des,id2});

      db.setTransactionSuccessful();//设置事务成功标志

   }finally{

      db.endTransaction();//结束事务:看事务是否成功,如果则提交,如果失败则回滚

   }

}

9.SQLiteOpenHelper

SQLiteOpenHelperAndroid提供的一个管理数据库的工具类,可用于管理数据库的创建和版木更新。一般的用法是创建SQLiteOpenHelper的子类,并扩展它的onCreate (SQLiteDatabasedb) onUpgrade (SQLiteDatabasedbintoldVersionintnewVersion)方法。

SQLiteOpenHelper包含如下常用的方法。

synchronized SQLiteDatabase  getReadableDatabase():以读写的方式打开数据库对应的SQLiteDatabase对象。

synchronized SQLiteDatabase  getWritableDatabase():以写的方式打开数据库对应的SQLiteDatabase 对象。

abstract void onCreate (SQLiteDatabase db):当第一次创建数据库时回调该方法。

abstract void onUpgrade (SQLiteDatabase db, int oldVersion, int newVersion):当数据库版本更新时回调该方法。

synchronized void close():关闭所有打开的SQLiteDatabase

从上面的方法介绍中不难看出,SQLiteOpenHelper提供了getReadableDatabase() getWritableDatabase()两个方法用于打开数据库连接,并提供了close方法来关闭数据库连接,而开发者需要做的就是重写它的两个抽象方法。

onCreate (SQLiteDatabase db):

用于初次使用软件时生成数据库表,当调用SQLiteOpenHelper getWritableDatabase()或者 getReadableDalabase()方法获取用于操作数据库的SQLiteDatabase实例时,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreateO方法,onCreateO方法在初次生成数据库时才会被调用,在onCreateO方法里可以生成数据库表结构及添加一些应用使用到的初始化数据。

onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):

用于升级软件时更新数据库表结构,方法在数据库的版本发生变化时会被调用,该方法调用时oldVersion代表数据库之前的版本号,newVersion代表当前数据库当前的版本号。那么在哪里指定数据库的版本号呢?当程序创建SQLiteOpenHelper对象时,必须指定一个version参数,该参数就决定了所使用的数据库的版本——也就是说,数据库的版本是由程序员控制的。只要某次创建 SQLiteOpenHdper时指定的数据库版本号高于之前指定的版本号,系统就会自动触发 onUpgrade(SQLiteDatabase db, int oldVersion, int new Version)方法,程序就可以在onUpgrade()方法里面根据原版号和目标版本号进行判断,即可根据版本号进行必需的表结构更新。

提示:实际上,当应用程序升级表结构时,完全可能因为已有的数据导致升级失败,在这种时候程序可能需要先对数据进行转姑,清空数据表中的记录,接着对数据!表进行更新,当教据表更新完成后再将教据保存回来。

一旦得到了SQLiteOpenHelper对象之后,程序无须使用SQLiteDatabase的静态方法创建SQLiteDatabase 实例,而且可以使用getWritableDatabase() getReadableDatabase()方法来获取一个用于操作数据库的SQLiteDatabase实例。

其中getWritableDatabase()方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用getWritableDatabase()打开数据库就会出错。 getReadableDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失敗后会继续尝试以只读方式打开数据库。

请尊重他人的劳动成果,转载请注明出处:Android开发之SQLite数据库详解 

http://blog.csdn.net/fengyuzhengfan/article/details/40194393


 

Android开发之SQLite数据库详解