你的位置:首页 > 操作系统

[操作系统]android菜鸟学习笔记20


Android内置了一个名为SQLite的关系型数据库,这是一款轻量型的数据库,操作十分简便。SQLite与别的数据库不同的是,它没有数据类型。可以保存任何类型的数据到你所想要保存的任何表的任何列中。但它又支持常见的类型比如: NULL, VARCHAR, TEXT, INTEGER, BLOB, CLOB...等。

唯一的例外是:integer primary key 此字段只能存储64位整数。

在JAVA项目中,要使用JDBC操作数据库需要加载数据库驱动,连接数据库等操作。Android简化了我们的数据库操作,无需由我们进行数据库驱动加载、连接等操作。

Android中进行数据库操作,需要涉及到如下几个类:

1)SQLiteOpenHelper:

在android.database.sqlite包下,这是一个抽象的帮助类,用于管理数据库的创建及版本维护操作。

我们在需要获取该类的对象时,需要自定义类继承自SQLiteOpenHelper类,并实现其中的onCreate(SQLiteDatabase), onUpgrade(SQLiteDatabase, int, int),可以选择性地实现 onOpen(SQLiteDatabase)。这个类会自动帮助我们在需要时打开数据库,在不存在时创建数据库,在必要时更新数据库。

常用方法:

 

一般,在自定义的子类中调用父类中第一个构造方法即可。

构造函数的参数说明:

context:应用的上下文对象

name:要操作的数据库的名称

factory:cursor工厂类对象,一般指定为null

version:数据库的版本号,必须大于等于1,由于控制数据库的升级。

 

注意到,只有onCreate()和onUpgrade()是抽象方法,所以自定义子类继承SQLiteOpenHelper时,一定要实现这两个方法。

其中:

onCreate()方法会在数据库不存在,第一次创建时调用,所以数据库中的初始化操作,如创建表等操作需要在该方法中完成。

onUpgrade()方法,新的版本号比原来有提升时,调用,用以完成数据库的升级操作,如新版本的app中,需要添加一张表,或者修改某个表,就需要在新版本的app创建SQLiteOpenHelper对象时,向其构造函数传入一个更大的版本号,这个版本号会被newVersion接收。

 

getReadaleDatabase()方法,创建或打开一个数据库,返回代表该数据库的只读的SQLiteDatabase对象

getWritableDatabase()方法,创建或打开一个数据库,返回代表该数据库的可读可写的SQLiteDatabase对象。

 

close()方法,用于关闭打开的数据库对象。

2)SQLiteDatabase:

通过SQLiteOpenHelper对象获取SQLiteDatabase对象后,便可以调用SQLiteDatabase类的相关方法进行数据库的增删改查操作了。

该类的常用方法有:

 

execSQL()方法用于执行SQL语句,可以用于执行不需要返回值的一些数据库操作。

 

rawQuery()方法一般被用于执行需要返回值的查询操作,查询的结果保存在Cursor对象中。

除了直接执行SQL语句进行数据库操作的方法之外,该类还封装几个更易用的增删改查方法。

 

insert()方法,用于向数据库中插入数据,参数说明:

table:指定要插入数据的表明

nullColumnHack:一般指定为null即可

注意:当values也为null,表示想向数据库中插入一条空记录时,该方法实际执行的SQL语句为insert into table(null) values(null);这样一条sql语句是没法执行的,所以,需要将nullColumnHack指定为任意一个可以为空的字段的字段名。如:nullColumnHack指定为”name”,values为null,此时SQL语句为insert into table(name) values(null);则可以正常执行了。

values:是一个ContentValues对象,用于存放要插入的各个字段名与值的对应关系。

 

delete()方法,用于删除表中的记录,参数说明:

table指定要操作的表名

whereClause指定where字句,可以包含占位符”?”,如“name = ?”,实际执行时,占位符会被第三个参数中对应索引的值替换

