前几天一直在做一个课表的小软件,里面涉及到的数据库。
在Android平台上,集成了一个嵌入式关系型数据库—sqlite,
1、sqlite3支持NULL、INTEGER、REAL(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)数据类型,虽然它支持的类型虽然只有五种,但实际上sqlite3也接受varchar(n)、char(n)、decimal(p,s) 等数据类型,只不过在运算或保存时会转成对应的五种数据类型。
2、sqlite最大的特点是你可以保存任何类型的数据到任何字段中,无论这列声明的数据类型是什么。例如:可以在Integer字段中存放字符串,或者在布尔型字段中存放浮点数,或者在字符型字段中存放日期型值。
3、但有一种情况例外:定义为INTEGER PRIMARY KEY的字段只能存储64位整数, 当向这种字段中保存除整数以外的数据时,将会产生错误。
4、另外, sqlite 在解析CREATE TABLE 语句时,会忽略 CREATE TABLE 语句中跟在字段名后面的数据类型信息,如下面语句会忽略 name字段的类型信息:
CREATE TABLE person (personid integer primary key autoincrement,name varchar(20))
sqlite可以解析大部分标准sql语句,如:
查询语句:select * from 表名 where 条件子句 group by 分组字句 having ... order by 排序子句
如:select * from person
select * from person order by id desc
select name from person group by name having count(*)>1
分页sql与MysqL类似,下面sql语句获取5条记录,跳过前面3条记录
select * from Account limit 5 offset 3 或者 select * from Account limit 3,5
插入语句:insert into 表名(字段列表) values(值列表)。如: insert into person(name,age) values(‘传智’,3)
更新语句:update 表名 set 字段名=值 where 条件子句。如:update person set name=‘传智‘ where id=10
删除语句:delete from 表名 where 条件子句。如:delete from person where id=10
Android提供了一个名为
sqliteDatabase的类,该类封装了一些操作
数据库的API。
public static
sqliteDatabase openDatabase(String path,
sqliteDatabase.CursorFactory factory,int flags)
flags参数可以是 OPEN_READWRITE, OPEN_READONLY ,CREATE_IF_NECESSARY, NO_LOCALIZED_COLLATORS四个的一个或多个(多个模式组合用|隔离).
public static
sqliteDatabase openOrCreateDatabase(File file,
sqliteDatabase.CursorFactory factory)
public static
sqliteDatabase openOrCreateDatabase(String path,
sqliteDatabase.CursorFactory factory)
public abstract
sqliteDatabase openOrCreateDatabase(String name,int mode,
sqliteDatabase.CursorFactory factory)直接在私有
数据库目录创建或打开一个名为name的
数据库,
注意:mode只的是MODE_PRIVATE,MODE_WORLD_READABLE, MODE_WORLD_WRITEABLE。
Context还有:
public abstract String[] databaseList();//返回私有
数据库目录所有
数据库名字
public abstract boolean deleteDatabase(String name);//
删除私有
数据库目录内
文件名为name的
数据库。
public static
sqliteDatabase create(
sqliteDatabase.CursorFactory factory)
来创建,创建失败返回null。
最后记住,不管用何种方式打开了
数据库,获得的
sqlite对象不再使用时,都要
调用close()来
关闭打开的
数据库,否则抛出IllegalStateException异常。
使用
sqliteDatabase对象可以完成对数据进行
添加(Create)、
查询(Retrieve)、更新(Update)和
删除 (Delete)操作(这些操作简称为CRUD)。对
sqliteDatabase的学习,我们应该重点掌握exec
sql()和rawQuery()方 法。 exec
sql()
方法可以执行insert、delete、update和CREATE TABLE之类有更改行为的
sql语句; rawQuery()
方法可以执行select语句。
sqliteDatabase db = ....;
db.exec
sql("insert into person(name,age) values('传智播客',4)");
db.close();
执行上面
sql语句会往person表中
添加进一条记录,在实际应用中, 语句中的“传智播客”这些参数值应该由
用户输入界面提供,如果把
用户输入的
内容原样组拼到上面的insert语句, 当
用户输入的
内容含有单引号时,组拼出来的
sql语句就会存在语法
错误。要
解决这个问题需要对单引号进行转义,也就是把单引号转换成两个单引号。有些时候
用户往往还会输入像“ & ”这些特殊
sql符号,为保证组拼好的
sql语句语法正确,必须对
sql语句中的这些特殊
sql符号都进行转义,显然,对每条
sql语句都做这样的处理工 作是比较烦琐的。
sqliteDatabase类提供了一个重载后的exec
sql(String
sql,Object[] bindArgs)
方法,使用这个
方法可以
解决前面提到的问题,因为这个
方法支持使用占位符参数(?)。使用例子如下:
sqliteDatabase db = ....;
db.exec
sql("insert into person(name,age) values(?,?)",new Object[]{"传智播客",4});
db.close();
exec
sql(String
sql,Object[] bindArgs)
方法的第一个参数为
sql语句,第二个参数为
sql语句中占位符参数的值,参数值在数组中的顺序要和占位符的位置对应。
sqliteDatabase的rawQuery() 用于执行select语句,使用例子如下:
sqliteDatabase db = ....;
Cursor cursor = db.rawQuery(“select * from person”,null);
while (cursor.moveToNext()) {
int personid = cursor.getInt(0); //
获取第一列的值,第一列的索引从0开始
String name = cursor.getString(1);//
获取第二列的值
int age = cursor.getInt(2);//
获取第三列的值
}
cursor.close();
db.close();
rawQuery()
方法的第一个参数为select语句;第二个参数为select语句中占位符参数的值,如果select语句没有使用占位符,该参数可以设置为null。带占位符参数的select语句使用例子如下:
Cursor cursor = db.rawQuery("select * from person where name like ? and age=?",new String[]{"%传智%","4"});
Cursor是结果集游标,用于对结果集进行
随机访问,如果大家熟悉jdbc, 其实Cursor与JDBC中的ResultSet作用很相似。使用moveToNext()
方法可以将游标从当前行移动到下一行,如果已经移过了结果集 的最后一行,返回结果为false,否则为true。另外Cursor 还有常用的moveToPrev
IoUs()
方法(用于将游标从当前行移动到上一行,如果已经移过了结果集的第一行,返回值为false,否则为true )、moveToFirst()
方法(用于将游标移动到结果集的第一行,如果结果集为空,返回值为false,否则为true )和moveToLast()
方法(用于将游标移动到结果集的最后一行,如果结果集为空,返回值为false,否则为true ) 。
除了前面给大家介绍的exec
sql()和rawQuery()
方法,
sqliteDatabase还专门提供了对应于
添加、
删除、更新、
查询的操作
方法: insert()、delete()、update()和query() 。这些
方法实际上是给那些不太了解
sql语法的人使用的,对于熟悉
sql语法的程序员而言,直接使用exec
sql()和rawQuery()
方法执行
sql语句就能完成数据的
添加、
删除、更新、
查询操作。
Insert()
方法用于
添加数据,各个字段的数据使用ContentValues进行存放。 ContentValues类似于MAP,相对于MAP,它提供了存取数据对应的put(String key,Xxx value)和getAsXxx(String key)
方法, key为字段
名称,value为字段值,Xxx指的是各种常用的数据类型,如:String、Integer等。
sqliteDatabase db = databaseHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name","传智播客");
values.put("age",4);
long rowid = db.insert(“person”,null,values);//返回新添记录的行号,与主键id无关
不管第三个参数是否包含数据,执行Insert()
方法必然会
添加一条记录,如果第三个参数为空,会
添加一条除主键之外其他字段值为Null的 记录。Insert()
方法内部实际上通过构造insert语句完成数据的
添加,Insert()
方法的第二个参数用于指定空值字段的
名称,相信大家对此 参数会感到疑惑,此参数的作用是干嘛的?是这样的:如果第三个参数values 为Null或者元素个数为0, Insert()
方法必然要
添加一条除了主键之外其它字段为Null值的记录,为了满足这条insert语句的语法, insert语句必须给定一个字段名,如:insert into person(name) values(NULL),倘若不给定字段名 , insert语句就成了这样: insert into person() values(),显然这不满足标准
sql的语法。对于字段名,建议使用主键之外的字段,如果使用了INTEGER类型的主键字段,执行类似insert into person(personid) values(NULL)的insert语句后,
该主键字段值也不会为NULL。如果第三个参数values 不为Null并且元素的个数大于0 ,可以把第二个参数设置为null。
sqliteDatabase db = databaseHelper.getWritableDatabase();
db.delete("person","personid<?",new String[]{"2"});
db.close();
上面
代码用于从person表中
删除personid小于2的记录。
sqliteDatabase db = databaseHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(“name”,“传智播客”);//key为字段名,value为值
db.update("person",values,"personid=?",new String[]{"1"});
db.close();
上面
代码用于把person表中personid等于1的记录的name字段的值改为“传智播客”。
query()
方法实际上是把select语句拆分成了若干个组成部分,然后作为
方法的输入参数:
sqliteDatabase db = databaseHelper.getWritableDatabase();
Cursor cursor = db.query("person",new String[]{"personid,name,age"},"name like ?",new String[]{"%溧阳%"},"personid desc","1,2");
while (cursor.moveToNext()) {
int personid = cursor.getInt(0); //
获取第一列的值,第一列的索引从0开始
String name = cursor.getString(1);//
获取第二列的值
int age = cursor.getInt(2);//
获取第三列的值
}
cursor.close();
db.close();
上面
代码用于从person表中查找name字段含有“传智”的记录,匹配的记录按personid降序排序,对排序后的结果略过第一条记录,只
获取2条记录。
query(table,columns,selection,selectionArgs,groupBy,having,orderBy,limit)
方法各参数的含义:
table:表名。相当于select语句from关键字后面的部分。如果是多表联合
查询,可以用逗号将两个表名分开。
columns:要
查询出来的列名。相当于select语句select关键字后面的部分。
selection:
查询条件子句,相当于select语句where关键字后面的部分,在条件子句允许使用占位符“?”
selectionArgs:对应于selection语句中占位符的值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。
groupBy:相当于select语句group by关键字后面的部分
having:相当于select语句having关键字后面的部分
orderBy:相当于select语句order by关键字后面的部分,如:personid desc,age asc;
limit:指定偏移量和
获取的记录数,相当于select语句limit关键字后面的部分。
如果应用使用到了
sqlite
数据库,在
用户初次使用软件时,需要创建应用使用到的
数据库表结构及
添加一些初始化记录,另外在软件
升级的时候, 也需要对数据表结构进行更新。在Android系统,为我们提供了一个名为
sqliteOpenHelper的类,该类用于对
数据库版本进行管理,该类是 一个抽象类,必须继承它才能使用。 为了实现对
数据库版本进行管理,
sqliteOpenHelper类有两种重要的
方法,分别是onCreate(
sqliteDatabase db)和onUpgrade(
sqliteDatabase db,int oldVersion,int newVersion)。还可以实现public abstract void onUpgrade(
sqliteDatabase db,int newVersion)
方法,它在每次成功打开
数据库后首先被执行,默认情况下此
方法的实现为空。
当
调用sqliteOpenHelper的getWritableDatabase()或者getReadableDatabase()
方法获 取用于操作
数据库的
sqliteDatabase实例的时候,如果
数据库不存在,Android系统会
自动生成一个
数据库,接着
调用onCreate()
方法,onCreate()
方法在初次
生成数据库时才会被
调用,在onCreate()
方法里可以
生成数据库表结构及
添加一些应用使用到的初始化数据。 onUpgrade()
方法在
数据库的版本发生变化时会被
调用,
数据库的版本是由程序员控制的,假设
数据库现在的版本是1,由于业务的需要,
修改了
数据库 表的结构,这时候就需要
升级软件,
升级软件时希望更
新用户手机里的
数据库表结构,为了实现这一目的,可以把原来的
数据库版本设置为2(有同学问设置为3行 不行?当然可以,如果你愿意,设置为100也行),并且在onUpgrade()
方法里面实现表结构的更新。当软件的版本
升级次数比较多,这时在 onUpgrade()
方法里面可以根据原版号和目标版本号进行判断,然后作出相应的表结构及数据更新。
getWritableDatabase()和getReadableDatabase()
方法都可以
获取一个用于操作
数据库的
sqliteDatabase实例。但getWritableDatabase()
方法以读写方式打开
数据库,一旦
数据库的磁盘空间满了,
数据库就只能读而不能写,倘若使用的是getWritableDatabase()
方法就会出错。getReadableDatabase()
方法先以读写方式打开
数据库,如果
数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝 试以只读方式打开
数据库。但若随后再次
调用此
方法时,问题已经被
解决,只读的
sqliteDatabase对象会被
关闭,而重新返回一个可读写的
sqliteDatabase
数据库对象。
public class DatabaseHelper extends
sqliteOpenHelper {
//类没有实例化,是不能用作
父类构造器的参数,必须声明为静态
private static final String name = "itcast"; //
数据库名称
private static final int version = 1; //
数据库版本
public DatabaseHelper(Context context) {
//第三个参数CursorFactory指定在执行
查询时获得一个游标实例的工厂类,设置为null,代表使用系统默认的工厂类
super(context,version);
}
@Override public void onCreate(
sqliteDatabase db) {
db.exec
sql("CREATE TABLE IF NOT EXISTS person (personid integer primary key autoincrement,name varchar(20),age INTEGER)");
}
@Override public void onUpgrade(
sqliteDatabase db,int newVersion) {
db.exec
sql("DROP TABLE IF EXISTS person");
onCreate(db);
}
}
public class DatabaseHelper extends
sqliteOpenHelper {
private static final String name = "itcast"; //
数据库名称
private static final int version = 1; //
数据库版本
......略
}
public class HelloActivity extends Activity {
@Override public void onCreate(Bundle savedInstanceState) {
......
Button button =(Button) this.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
DatabaseHelper databaseHelper = new DatabaseHelper(HelloActivity.this);
sqliteDatabase db = databaseHelper.getWritableDatabase();
db.exec
sql("insert into person(name,4});
db.close();
}});
}
}
第一次
调用getWritableDatabase()或getReadableDatabase()
方法 后,
sqliteOpenHelper会缓存当前的
sqliteDatabase实例,
sqliteDatabase实例正常情况下会维持
数据库的打开状 态,所以在你不再需要
sqliteDatabase实例时,请及时
调用close()
方法释放资源。一旦
sqliteDatabase实例被缓存,多次调 用getWritableDatabase()或getReadableDatabase()
方法得到的都是同一实例。
使用
sqliteDatabase的beginTransaction()
方法可以开启一个事务,程序执行到endTransaction()
方法时会检查事务的标志是否为成功,如果为成功则提交事务,否则回滚事务。当应用需要提交事务,必须在程序执行到endTransaction()
方法之 前使用setTransactionSuccessful()
方法设置事务的标志为成功,如果不
调用setTransactionSuccessful()
方法,默认会回滚事务。使用例子如下:
sqliteDatabase db = ....;
db.beginTransaction();//开始事务
try {
db.exec
sql("insert into person(name,4});
db.exec
sql("update person set name=? where personid=?",new Object[]{"传智",1});
db.setTransactionSuccessful();//
调用此
方法会在执行到endTransaction() 时提交当前事务,如果不
调用此
方法会回滚事务
} finally {
db.endTransaction();//由事务的标志决定是提交事务,还是回滚事务
}
db.close();
package com.android.course;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.
sqlite.
sqliteDatabase;
import android.database.
sqlite.
sqliteOpenHelper;
public class Course
sql extends
sqliteOpenHelper{
private static final String DB_NAME = "Curriculum.db";
private static final String TBL_NAME1 = "Course";
private static final String TBL_NAME2 = "CourseName";
private static final String TBL_NAME3= "CourseAddress";
private static final String CREATE_TBL1= " create table "
+ " Course(_id integer primary key autoincrement,WeekDay Text,CourseNum text," +
"CourseName text,CourseAddress text,CourseTeacher text) ";
private static final String CREATE_TBL2 = " create table "
+ " CourseName(_id integer primary key autoincrement,CourseName text) ";
private static final String CREATE_TBL3 = " create table "
+ " CourseAddress(_id integer primary key autoincrement,CourseAddress text) ";
private
sqliteDatabase db;
public Course
sql(Context c) {
super(c,DB_NAME,2);
}
@Override //创建三个表
public void onCreate(
sqliteDatabase db) {
this.db = db;
db.exec
sql(CREATE_TBL1);
db.exec
sql(CREATE_TBL2);
db.exec
sql(CREATE_TBL3);
}
public void onCreate(
sqliteDatabase db,int num) {
this.db = db;
switch(num)
{
case 0:
db.exec
sql(CREATE_TBL1);
break;
case 1:
db.exec
sql(CREATE_TBL2);
break;
case 2:
db.exec
sql(CREATE_TBL3);
break;
}
}
//插入数据
public void insert(ContentValues values,int num) {
sqliteDatabase db = getWritableDatabase();
if(num ==0){
db.insert(TBL_NAME1,values);
}
else if(num == 1){
db.insert(TBL_NAME2,values);}
else if (num == 2){
db.insert(TBL_NAME3,values);
}
db.close();
}
//
查询数据
public Cursor query(int num) {
sqliteDatabase db = getWritableDatabase();
Cursor c = null;
if(num ==0){
c = db.query(TBL_NAME1,null);
}
else if(num == 1){
c = db.query(TBL_NAME2,null);
}
else if(num == 2)
{
c = db.query(TBL_NAME3,null);
}
return c;
}
// 当天课表
查询
public Cursor RawQuery(String Today)
{
sqliteDatabase db = getWritableDatabase();
String
sql ="SELECT * FROM "+TBL_NAME1+" WHERE WeekDay=?";
Cursor c = db.rawQuery(
sql,new String[]{Today});
return c;
}
// 根据_id
删除数据
public void del(int id,int num) {
if (db == null)
db = getWritableDatabase();
if(num == 0)
{
db.delete(TBL_NAME1,"_id=?",new String[] { String.valueOf(id) });}
else if(num ==1)
{
db.delete(TBL_NAME2,new String[] { String.valueOf(id) });
}
else if (num ==2)
{
db.delete(TBL_NAME3,new String[] { String.valueOf(id) });
}
}
//
关闭数据库
public void close() {
if (db != null){
db.close();
}
}
//版本更新
public void Update(int num) {
sqliteDatabase db = getWritableDatabase();
switch(num)
{
case 0:
db.exec
sql("DROP TABLE IF EXISTS "+TBL_NAME1);
this.onCreate(db,num);
break;
case 1:
db.exec
sql("DROP TABLE IF EXISTS "+TBL_NAME2);
this.onCreate(db,num);
break;
case 2:
db.exec
sql("DROP TABLE IF EXISTS "+TBL_NAME3);
this.onCreate(db,num);
break;
}
}
/更新课程和课程地点 public void update(String CourseName,String CourseAddress,String Weekday,String CourseNum) {
sqliteDatabase db = getWritableDatabase(); db.exec
sql( "update "+TBL_NAME1+" set CourseName=?,CourseAddress=? where WeekDay=? and CourseNum=?",new String[] {CourseName,CourseAddress,Weekday,CourseNum}); } @Override public void onUpgrade(
sqliteDatabase db,int newVersion) { // TODO Auto-generated method stub } }
原文链接:https://www.f2er.com/sqlite/201475.html