Android笔记之存储(SQLite数据库)

SQLite数据库存储:
需要存储大量复杂的关系型数据的时候,使用此方法存储。

创建数据库:
借助SQLiteOpenHelper类对数据库进行创建和升级。
SQLiteOpenHelper是抽象类,意味着要使用它必须创建一个子类去继承它,而且要在子类中重写SQLiteOpenHelper类的两个抽象方法,分别是onCreate()和onUpgrade()。然后分别在这两个方法中实现创建,升级数据库的逻辑。

SQLiteOpenHelper类中还有两个非常重要的实例方法,getReadableDatabase()和getWritableDatabase()。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库)。并返回一个可对数据库进行读写操作的对象。不同的是,当数据库不可写入时(如磁盘控件已满)getReadableDatabase()方法返回的对象将以只读的方式打开数据库,而getWritableDatabase()方法则出现异常。

SQLiteOpenHelper中有两个构造方法可供重写,一般使用参数少一点的构造方法即可。该构造方法中接收四个参数,第一个是Context,第二个是数据库名,第三个参数允许在查询数据的时候返回一个自定义的Cursor,一般都是传入null。第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作。

构建出SQLiteOpenHelper实例后,再调用它的getReadableDatabase()或getWritableDatabase()方法就能创建数据库。此时,重写的onCreate()方法会得到执行,所以通常会在这里去处理一些创建表的逻辑。

假设我们需要创建一个名为BookStore.db的数据库。然后在这个数据库中新建一张Book表,表中有id(主键),作者,价格,页数和书名等列。

创建数据库表还是需要用建表语句,SQLite中的建表语句如下:

create table Book(
	id integer primary Key autoincrement,
	author text,
	price real,
	pages integer,
	name text)
以上,integer表示整形,real表示浮点型,text表示文本类型,blob表示二进制类型(上面没有)。同时,还使用了primary Key将id列设为主键,并用autoincrement关键字,表示id列是自增长的。

然后需要在代码中去执行这条SQL语句,才能完成创建表的操作。新建一个子类继承自SQLiteOpenHelper,示例代码如下:
//继承自SQLiteOpenHelper。
public class MyDatabaseHelper extends SQLiteOpenHelper {

    //将建表语句定义成字符串常量,此时CREATE_BOOK就代表建表语句。注意建表语句在android代码中的格式。
    public static final String CREATE_BOOK="create table book("
            + "id integer primary Key autoincrement,"
            +"author text,"
            +"price real,"
            +"pages integer,"
            +"name text)";
   
    private Context mContext;
    //子类构造函数,接收的四个对象就是上面讲过的context对象,数据库名,自定义cursor,版本号。
    public MyDatabaseHelper(Context context,String name,SQLiteDatabase.CursorFactory factory,int version){
	//重写父类构造函数。
        super(context,name,factory,version);
	//将接收的context对象的值赋给mContext对象。
        mContext=context;
    }
    //重写onCreate方法。
    @Override
    public void onCreate(SQLiteDatabase db){
	//调用SQLiteDatabase对象的execSQL方法执行建表语句。这样就能保证数据库创建完成的同时创建BOOK表。
        db.execSQL(CREATE_BOOK);
	Toast.makeText(mContext,"创建成功",Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion){
       
    }
}
然后在布局文件中创建一个按钮。
MainActivity中的代码:

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper databaseHelper;
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
	
	//创建数据库类对象。接收的第一个对象当然就是当前对象,数据库名为BookStore.db。自定义curso为空,版本号为1。
        databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,1);
        Button createDatabase=(Button)findViewById(R.id.button);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
		//监听器中的逻辑就是调用数据库对象的getEritableDatabase()方法创建数据库。调用此方法后,对象中的onCreate()方法才执行。当数据库已存在时,再次点击,则不会执行onCrete()方法。
                databaseHelper.getWritableDatabase();
            }
        });
	}
getReadableDatabase()和getWritableDatabase()方法不仅用于创建升级数据库,同时,他们还会返回一个SQLiteDatabase对象。也就是onCreate()方法接收的那个对象。

以上就是创建数据库的方法,在重写的两个方法中,目前还有一个onUpgrade()方法是没有写入逻辑的。onUpgrade()方法是用于对数据库进行升级。

假设我们需要在数据库中再添加一张Category表用于记录书籍的分类,这就用到了Upgrade()方法。
Category表中有id,分类名和分类代码这几个列,那么建表语句就可以写成:

create table Category(
	id integer primary Key autoincrement,
	category_name text,
	category_code integer)
将这条建表语句写入android代码中,也就是本次示例的MyDatabaseHelper中。

public class MyDatabaseHelper extends SQLiteOpenHelper {

    public static final String CREATE_BOOK="create table book("
            + "id integer primary Key autoincrement,"
            +"author text,"
            +"price real,"
            +"pages integer,"
            +"name text)";
    //同样将建Category表的建表语句定义成字符常量:CREATE_CATEGORY。
    public static final String CREATE_CATEGORY="create table category("
            +"id integer primary Key autoincrement,"
            +"category_name text,"
            +"category_code integer)";