whereArgs:指定where字句中,占位符对应的值,如new String[]{“zhangsan”}

实际执行的语句就是delete from table where name = “zhangsan”

 

update()方法,用于执行表中记录的更新操作,参数说明:

table,whereClause,whereArgs与delete相同含义

values用于指定对应字段名要更新的值的映射关系。

 

query()记录查询方法,最简单的一个重载形式也有七个参数,都是select中的各个字句部分,如where子句部分,group by子句部分,having,order by等。参数说明:

table指定要查询的表名

colmns指定要查询的字段

selection:可以带占位符的where子句部分

slectionArgs:where子句占位符对应的值

groupBy:group by子句部分

having:having子句部分

orderBy:order by 子句部分

等等

 

isOpen()判断数据库是否已打开。

 

beginTransaction()用于开启事务操作

 

setTransactionSuccessful()方法用于标记事务操作成功

 

endTransaction()方法用于关闭事务,若事务标记成功,则提交事务操作,否则,则回滚失败的事务操作。

其他方法,在需要时,可以查询API帮助手册。

3)Cursor:

Cursor是一个接口,其实现类用于存放SQL语句查询的结果集。SQLiteDatabase的rawQuery()及query()方法均会返回该接口的对象,用以存储操作查询返回的结果集。

Cursor对象维持一个游标,默认指向结果集第一条记录之前的位置,可以通过下面几个方法,来移动游标,从而取得需要的记录。当游标已在第一条记录之前,调用moveToPreious(),或者已指向最后一条记录,调用moveToNext()方法时,均会返回false()标识移动失败。

 

 

getShort()、getString()、getInt()等getXXX()方法,用于根据当前记录的字段的索引获取字段的值。

 

getColumnName()用于根据索引获取字段名

getColumnNames()用于获取所有的字段名,其顺序与在Cursor中保存的顺序相同。

getCount()用于获取当前Cursor对象中保存的记录数。

 

getColumnCount()方法用于获取记录的字段总数

getColumnIndex()用于根据字段名获取其索引,不存在时返回-1。

 

close()方法,用于关闭当前Cursor对象。

4)ContentValues:

该类用于存放键值对的数据,在数据库的插入更新等操作中,可以使用字段名作为键,使用要插入或更新的字段值作为值。

常用的是put()方法,向ContentValues对象中存储数据。

如:put(“name”,”zhangsan”);等

以上便是数据库操作所涉及的几个主要的类和接口。

下面通过一个具体的代码,来学习使用这些个API:

第一步:

自定义类继承SQLiteOpenHelper类,实现onCreate()和onUpgrade()方法:

 1 public class MySqliteHelper extends SQLiteOpenHelper { 2  3    public static final String TAG = "MYSQLITEHELPER"; 4  5    public static final String CREATE_STUDENT = "create table t_student (" + 6  7         "id integer primary key, name varchar(20), gender varchar(10), age integer)"; 8  9    public MySqliteHelper(Context context, String name, CursorFactory factory,10 11         int version) {12 13      super(context, name, factory, version);14 15    }16 17    @Override18 19    public void onOpen(SQLiteDatabase db) {20 21      Log.i(TAG,"open db");22 23      super.onOpen(db);24 25    }26 27    @Override28 29    public void onCreate(SQLiteDatabase db) {30 31      Log.i(TAG,"create db");32 33      Log.i(TAG,"before excSql");34 35       db.execSQL(CREATE_STUDENT);36 37      Log.i(TAG,"after excSql");38 39    }40 41    @Override42 43    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {44 45 46    }47 48 }

