Android :数据存储方案学习笔记之 SQLite数据库存储

Posted JMW1407

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android :数据存储方案学习笔记之 SQLite数据库存储相关的知识,希望对你有一定的参考价值。

SQLite数据库存储

特点:

  • 适用于存储大量复杂的数据

1、创建数据库

android专门提供了一个 SQLiteOpenHelper帮助类对数据库进行创建和升级

  • SQLiteOpenHelper需要创建一个自己的帮助类去继承它并且重写它的两个抽象方法,即 onCreate()
    onUpgrade()
  • SQLiteOpenHelper 中有两个重要的实例方法:getReadableDatabase()getWritableDatabase()

创建一个名为 BookStore.db 的数据库

  • 在这个数据库中新建一张 book表,表中有 id(主键)、作者、价格、页数和书名等列

新建 MyDatabaseHelper类继承自 SQLiteOpenHelper,代码如下:

public class MyDatabaseHelper extends SQLiteOpenHelper {
 
    // Book表的建表语句
    private static final String CREATE_BOOK = "create table book("
            +"id integer primary key autoincrement,"
            +"author text,"
            +"price real,"
            +"pages integer,"
            +"name text)";
 
    private Context mContext;
 
    /**
     * 构造方法
     * @param context
     * @param name 数据库名
     * @param factory 允许我们在查询数据的时候返回一个自定义的 Cursor,一般都是传入 null
     * @param version 当前数据库的版本号,可用于对数据库进行升级操作
     */
    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }
 
    /**
     * 创建数据库
     * @param db
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        // 执行建表语句
        db.execSQL(CREATE_BOOK);
        ToastUtils.showShort("创建成功");
    }
 
    /**
     * 升级数据库
     * @param db
     * @param oldVersion
     * @param newVersion
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 
    }
}

修改布局 activity_sqlite.xml 中代码,添加个按钮来创建数据库:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="15dp"
    android:orientation="vertical" >
 
    <Button
        android:id="@+id/btn_create_database"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="创建数据库"/>
 
</LinearLayout>

修改 activity 中的代码:

public class SQLiteActivity extends AppCompatActivity {
 
    private MyDatabaseHelper dbHelper;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sqlite);
 
        // 构建MyDatabaseHelper对象,指定数据库名为"BookStore.db、版本号为1
        dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);
 
        Button btn_create_database = (Button) findViewById(R.id.btn_create_database);
        btn_create_database.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 创建或打开一个现有的数据库(已存在则打开,否则创建一个新的)
                dbHelper.getWritableDatabase();
            }
        });
    }
}


第一次点击按钮时,会检测到当前程序中并没有 BookStore.db 这个数据库,于是会创建该数据库并调用 MyDatabaseHelper中的 onCreate()方法,创建 book 表,

然后弹出一个 Toast 提示创建成功。再次点击按钮时,会发现此时已存在 BookStore.db 数据库了,因此不会再创建一次。

2、升级数据库

MyDatabaseHelper 中的onUpgrade() 方法是用于对数据库进行升级

项目中已经有一张 book 表用于存放书的各种详细数据,若我们想再添加一张 category 表用于记录书籍的分类该怎么做?

修改 MyDatabaseHelper 中的代码,如下:

public class MyDatabaseHelper extends SQLiteOpenHelper {
 
    // Book表的建表语句
    private static final String CREATE_BOOK = "create table book("
            +"id integer primary key autoincrement,"
            +"author text,"
            +"price real,"
            +"pages integer,"
            +"name text)";
 
    // Category表的建表语句
    private static final String CREATE_CATEGORY = "create table category("
            +"id integer primary key autoincrement,"
            +"category_name text,"
            +"category_code integer)";
    
    private Context mContext;
 
    /**
     * 构造方法
     * @param context
     * @param name 数据库名
     * @param factory 允许我们在查询数据的时候返回一个自定义的 Cursor,一般都是传入 null
     * @param version 当前数据库的版本号,可用于对数据库进行升级操作
     */
    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }
 
    /**
     * 创建数据库
     * @param db
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        // 执行建表语句
        db.execSQL(CREATE_BOOK);
        db.execSQL(CREATE_CATEGORY);
        ToastUtils.showShort("创建成功");
    }
 
    /**
     * 升级数据库
     * @param db
     * @param oldVersion
     * @param newVersion
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 若发现数据库中已存在 book 表或 category 表,将这两张表删除掉
        db.execSQL("drop table if exists book");
        db.execSQL("drop table if exists category");
        // 重新创建表
        onCreate(db);
    }
}

修改 activity 中的代码,在 SQLiteOpenHelper 的构造方法里接收的第四个参数传入一个比之前传入的版本号 1 大的数

就可以让 onUpgrade()方法得到执行了。如下

public class SQLiteActivity extends AppCompatActivity {
 
    private MyDatabaseHelper dbHelper;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sqlite);
 
        // 构建MyDatabaseHelper对象,指定数据库名为"BookStore.db、版本号为1
        //dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);
        // 将数据库版本号指定为2
        dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
 
        Button btn_create_database = (Button) findViewById(R.id.btn_create_database);
        btn_create_database.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 创建或打开一个现有的数据库(已存在则打开,否则创建一个新的)
                dbHelper.getWritableDatabase();
            }
        });
    }
}

3、增删查改

CRUD:添加(Create),查询(Retrieve),更新(Update),删除(Delete)

SQLiteOpenHelper 中的 getReadableDatabase() 或 getWritableDatabase() 方法都会返回一个 SQLiteDatabase对象,借助这个对象可以对数据进行 CRUD 操作

修改下布局 activity_sqlite.xml 的代码如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="15dp"
    android:orientation="vertical" >
 
    <Button
        android:id="@+id/btn_create_database"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="创建数据库"/>
 
    <Button
        android:id="@+id/btn_add_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="添加数据"/>
 
    <Button
        android:id="@+id/btn_update_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="更新数据"/>
 
    <Button
        android:id="@+id/btn_delete_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="删除数据"/>
 
    <Button
        android:id="@+id/btn_query_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="查询数据"/>
 
</LinearLayout>

3.1、添加数据

SQLiteDatabase 中提供了一个 insert() 方法用于添加数据

它接收三个参数,

  • 第一个参数是表名
  • 第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值 NULL,一般直接传入 null 即可
  • 第三个参数是一个 ContentValues 对象,它提供了一系列的 put() 方法重载

用于向 ContentValues 中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可

修改 activity 中的代码,如下:

public class SQLiteActivity extends AppCompatActivity {
 
    private MyDatabaseHelper dbHelper;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sqlite);
 
        . . .
 
        // 添加数据
        Button btn_add_data = (Button) findViewById(R.id.btn_add_data);
        btn_add_data.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                // 开始组装第一条数据
                values.put("name","The Da Vinci Code");
                values.put("author","Dan Brown");
                values.put("pages",454);
                values.put("price",16.96);
                db.insert("book",null,values); //插入第一条数据
                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); //插入第二条数据
            }
        });
    }
}

3.2、更新数据

SQLiteDatabase 中提供了一个 update() 方法

它接收四个参数,

  • 第一个参数和 insert()方法一样,是表名
  • 第二个参数是 ContentValues 对象,要把更新数据在这里组装进去
  • 第三、第四个参数用于去约束更新某一行或某几行中的数据,不指定的话默认就是更新所有行

修改 activity 中的代码,如下:

public class SQLiteActivity extends AppCompatActivity {
 
    private MyDatabaseHelper dbHelper;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sqlite);
 
        . . . 
 
        // 更新数据
        Button btn_update_data = (Button) findViewById(R.id.btn_update_data);
        btn_update_data.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                // 把名字为 The Da Vinci Code 的这本书的更新成666.66
                values.put("price",666.66);
                db.update("book",values, "name = ?", new String[]{"The Da Vinci Code"});
            }
        });
    }
}

3.3、删除数据

SQLiteDatabase 中提供了一个 delete()方法用于删除数据

这个方法接收三个参数,

  • 第一 个参数仍然是表名
  • 第二、第三个参数又是用于去约束删除某一 行或某几行的数据,不指定的话默认就是删除所有行

修改 activity 中的代码,如下:

public class SQLiteActivity extends AppCompatActivity {
 
    private MyDatabaseHelper dbHelper;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sqlite);
 
        . . . 
 
        // 删除数据
        Button btn_delete_data = (Button) findViewById(R.id.btn_delete_data);
        btn_delete_data.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                // 删除页数超过500页的书
                db.delete("book", "pages > ?", new String[]{"500"});
            }
        });
    }
}

3.4、查询数据

SQLiteDatabase 中提供了一个 query()方法用于查询数据

这个方法的参数非常复杂,最短的一个方法重载也需要传入七个参数

  • 第一个参数是表名
  • 第二个参数用于指定去查询哪几列,如果不指定则默认查询所有列
  • 第三、第四个参数用于去约束查询某一行或某几行的数据,不指定则默认是查询所有行的数据
  • 第五个参数用于指定需要去 group by 的列,不指定则表示不对查询结果进行 group by 操作
  • 第六个参数用于对 group by 之后的数据进行进一步的过滤,不指定则表示不进行过滤
  • 第七个参数用于指定查询结果的排序方式,不指定则表示使用默认的排序方式

调用 query() 方法后会返回一个 Cursor 对象,查询到的所有数据都将从这个对象中取出

修改 activity 中的代码,如下:

public class SQLiteActivity extends AppCompatActivity {
 
    private MyDatabaseHelper dbHelper;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sqlite);
 
        . . . 
 
        // 查询数据
        Button btn_query_data = (Button) findViewById(R.id.btn_query_data);
        btn_query_data.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                // 查询 book 表中所有数据
                Cursor cursor = db.query("book", null,null,null,null,null,null,null);
                if (cursor.moveToFirst()){
                    do {
                        // 遍历 Cursor 对象,取出数据并打印
                        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("SQLiteActivity_query", "book name is: " + name);
                        Log.d("SQLiteActivity_query", "book author is: " + author);
                        Log.d("SQLiteActivity_query", "book pages are: " + pages);
                        Log.d("SQLiteActivity_query", "book price is: " + price);
                    }while (cursor.moveToNext());
                }
                cursor.close();
            }
        });
    }
}

4、使用 SQL 操作数据库

添加数据:

db.execSQL("insert into book (name, author, pages, price) values(?, ?, ?, ?)", new String[] { "The Da Vinci Code", "Dan Brown", "454", "16.96" }); 

db.execSQL("insert into book (name, author, pages, price) values(?, ?, ?, ?)",  new String[] { "The Lost Symbol", "Dan Brown", "510", "19.95" });

更新数据:

db.execSQL("update Book set price = ? where name = ?", new String[] { "666.66", "The Da Vinci Code" });

删除数据:

db.execSQL("delete from Book where pages > ?", new String[] { "500" });

查询数据:

db.rawQuery("select * from Book", null);

5、使用事务

前面我们已经知道,SQLite 数据库是支持事务的,事务的特性可以保证让某一系列的操作要么全部完成,要么一个都不会完成。那么在什么情况下才需要使用事务呢?想象以下场景,比如你正在进行一次转账操作,银行会将转账金额先从你的账户中扣除,然后再向收款方的账户中添加等量的金额。看上去好像没什么问题吧?可是,如果当你账户中的金额刚刚被扣除,这时由于一些异常导致对方收款失败,这一部分钱就凭空消息了!当然银行肯定已经充分考虑到了这种情况,它会保证扣钱和收款的操作要么一起成功,要么都不会成功,而使用的技术当然是事务了。

接下来我们看一看如何在 Android 中使用事务吧,仍然是在 DatabaseTest 项目的基础上进行修改。比如 Book 表中的数据都已经很老了,现在准备全部废弃替换成新数据,可以先使用 delete() 方法将 Book 表中的数据删除,然后再使用 insert() 方法将新的数据添加到表中。我们要保证的是,删除旧数据和添加新数据的操作必须一起完成,否则就还要继续保留原来的旧数据。修改 activity_main.xml 中的代码,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
 
    ......
 
   <Button 
        android:id="@+id/replace_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
		android:text="Replace data"        
        />
 
</LinearLayout>


可以看到,这里又添加了一个按钮,用于进行数据替换操作。然后修改 MainActivity 中的代码,如下所示:

public class MainActivity extends Activity {
 
	private MyDatabaseHelper dbHelper;
 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
		......
		Button replaceData = (Button) findViewById(R.id.replace_data);
		replaceData.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				SQLiteDatabase db = dbHelper.getWritableDatabase();
				db.beginTransaction(); //开启事务
				try {
					db.delete("Book", null, null);
					if (true) {
                                            // 在这里手动抛出一个异常,让事务失败
                                           throw new NullPointerException();
					}
					ContentValues values = new ContentValues();
					values.put以上是关于Android :数据存储方案学习笔记之 SQLite数据库存储的主要内容,如果未能解决你的问题,请参考以下文章

Android :数据存储方案学习笔记之 文件存储(openFileOutputopenFileInput)

NodeJS学习笔记之MongoDB模块

Android 数据存储 - 文件与 SQLite

sqli-labs学习笔记

Android :安卓学习笔记之 通过Intent传递类对象(实现Serializable和Parcelable接口)

Android :安卓学习笔记之事件内存泄露 的简单理解