    private Context mContext;
    public MyDatabaseHelper(Context context,String name,SQLiteDatabase.CursorFactory factory,int version){
        super(context,name,factory,version);
        mContext=context;
    }
    @Override
    public void onCreate(SQLiteDatabase db){
        db.execSQL(CREATE_BOOK);
	//在这里增加了一句创建Category表,但如果仅仅只是这样的话,是没用的,因为有了BOOK表,我们再点击按钮都是不会执行onCreate方法的。
        db.execSQL(CREATE_CATEGORY);
        Toast.makeText(mContext,"创建成功",Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion){
	//execSQL()方法中执行的是两条DROP语句,意思是如果存在BOOK和Category表就将其删除。
        db.execSQL("drop table if exists Book");
        db.execSQL("drop table if exists Category");
	//删除以后再调用onCreate()方法重新创建这两个表。
        onCreate(db);
    }
}
以上已经将Upgrade()方法中的逻辑写好了,接下来要做的就是执行此方法。
当初我们在SQLiteOpenHelper的构造函数中接收的第四个参数,也就是版本号里我们填入的是1,现在只要将其传入一个比1大的数就可以执行Upgrade()方法了。

MainActivity中的代码:
public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper databaseHelper;
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

	//这次只改动了版本号,表示我们对数据库进行升级。重新运行程序,重新点击此按钮,Upgarde()方法就会得到执行。
        databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,2);
        Button createDatabase=(Button)findViewById(R.id.button);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                databaseHelper.getWritableDatabase();
            }
        });
}
以上都只是创建和升级数据库的操作代码。

向数据库的表中添加数据:
SQLiteDatabase中提供了一个insert()方法,这个方法专门用于添加数据。它接收三个参数,第一个是表名,第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值null,一般用不到,直接传入null即可。第三个参数是ContextValues对象,它提供了一系列的put方法重载,用于向ContextValues中添加数据。

再次在布局文件中添加一个按钮。
修改MainActivity中的代码,如下所示:

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper databaseHelper;
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,2);
        Button createDatabase=(Button)findViewById(R.id.button);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                databaseHelper.getWritableDatabase();
            }
        });

	//第二个按钮的实例与监听器。
        Button addData=(Button)findViewById(R.id.button1);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
		//之前说过,创建数据库的方法会返回一个SQLiteDatabase对象,利用这个方法创建一个SQLiteDatabase对象,命名为db。
                SQLiteDatabase db=databaseHelper.getWritableDatabase();
		//创建一个ContextValues对象。
                ContentValues values=new ContentValues();
		//我们用ContextValues对象的put方法重载向values对象添加数据。
		//这四个put方法重载接收的第一个参数都是键名,后面是新增的值。和前面建表时的键名一样,只少了一个id的键,因为我们前面的建表语句中已经将id列设置为自增长了。
                values.put("name","The Da Vinci Code");
                values.put("author","Dan Brown");
                values.put("pages",454);
                values.put("price",16.96);
		//调用SQLiteDatabase对象的insert()方法添加数据。
                db.insert("Book",null,values);
		//这里我们要添加两次数据,为了防止数据叠加出现异常,第二次添加之前,都要执行一下clear()方法清除第一次的数据。
                values.clear();
		
		//第二次添加数据。
                values.put("name","The Lost Symbol");
                values.put("author","Dan Brown");
                values.put("pages",510);
                values.put("price",19.95);
                db.insert("Book", null, values);
            }
        });
	//所以,当点击第二个按钮的时候,监听器内的逻辑就会执行,就会自动向BOOK表中的各列添加两次数据。
}
以上就是向数据库表中添加数据。

向数据库的表中更新数据:
SQLiteDatabase中提供了update()方法用于对数据进行更新。此方法接收四个参数,第一个同样是表名,第二个是ContextValues对象。第三第四个参数用于约束更新某一行或某几行中的数据,不指定的话默认就是更新所有行。

再次在布局文件中添加一个按钮。
MainActivity中的代码:

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper databaseHelper;
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,2);
	
	.....

        Button updateData=(Button)findViewById(R.id.button2);
        updateData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
		//同样获取SQLiteDatabase对象。
                SQLiteDatabase db=databaseHelper.getWritableDatabase();
		//创建ContextValues对象。
                ContentValues values=new ContentValues();
		//将"price"列的数据更新为10.99。之前是16.96。
                values.put("price",10.99);
		//调用update()方法。第一个参数表名,第二个ContextValues对象,第三个是SQL语句的where部分,表示更新所有name等于?的行,?是一个占位符。是通过四个参数提供的字符串数组为第三个参数中的每个占位符指定相应的内容。第四个参数中字符串数组其实就是代替了?占位符。因此代码表达的意图就是name="The Da Vinci Code"。更新"The Da Vinci Code"的price值。
                db.update("Book", values, "name=?", new String[]{"The Da Vinci Code"});
            }
        });
	//当点击以上按钮时,The Da Vinci Code的price值就会被更新。

}
以上就是向数据库表中的更新数据代码。