第二步,定义实体类:

 1 package cn.csc.sqlite.bean; 2  3  4  5 public class Student { 6  7    private int id; 8  9    private String name;10 11    private String gender;12 13    private int age;14 15 16 17    public int getId() {18 19      return id;20 21    }22 23    public void setId(int id) {24 25      this.id = id;26 27    }28 29    public String getName() {30 31      return name;32 33    }34 35    public void setName(String name) {36 37      this.name = name;38 39    }40 41    public String getGender() {42 43      return gender;44 45    }46 47    public void setGender(String gender) {48 49      this.gender = gender;50 51    }52 53    public int getAge() {54 55      return age;56 57    }58 59    public void setAge(int age) {60 61      this.age = age;62 63    }64 65   66 67    public Student() {68 69      super();70 71    }72 73    public Student(int id, String name, String gender, int age) {74 75      super();76 77      this.id = id;78 79      this.name = name;80 81      this.gender = gender;82 83      this.age = age;84 85    }86 87    @Override88 89    public String toString() {90 91      return "Student [id=" + id + ", name=" + name + ", gender=" + gender92 93            + ", age=" + age + "]";94 95    }96 97 }

第三步,定义数据库操作类:

 1 public class StudentDao { 2  3    private SQLiteOpenHelper helper; 4  5    private Context context; 6  7    public StudentDao(Context context){ 8  9      this.context = context;10 11    }12 13    public void insert(Student stu){14 15      helper = new MySqliteHelper(context,"students.db", null, 1);16 17      Log.i("MYSQLITEHELPER","before get db");18 19      SQLiteDatabase db = helper.getWritableDatabase();20 21      Log.i("MYSQLITEHELPER","after get db");22 23      db.execSQL("insert into t_student(name, gender, age) values(?,?,?)" , new Object[]{stu.getName(),stu.getGender(),stu.getAge()});24 25       db.close();26 27    }28 29 }

第四步,定义测试类,测试StudentDao的insert()方法:

 1 public class TestDao extends AndroidTestCase { 2  3    public void testInsert(){ 4  5      StudentDao dao = new StudentDao(getContext()); 6  7      dao.insert(new Student(0,"zhangsan", "male", 23)); 8  9    }10 11 }

运行该测试方法,运行结果如下:

 

注意到,定义SQLiteOpenHelper对象,并不会创建数据库,只有调用getWritableDatabase()或者getReadableDatabase()才会调用onCreate()方法,onCreate()内部执行了execSQL()方法,但是并没有调用onOpen()方法。onCreate()方法执行完成后,才接着调用了onOpen()方法。

 

从File Explorer中可以看出,students.db存放在/data/data/应用包名/databases/下。

再次运行,由于数据库已经存在,onCreate()方法就没再被调用。

可以通过sqlite3命令来查看数据库内容:

 

sqlite的简单使用说明:

adb shell挂载虚拟机控制台

cd /data/data/cn.csc.sqlite/databases进入数据库文件所在目录

sqlite3 数据库文件名: 管理数据库文件名所指定的数据库,如sqlite3  students.db,然后光标变为sqlite>,表示进入sqlite操作模式。

.tables 查看数据库中所有的表

可以直接输入sql语句并执行

.exit 退出sqlite操作模式

.schema 查看查看库中所有表的DDL语句

.mode list|column|insert|line|tabs|tcl|csv 改变输出格式

 

若觉得命令行用着不习惯,可以从File Explorer中把数据库文件导出到电脑中,然后使用图形化工具,如sqlite expert来查看管理数据库。

下载地址:http://pan.baidu.com/s/1jG8G7QY

StudentDao中添加getAllStudents()方法:

 1 public List<Student> getAllStudents(){ 2  3      List<Student> list = new ArrayList<Student>(); 4  5      helper = new MySqliteHelper(context,"students.db", null, 1); 6  7      SQLiteDatabase db = helper.getWritableDatabase(); 8  9      Cursor cursor = db.rawQuery("select id,name,gender,age from t_student", null);10 11      if(cursor == null){12 13         return null;14 15       }16 17      while(cursor.moveToNext()){18 19         Student stu = new Student(cursor.getInt(0),cursor.getString(1),cursor.getString(2),cursor.getInt(3));20 21         Log.i("MYSQLITEHELPER",stu.toString());22 23          list.add(stu);24 25       }26 27      28 29      return list;30 31 }

