Android数据存储之:SQLite数据库存储
转载部分来自:http://blog.csdn.net/zuolongsnail/article/details/6529096,http://fine36.blog.163.com/blog/static/189251005201183053216297/
Android中的数据库存储是直接使用了SQLite。在Android应用中创建数据库后数据库文件是存储在/data/ data/应用包名/databases/下。
在Android中使用到SQLite会涉及到以下三个类或接口:
1.SQLiteOpenHelper
*SQLiteOpenHelper 构造方法,一般传递一个要创建的数据库名称name参数
*onCreate 创建数据库时调用(创建所有表的操作)
*onUpgrade 版本更新时调用
*getReadableDatabase 创建或打开一个只读数据库
*getWritableDatabase 创建或打开一个读写数据库
2.SQLiteDatabase
*openOrCreateDatabase 打开或者创建数据库
*insert 添加一条记录
*delete 删除一条记录
*query 查询记录
*update 更新记录
*execSQL 执行一条SQL语句
*close 关闭数据库
3.Cursor
*getCount 总记录条数
*isFirst 判断是否第一条记录
*isLast 判断是否最后一条记录
*moveToFirst 移动到第一条记录
*moveToLast 移动到最后一条记录
*move 移动到指定记录
*moveToNext 移动到下一条记录
*moveToPrevious 移动到上一条记录
*getColumnIndexOrThrow根据列名称获得列索引
*getInt 获得指定列索引的int类型值
*getString 获得指定列索引的String类型值
注:某些方法是有重载的,可以结合docs熟悉下。
android.database.sqlite.SQLiteDatabase是Android SDK中操作数据库的核心类之一。使用SQLiteDatabase可以打开数据库,也可以对数据库进行操作。然而,为了数据库升级的需要以及使用更方便,往往使用SQLiteOpenHelper的子类来完成创建、打开数据库及各种数据库的操作。
SQLiteOpenHelper是一个抽象类,在该类中有如下两个抽象方法,因此,SQLiteOpenHelper的子类必须实现这两个方法。
public abstract void onCreate(SQLiteDatabase db);
public abstract void onUpgrade(SQLiteDatabase db,int oldVersion, int newVersion);
onCreate()调用:
SQLiteOpenHelper会自动检测数据库文件是否存在。如果数据库文件存在,会打开这个数据库。如果数据库文件不存在的时候,SQLiteOpenHelper首先会创建一个数据库文件,然后打开这个数据库,最后会调用onCreate方法。因此,onCreate方法一般被用来在新创建的数据库中建立表、视图等数据库组件。也就是说,onCreate方法在数据库文件第一次被创建时调用。
onUpgrade()调用:
SQLiteOpenHelper类的构造方法:
public SQLiteOpenHelper(Context context, Stringname, CursorFactory factory, int version);
参数意义:
name参数表示数据库文件名(不包含文件路径),SQLiteOpenHelper会根据这个文件名创建数据库文件。
version表示数据库的版本号。
如果当前传递的数据库版本号比上次创建或升级的数据库版本号高。SQLiteOpenHelper就会调用onUpgrade方法。也就是说,当数据库第1次创建时会有一个初始的版本号。当需要对数据库中表、视图等组件升级时可以增大版本号。这时SQLiteOpenHelper会调用onUpgrade方法。当调用完onUpgrade方法后,系统会更新数据库的版本号。这个当前的版本号就是通过SQLiteOpenHelper类的最后一个参数version传入SQLiteOpenHelper对象的。
因此,在onUpgrade方法中一般会首先删除要升级的表、视图等组件,再重新创建它们。
(举例:如果版本1创建了表a、表b,后来版本升级后,版本2里面有表a,同时多了表c,没有了之前版本的表b,用户分为两种:
一种是第一次使用的是版本2,不是直接升级软件的用户,因为是第一次进入,发现没有数据库,所以就在SQLiteOpenHelper构造器里面创建数据库,然后自动的调用onCreate方法创建这个版本所需要的表。
一种是使用了版本1的用户,他直接升级软件,这个时候,系统识别已经创建了数据库,所以不会调用onCreate(),因为版本有改变,会调用onUpgrade方法,这个方法里面就要去删除表b的操作,因为升级版本的用户,系统不会自动的调用onCreate方法,所以可能会错过表c,所以在onUpgrade方法里面手动的调用onCreate方法去创建表(onCreate里面创表的语句一定要用create table if not exists xxx,如果不存在就创建,存在直接用。避免重复的建表))
下面贴上数据库操作的代码,完整代码下载地址:android_sqlite.rar
1.创建数据库只要自定义一个类继承SQLiteOpenHelper即可。在SQLiteOpenHelper的子类中至少需要实现三个方法:
*构造方法,调用父类SQLiteOpenHelper的构造函数。需要四个参数:上下文环境(例如一个Activity);数据库名称;一个可选的游标工厂(通常是null);一个正在使用的数据库版本。
*onCreate方法,需要一个SQLiteDatabase对象作为参数,根据需要对这个对象填充表和初始化数据。
*onUpgrade方法,需要三个参数:一个SQLiteDatabase对象,一个旧的版本号和一个新的版本号。
(为了数据库的多次使用,同时避免错误,一个工程的数据库应该独立在一个包里面,里面包含3个java文件:
一个是继承SQLiteOpenHelper的子类(负责创建数据库和各种表视图等,同时解决版本升级的问题),
一个是数据库操作的类(负责数据库的增删改查),一个专门存储数据库的常量的java类(SQL语句不小心就出个小错,所以我们写成常量,要用的时候直接调用,避免他人使用这些常量的时候出错,也便于我们统一修改。))
[java] view plain copy
- /**
- *数据库操作助手类
- *
- *@authorzuolongsnail
- */
- publicclassAndroidSQLiteOpenHelperextendsSQLiteOpenHelper{
- //数据库名称
- publicstaticfinalStringDBNAME="android.db";
- //数据库版本
- publicstaticfinalintVERSION=2;
- //建表语句,大小写不敏感
- privatestaticfinalStringCREATETABLE="createtable"
- +Person.TABLENAME
- +"(idstring,namestring,genderint,ageint)";
- publicAndroidSQLiteOpenHelper(Contextcontext){
- super(context,DBNAME,null,VERSION);
- }
- //创建表
- @Override
- publicvoidonCreate(SQLiteDatabasedb){
- db.execSQL(CREATETABLE);
- }
- //更新表
- @Override
- publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){
- this.deleteDB(db);
- this.onCreate(db);
- }
- //删除表
- privatevoiddeleteDB(SQLiteDatabasedb){
- db.execSQL("droptableifexists"+Person.TABLENAME);
- }
- }
2.对数据库表进行操作,包括添加、删除、修改和查询。(下面的代码使用的是第一种方法)
有两种方法可以对数据库表进行操作:使用execSQL方法执行SQL语句;使用insert、delete、update和query方法,把SQL语句的一部分作为参数。(下面的代码使用的是第一种方法)
注:查询数据库时执行SQL语句是使用SQLiteDatabase的rawQuery方法而不是execSQL。
[java] view plain copy
- /**
- *数据库管理类
- *
- *@authorzuolongsnail
- *
- */
- publicclassDatabaseManager{
- privateAndroidSQLiteOpenHelperdbHelper;
- publicDatabaseManager(Contextcontext){
- dbHelper=newAndroidSQLiteOpenHelper(context);
- }
- //插入记录
- publicintinsert(Personperson){
- Log.e("SQLite","----insert----");
- SQLiteDatabasedb=dbHelper.getWritableDatabase();
- db.beginTransaction();
- try{
- db.execSQL("insertinto"+Person.TABLENAME
- +"values(?,?,?,?)",newObject[]{person.id,
- person.name,person.gender,person.age});
- db.setTransactionSuccessful();
- }catch(Exceptione){
- return0;
- }finally{
- db.endTransaction();
- }
- db.close();
- return1;
- }
- //删除记录
- publicintdelete(Personperson){
- Log.e("SQLite","----delete----");
- SQLiteDatabasedb=dbHelper.getWritableDatabase();
- db.beginTransaction();
- try{
- db.execSQL("deletefrom"+Person.TABLENAME+"whereid=?",
- newObject[]{person.id});
- db.setTransactionSuccessful();
- }catch(Exceptione){
- return0;
- }finally{
- db.endTransaction();
- }
- db.close();
- return1;
- }
- //更新记录
- publicintupdate(Personperson){
- Log.e("SQLite","----update----");
- SQLiteDatabasedb=dbHelper.getWritableDatabase();
- db.beginTransaction();
- try{
- db.execSQL("update"+Person.TABLENAME
- +"setname=?,gender=?,age=?whereid=?",newObject[]{
- person.name,person.gender,person.age,person.id});
- db.setTransactionSuccessful();
- }catch(Exceptione){
- return0;
- }finally{
- db.endTransaction();
- }
- db.close();
- return1;
- }
- //查询记录
- publicArrayList<Person>query(Stringid){
- Log.e("SQLite","----query----");
- SQLiteDatabasedb=dbHelper.getReadableDatabase();
- Cursorcursor;
- Personperson;
- ArrayList<Person>list=newArrayList<Person>();
- //若fileId为null或""则查询所有记录
- if(id==null||id.equals("")){
- cursor=db.rawQuery("select*from"+Person.TABLENAME,null);
- }else{
- cursor=db.rawQuery("select*from"+Person.TABLENAME
- +"whereid=?",newString[]{id});
- }
- while(cursor.moveToNext()){
- person=newPerson();
- person.id=cursor.getString(cursor.getColumnIndex("id"));
- person.name=cursor.getString(cursor.getColumnIndex("name"));
- person.gender=cursor.getString(cursor.getColumnIndex("gender"));
- person.age=cursor.getInt(cursor.getColumnIndex("age"));
- Log.e("SQLite",person.toString());
- list.add(person);
- }
- cursor.close();
- db.close();
- if(list.size()==0){
- Log.e("SQLite","****表中无数据****");
- }
- returnlist;
- }
- }
3、对数据库需要的常量专门定义一个类管理,比如:DBConfig.java(举例说明而已,与上面的不是代码不是一个人的)
/** * 数据库的工具类 * 里面封装了很多常量,便于用数据库的时候直接访问 * @author Administrator * */public class DBConfig {/**数据库名*/final static String DB_NAME ="UserDatabase.db";/**创建表语句的头部*/static final String CREAT_TABLE_HEAD="create table if not exists ";/**创建表语句的主件自增*/static final String PRIMARY_KEY=" integer primary key autoincrement,";/**版本号*/final static int VERSION=1;/**表名称*/static final String TB_USER="user";/**字段名id*/static final String C_ID="id";/**字段名name*/static final String C_NAME="name";/**字段名tel*/static final String C_TEL="tel";}有了这个类之后,需要创建表的语句:
sql语句:create table if not exists tb_note(id integer primary key autoincrement,title verchar(30),content text ,time verchar(30))
下面为调用了DBConfig.java类的sql语句,这样可以避免书写出现的错误:
static final String CREAT_TABLE_USER = DBConfig.CREAT_TABLE_HEAD+ DBConfig.TB_USER+"(" +DBConfig.C_ID+DBConfig.PRIMARY_KEY+DBConfig.C_NAME+" verchar(30)," +DBConfig.C_TEL+" verchar(30))";
有了常量之后的数据库操作类可以这样写:
/** * 数据库的工具类 负责表的增删改查 * * @author Administrator * */public class DBOperator {SQLiteDatabase mySql;MyDBHelper helper;public DBOperator(Context context) {helper = new MyDBHelper(context);mySql = helper.getReadableDatabase();}/** * 插入数据 * @param user * @return */public long addUser(User user) {if(user!=null){return mySql.insert(DBConfig.TB_USER, null, buildValues(user));}return 0;}private ContentValues buildValues(User user){ContentValues values=new ContentValues();values.put(DBConfig.C_NAME, user.getName());values.put(DBConfig.C_TEL, user.getTel());return values;}/** * 删除数据 * @param id * @return */public int deleteUserById(int id){//mySql.delete("tb_note", "time=?", new String[]{time});return mySql.delete(DBConfig.TB_USER, DBConfig.C_ID+"="+id, null);}/** * 更新数据 * @param user * @return */public int changeUser(User user){if(user==null || user.getId()==0){//如果传进来的user是刚new之后的user那user不为null,但是id等int型默认为0return 0;}else{return mySql.update(DBConfig.TB_USER, buildValues(user), DBConfig.C_ID+"="+user.getId(), null);}}/** * 通过id查询指定数据 * @param id * @return */public User queryById(int id){//sql语句:mySql.rawQuery("select * from "+DBConfig.TB_USER+" where "+DBConfig.C_ID+"="+id, null);Cursor cursor=mySql.query(DBConfig.TB_USER, null, DBConfig.C_ID+"="+id, null, null, null, null);User user=null;if(cursor.moveToNext()){user=cursorToGetUser(cursor);}cursor.close();return user;}/** * 查询表中所有东西 * @return */public List<User> queryUserAll(){Cursor cursor=mySql.rawQuery("select * from "+DBConfig.TB_USER, null);List<User> list=new ArrayList<User>();while(cursor.moveToNext()){User user=cursorToGetUser(cursor);list.add(user);user=null;}cursor.close();return list;}private User cursorToGetUser(Cursor cursor){User user=new User();user.setId(cursor.getInt(cursor.getColumnIndex(DBConfig.C_ID)));user.setName(cursor.getString(cursor.getColumnIndex(DBConfig.C_NAME)));user.setTel(cursor.getString(cursor.getColumnIndex(DBConfig.C_TEL)));return user;}/** * 关闭数据库 */public void dbClose(){if(mySql!=null){mySql.close();}}}
SQLiteDatabase的使用(建议使用上面的SQLiteOpenHelper)
private SQLiteDatabase mySql;
<span style="font-size: 12px;"><span style="white-space: pre;"></span>/**</span>
* 创建数据库 */private void createDataBase() {if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {File file = Environment.getExternalStorageDirectory();File newFile = new File(file, "noteBook.db");mySql=SQLiteDatabase.openOrCreateDatabase(newFile, null);String sql="create table if not exists tb_note(id integer primary key autoincrement,title verchar(30),content text ,time verchar(30))";mySql.execSQL(sql);}}
删除数据:
final String time=note.getTime();mySql.delete("tb_note", "time=?", new String[]{time});
查询表中所有数据:
<span style="white-space:pre"></span>/** * 获取数据 * @return */private List<NoteBook> queryDatabase() {list=new ArrayList<NoteBook>();Cursor cursor=mySql.query("tb_note", null, null, null, null, null, null);int count=cursor.getCount();//得到行数if(count>0){while(cursor.moveToNext()){String title=cursor.getString(cursor.getColumnIndex("title"));String time=cursor.getString(cursor.getColumnIndex("time"));//取数据存入note对象中NoteBook note=new NoteBook();note.setTitle(title);note.setTime(time);//把对象存listlist.add(note);note=null;//方便回收}cursor.close();}return list;}
cursor游标的使用 :转载:http://blog.sina.com.cn/s/blog_618199e60101fskp.html
在你理解和使用 Android Cursor 的时候你必须先知道关于 Cursor 的几件事情:
Cursor 是每行的集合。使用 moveToFirst() 定位第一行。你必须知道每一列的名称。你必须知道每一列的数据类型。Cursor 是一个随机的数据源。所有的数据都是通过下标取得。
关于 Cursor 的重要方法:
·close()——关闭游标,释放资源
·copyStringToBuffer(int columnIndex, CharArrayBuffer buffer)——在缓冲区中检索请求的列的文本,将将其存储
·getColumnCount()——返回所有列的总数
·getColumnIndex(String columnName)——返回指定名称所在的列,如果不存在返回-1
·getColumnIndexOrThrow(String columnName)——从零开始返回指定列名称,如果不存在将抛出IllegalArgumentException异常。
·getColumnName(int columnIndex)——从给定的索引返回列名
·getColumnNames()——返回一个字符串数组的列名
·getCount()——返回Cursor 中的行数
·moveToFirst()——移动光标到第一行
·moveToLast()——移动光标到最后一行
·moveToNext()——移动光标到下一行
·moveToPosition(int position)——移动光标到一个绝对的位置
·moveToPrevious()——移动光标到上一行
下面来看看一小段代码:
if (cur.moveToFirst() == false){ //为空的Cursor
return;
}
访问 Cursor 的下标获得其中的数据
int nameColumnIndex = cur.getColumnIndex(People.NAME);
String name = cur.getString(nameColumnIndex);
现在让我们看看如何循环 Cursor 取出我们需要的数据
while(cur.moveToNext()) {
//光标移动成功
String email =cursor.getString(cursor.getColumnIndex(RuiXin.EMAIL));
startManagingCursor(cursor);
//查找后关闭游标
//把数据取出
}
当cur.moveToNext() 为假时将跳出循环,即 Cursor 数据循环完毕。
如果你喜欢用 for 循环而不想用While 循环可以使用Google 提供的几下方法:
·isBeforeFirst()——返回游标是否指向之前第一行的位置
·isAfterLast()——返回游标是否指向第最后一行的位置
·isClosed()——如果返回 true 即表示该游戏标己关闭
有了以上的方法,可以如此取出数据
for(cur.moveToFirst();!cur.isAfterLast();cur.moveToNext())
{
int nameColumn = cur.getColumnIndex(People.NAME);
int phoneColumn = cur.getColumnIndex(People.NUMBER);
String name = cur.getString(nameColumn);
String phoneNumber = cur.getString(phoneColumn);
}
Tip:在Android 查询数据是通过Cursor 类来实现的。当我们使用 SQLiteDatabase.query()方法时,就会得到Cursor对象, Cursor所指向的就是每一条数据。
Cursor 位于 android.database.Cursor类,可见出它的设计是基于数据库服务产生的。
另:Activity.startManagingCursor方法:
将获得的Cursor对象交与Activity管理,这样Cursor对象的生命周期便能与当前的Activity自动同步,省去了自己对Cursor的管理。
1.这个方法使用的前提是:游标结果集里有很多的数据记录。
所以,在使用之前,先对Cursor是否为null进行判断,如果Cursor != null,再使用此方法 2.如果使用这个方法,最后也要用stopManagingCursor()来把它停止掉,以免出现错误。 3.使用这个方法的目的是把获取的Cursor对象交给Activity管理,这样Cursor的生命周期便能和Activity自动同步,省去自己手动管理。手动处理cursor关闭:cursor.close();
更多相关文章
- “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
- Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
- 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
- android 常用到的 listview ,scrollview 等上拉刷新
- Android基础 : Android(安卓)ContentProvider
- Android(安卓)工程编译 Unsupported major.minor version 51.0
- [Android]使用permission保护数据
- 关于android的反射机制的用法
- Android快速实现断点续传的方法