删除数据:
SQLiteDatabase提供了delete()方法用于删除数据。此方法接收三个参数,第一个参数依旧是表名,第二三个参数又是用于约束删除某一行或某几行的数据,不指定的话默认就是删除所有行。

再次在布局文件中添加一个按钮,用于点击删除数据。

MainActivity中的代码:

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper databaseHelper;
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,2);
       
	......

        Button deleteData=(Button)findViewById(R.id.button3);
        deleteData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
		//获取SQLiteDatabase对象。
                SQLiteDatabase db=databaseHelper.getWritableDatabase();
		//delete()方法接收的三个参数,第一个Book表名,第二第三个参数的意思是删除pages键里值超过500的书籍名,也就是刚才定义的name里所对应的书名。刚才我们的定义的书名中The Lost Symbol书名是超过500的,所以点击此按钮时,会删除此书名数据。
                db.delete("Book", "pages>?", new String[]{"500"});
            }
        });
}
查询数据:
SQLiteDatabase中提供了一个query()方法用于对数据进行查询,此方法参数非常复杂,最短的重载也需要七个参数。第一个参数还是表名,第二个参数用于指定查询哪几列,不指定默认查询所有列。第三第四个参数用于约束查询某一行或某几行的数据,不指定默认查询所有行。第五个参数用于指定需要去group by的列,不指定则表示不对查询结果进行group by操作。第六个参数用于对group by之后的数据进行进一步的过滤,不指定则表示不进行过滤。第七个参数用于指定查询结果的排列方式,不指定则使用默认的排序方式。
同时调用此方法后会返回一个Cursor对象,查询到的所有数据都将从这个对象中取出。

再次在布局文件中添加一个按钮。
MainActivity中的代码:

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper databaseHelper;
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,2);
        
	......

        Button queryData=(Button)findViewById(R.id.button4);
        queryData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
		//获取SQLiteDatabase对象。
                SQLiteDatabase db=databaseHelper.getWritableDatabase();
		//执行query()方法后会返回一个cursor对象,利用这点创建Cursor对象。同时查询Book表中的数据,不指定其他约束,就全部填入null。
                Cursor cursor=db.query("Book",null,null,null,null,null,null);
		//查询出来的cursor的初始位置是指向第一条记录的前一个位置的,cursor.moveToFirst()指向查询结果的第一个位置。通过判断cursor.moveToFirst()的值为true或false来确定查询结果是否为空。
                if (cursor.moveToFirst()){
                    do {
                        String name=cursor.getString(cursor.getColumnIndex("name"));
                        String author=cursor.getString(cursor.getColumnIndex("author"));
                        int pages=cursor.getInt(cursor.getColumnIndex("pages"));
                        double price=cursor.getDouble(cursor.getColumnIndex("price"));

                        Log.d("MainActivity","book name:"+name);
                        Log.d("MainActivity","book author:"+author);
                        Log.d("MainActivity","book pages:"+pages);
                        Log.d("MainActivity","book price:"+price);
                    }while (cursor.moveToNext());
                }
		//调用close()方法关闭Cursor。
                cursor.close();
            }
        });
以上是查询数据代码,查询数据是非常复杂的,这只是一个很简单的实例。

数据库操作一般就是增删改查,SQLiteDatabase提供的四个方法分别用于这些操作。
insert()方法用于添加数据,update()方法用于更新数据。delete()方法用于删除数据,query()方法用于查询数据。

使用事务:
事务的特性是保证让某一系列的操作要么全部完成,要么一个都完不成。
在上面示例的基础上增加使用事务,比如Book表中的数据很陈旧,需要全部废弃替换成新数据。可以先使用delete()方法将Book表中的数据删除,然后再使用insert()方法将新的数据添加到表中。在此要保证的是,删除和添加的操作必须一起完成,否则就还要继续保留原来的数据。

再次在布局文件中添加一个按钮。
MainActivity中的代码:

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper databaseHelper;
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,2);
        
	......

        Button replaceData=(Button)findViewById(R.id.button5);
        replaceData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
		//获取SQLiteDatabase对象。
                SQLiteDatabase db=databaseHelper.getWritableDatabase();
		//调用beginTransaction()方法来开启事务。
                db.beginTransaction();
                try {
		    //删除Book表中的所有数据。
                    db.delete("Book",null,null);

                    ContentValues values=new ContentValues();
                    values.put("name","Game of Thrones");
                    values.put("author","George Martin");
                    values.put("pages",720);
                    values.put("price",20.85);
		    //添加新数据。
                    db.insert("Book", null, values);
		    //事务执行成功。
                    db.setTransactionSuccessful();
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
		    //结束事务。
                    db.endTransaction();
                }
            }
        });
    }
}
以上就是使用事务的代码,这是很基础的示例。






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章