测试,输出:

 

上面用的都是直接写完整的SQL语句,下面添加几个方法,调用SQLiteDatabase封装的几个简单操作的API:

update()方法的使用

StudentDao类添加:修改指定id的学生的姓名:

 1 public void updateNameById(int id, String newName){ 2  3      helper = new MySqliteHelper(context,"students.db", null, 1); 4  5      SQLiteDatabase db = helper.getWritableDatabase(); 6  7      ContentValues values = new ContentValues(); 8  9      values.put("name", newName);10 11      db.update("t_student", values, "id=?", new String[]{id+""});12 13 }

测试代码:

1 public void testUpdate(){2 3      StudentDao dao = new StudentDao(getContext());4 5      dao.updateNameById(1, "dqrcsc");6 7 }

运行前后:

 

delete()方法的使用

StudentDao类添加:删除指定id的学生

1 public void deleteById(int id){2 3      helper = new MySqliteHelper(context,"students.db", null, 1);4 5      SQLiteDatabase db = helper.getWritableDatabase();6 7      db.delete("t_student", "id=?", new String[]{id+""});8 9 }

 

测试代码:

1 public void testDelete(){2 3      StudentDao dao = new StudentDao(getContext());4 5      dao.deleteById(2);6 7 }

 运行前后:

 

insert()方法的使用

StudentDao类中添加如下方法:

 1 public void addStudent(Student stu){ 2  3      helper = new MySqliteHelper(context,"students.db", null, 1); 4  5      SQLiteDatabase db = helper.getWritableDatabase(); 6  7      ContentValues values = new ContentValues(); 8  9      values.put("name", stu.getName());10 11      values.put("gender", stu.getGender());12 13      values.put("age", stu.getAge());14 15      db.insert("t_student", null, values);16 17 }

测试代码:

1 public void testAddStudent(){2 3      StudentDao dao = new StudentDao(getContext());4 5      dao.addStudent(new Student(0,"csc","male",24));6 7 }

运行前后:

 

query()方法的使用

 1 public Student getStudentById(int id){ 2  3      Student stu = null; 4  5      helper = new MySqliteHelper(context,"students.db", null, 1); 6  7      SQLiteDatabase db = helper.getWritableDatabase(); 8  9      Cursor cursor = db.query("t_student", new String[]{"id","name","gender","age"}, "id=?", new String[]{id+""}, null, null, null);10 11      if(cursor == null){12 13         return null;14 15       }16 17      if(cursor.moveToFirst()){18 19         stu = new Student(cursor.getInt(0),cursor.getString(1),cursor.getString(2),cursor.getInt(3));20 21       }22 23      return stu;24 25 }

 

测试代码:

1 public void testGetStudentById(){2 3      StudentDao dao = new StudentDao(getContext());4 5      Student stu = dao.getStudentById(1);6 7      Log.i("MYSQLITEHELPER",stu.toString());8 9 }

输出:

 

 关于事务的操作

被用烂来的例子,就是银行转账问题,一个账户转出,一个账户转入,两个操作要么同时成功,要么同时失败。

这里懒得再建一张表了,就转年龄吧,其实换汤不换药,原理完全一样。

假设年龄可以在学生之间转换,我要把自己的年龄转10岁给lisi这个同学,要保证这整个操作的原子性,就需要用到事务。

在StudentDao中添加转账年龄的方法:

 1 public void transAge(){ 2  3      helper = new MySqliteHelper(context,"students.db", null, 1); 4  5      SQLiteDatabase db = helper.getWritableDatabase(); 6  7      db.execSQL("update t_student set age = age - 10 where name = ?", new String[]{"dqrcsc"}); 8  9      int i = 1/0;10 11      db.execSQL("update t_student set age = age + 10 where name = ?", new String[]{"lisi"});12 13 }

注意两条update语句之间有个1/0的操作,会导致程序异常终止,只有第一条被执行。

执行前后:

 

可以看到,我的年龄减去10岁,而lisi的年龄并没有加上10岁。

修改代码,改用事务处理:

 1 public void transAge(){ 2  3      helper = new MySqliteHelper(context,"students.db", null, 1); 4  5      SQLiteDatabase db = helper.getWritableDatabase(); 6  7       db.beginTransaction(); 8  9      try{10 11         db.execSQL("update t_student set age = age - 10 where name = ?", new String[]{"dqrcsc"});12 13         int i = 1/0;14 15         db.execSQL("update t_student set age = age + 10 where name = ?", new String[]{"lisi"});16 17          db.setTransactionSuccessful();18 19      }finally{20 21          db.endTransaction();22 23       }24 25 }

这一次,我的年龄没有减少,lisi的年龄也没有增加,保证了一致性。

 

关于更新数据库版本的简单示例

如,由于业务需要,更新了APP,新版本的APP在数据库中增加了一张教师表,现在修改onCreate()方法:

 1 public static final String CREATE_TEACHER = "create table t_teacher(id integer primary key, name varchar(20))"; 2  3 public void onCreate(SQLiteDatabase db) { 4  5      // TODO Auto-generated method stub 6  7       db.execSQL(CREATE_STUDENT); 8  9       db.execSQL(CREATE_TEACHER);10 11 }

运行,发现根本没有增加t_teacher这张表,因为数据库已存在,onCreate()方法不会被运行,这时,就需要用到onUpgrade()方法了:

 1 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 2  3      // TODO Auto-generated method stub 4  5      if(oldVersion == 1 && newVersion == 2){ 6  7          db.execSQL(CREATE_TEACHER); 8  9       }10 11 }

在StudentDao中添加addTeacher()方法:

1 public void addTeacher(){2 3      helper = new MySqliteHelper(context,"students.db", null, 2);4 5      SQLiteDatabase db = helper.getWritableDatabase();6 7      db.execSQL("insert into t_teacher(name) values(?)",new String[]{"wanger"});8 9 }

注意,这里指定的版本号为2。

测试运行结果:

 

数据库操作的学习,就简单学到这里。

 




几月份去泰国旅游最好什么时候去泰国旅游最便宜去泰国旅游跟团要多少钱去泰国旅游需要多少钱泰国旅游大概多少钱三水荷花世界春节有花展吗?2015春节荷花世界赏花攻略? 2015春节英德仙桥地下河有哪些玩的?仙桥地下河春节玩什么? 2015春节蓝田瑶族风情园有哪些好玩的?龙门蓝田瑶族风情园春节有什么活动? 2015春节台山下川岛航班安排?台山上川岛春节开门吗? 清远佛冈田野绿世界有什么花看?佛冈田野绿世界花开了吗? 佛冈田野绿世界现在有什么水果采摘?清远佛冈田野绿世界水果有什么? 佛冈田野绿世界花期表,清远佛冈田野绿世界有什么水果?田野绿世界电话 深圳欢乐谷玛雅水公园圣诞活动?深圳玛雅水公园hi歌嘉年华? 2013中秋节香港旅游纪实 国庆去香港海洋公园玩吧 港澳通行证办理指南 十一国庆去凤凰古城度假纪实 厦门自驾游,走哪条路线好? 厦门游玩住在哪里比较方便 厦门三日游,请安排一下详细的行程! 厦门游玩攻略 AQ11EM390GA7BE Datasheet AQ11EM390GA7BE Datasheet 08055A391FAT4A Datasheet 08055A391FAT4A Datasheet AQ11EM390GA7ME\500 Datasheet AQ11EM390GA7ME\500 Datasheet 深圳至庐山旅游 深圳至庐山旅游 深圳至庐山旅游 到江西旅游价格 到江西旅游价格 到江西旅游价格 江西旅游 线路 江西旅游 线路 江西旅游 线路