原文链接:http://www.orlion.ga/610/

一、事务

SQLite支持事务,看一下Android如何使用事务:比如 Book表中的数据都已经很老了,现在准备全部废弃掉替换成新数据,可以先使用delete()方法将Book表中的数据删除, 然后再使用insert()方法将新的数据添加到表中。我们要保证的是,删除旧数据和添加新数据的操作必须一起完成,否则就还要继续保留原来的旧数据。

                Button replaceData = (Button) findViewById(R.id.replace_data);
replaceData.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.beginTransaction();
db.delete("book", null, null);
try {
if (true) {
// 手动抛出异常,让事务失败
throw new Exception();
} ContentValues values = new ContentValues();
values.put("name", "book new");
values.put("author", "orlion");
values.put("pages", 200);
values.put("price", 100); db.insert("book", null, values);
db.setTransactionSuccessful(); // 事务已经执行成功
} catch (Exception e) {
e.printStackTrace();
} finally {
db.endTransaction(); // 结束事务
}
}
});

上述代码就是Android中事务的标准用法, 首先调用SQLiteDatabase的beginTransaction()方法来开启一个事务,然后在一个异常捕获的代码块中去执行具体的数据库操作,当所有的操作都完成之后,调用 setTransactionSuccessful()表示事务已经执行成功了,最后在 finally代码块中调用 endTransaction()来结束事务。注意观察,我们在删除旧数据的操作完成后手动抛出了一个 NullPointerException,这样添加新数据的代码就执行不到了。不过由于事务的存在,中途出现异常会导致事务的失败,此时旧数据应该是删除不掉的。

二、升级数据库的最佳写法

// 这里直接复制《第一行代码原文》

Android入门(十)SQLite创建升级数据库 一文中升级数据库的方式是非常粗暴的,为了保证数据库中的表是最新的,我们只是简单地在 onUpgrade()方法中删除掉了当前所有的表,然后强制重新执行了一遍 onCreate()方法。这种方式在产品的开发阶段确实可以用,但是当产品真正上线了之后就绝对不行了。

每一个数据库版本都会对应一个版本号, 当指定的数据库版本号大于当前数据库版本号的时候, 就会进入到 onUpgrade()

方法中去执行更新操作。这里需要为每一个版本号赋予它各自改变的内容,然后在onUpgrade()方法中对当前数据库的版本号进行判断,再执行相应的改变就可以了。

接着就让我们来模拟一个数据库升级的案例,还是由 MyDatabaseHelper类来对数据库进行管理。第一版的程序要求非常简单,只需要创建一张 Book表,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)";
    public MyDatabaseHelper(Context context, String name, CursorFactory
        factory, int version) {
        super(context, name, factory, version);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}

不过,几星期之后又有了新需求,这次需要向数据库中再添加一张 Category表。于是,修改 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)";
    public static final String CREATE_CATEGORY = "create table Category ("
        + "id integer primary key autoincrement, "
        + "category_name text, "
        + "category_code integer)";
    public MyDatabaseHelper(Context context, String name,
        CursorFactory factory, int version) {
        super(context, name, factory, version);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        db.execSQL(CREATE_CATEGORY);
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        switch (oldVersion) {
        case 1:
            db.execSQL(CREATE_CATEGORY);
            default:
        }
    }
}

可以看到,在 onCreate()方法里我们新增了一条建表语句,然后又在 onUpgrade()方法中添加了一个 switch判断,如果用户当前数据库的版本号是 1,就只会创建一张 Category表。这样当用户是直接安装的第二版的程序时,就会将两张表一起创建。而当用户是使用第二版的程序覆盖安装第一版的程序时,就会进入到升级数据库的操作中,此时由于 Book表已经存在了,因此只需要创建一张 Category表即可。但是没过多久,新的需求又来了,这次要给 Book表和 Category表之间建立关联,需要在 Book表中添加一个 category_id的字段。 再次修改 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_id integer)";
    public static final String CREATE_CATEGORY = "create table Category ("
        + "id integer primary key autoincrement, "
        + "category_name text, "
        + "category_code integer)";
    public MyDatabaseHelper(Context context, String name,
        CursorFactory factory, int version) {
        super(context, name, factory, version);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        db.execSQL(CREATE_CATEGORY);
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        switch (oldVersion) {
        case 1:
            db.execSQL(CREATE_CATEGORY);
        case 2:
            db.execSQL("alter table Book add column category_id integer");
        default:
        }
    }
}

可以看到,首先我们在 Book表的建表语句中添加了一个 category_id列,这样当用户直接安装第三版的程序时,这个新增的列就已经自动添加成功了。然而,如果用户之前已经安装了某一版本的程序,现在需要覆盖安装,就会进入到升级数据库的操作中。在 onUpgrade()方法里,我们添加了一个新的 case,如果当前数据库的版本号是 2,就会执行 alter命令来为Book表新增一个 category_id列。

这里请注意一个非常重要的细节,switch中每一个 case的最后都是没有使用 break的,为什么要这么做呢?这是为了保证在跨版本升级的时候, 每一次的数据库修改都能被全部执行到。比如用户当前是从第二版程序升级到第三版程序的,那么 case 2中的逻辑就会执行。而如果用户是直接从第一版程序升级到第三版程序的,那么 case 1和 case 2中的逻辑都会执行。使用这种方式来维护数据库的升级,不管版本怎样更新,都可以保证数据库的表结构是最新的,而且表中的数据也完全不会丢失了。

Android入门(十二)SQLite事务、升级数据库的更多相关文章

  1. android 入门 006(sqlite增删改查)

    android 入门 006(sqlite增删改查) package cn.rfvip.feb_14_2_sqlite; import android.content.Context; import ...

  2. Android Studio(十二):打包多个发布渠道的apk文件

    Android Studio相关博客: Android Studio(一):介绍.安装.配置 Android Studio(二):快捷键设置.插件安装 Android Studio(三):设置Andr ...

  3. Android入门(十)SQLite创建升级数据库

    原文链接:http://www.orlion.ga/603/ 一.创建数据库 Android为了让我们能够更加方便地管理数据库,专门提供了一个 SQLiteOpenHelper帮助类, 借助这个类就可 ...

  4. JavaWeb学习总结(十二)--事务

    一.事务的介绍 1.1 什么是事务 银行转账!张三转10000块到李四的账户,这其实需要两条SQL语句: 给张三的账户减去10000元: 给李四的账户加上10000元. 如果在第一条SQL语句执行成功 ...

  5. Android入门(十六)调用摄像头相册

    原文链接:http://www.orlion.ga/665/ 一.调用摄像头 创建一个项目ChoosePicDemo,修改activity_main.xml: <LinearLayout xml ...

  6. Android入门(十四)内容提供器-实现跨程序共享实例

    原文链接:http://www.orlion.ga/661/ 打开SQLite博文中创建的 DatabaseDemo项目,首先将 MyDatabaseHelper中使用 Toast弹出创建数据库成功的 ...

  7. android学习十二(android的Content Provider(内容提供器)的使用)

    文件存储和SharePreference存储以及数据存储一般为了安全,最好用于当前应用程序中訪问和存储数据.内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能 ...

  8. Android入门(二):Android的系统架构

    android的系统架构和其操作系统一样,采用了分层的架构.从架构图看,android分为四个层,从高层到低层分别是应用程序层.应用程序框架层.系统运行库层和linux核心层.   从技术方面看,An ...

  9. Java开发学习(二十二)----Spring事务属性、事务传播行为

    一.事务配置 上面这些属性都可以在@Transactional注解的参数上进行设置. readOnly:true只读事务,false读写事务,增删改要设为false,查询设为true. timeout ...

随机推荐

  1. link2001错误无法解析外部符号metaObject

    http://blog.sina.com.cn/s/blog_791f544a0100r01b.html     1>MainWindowBottomWidget.obj : error LNK ...

  2. Request三种获取数据的方式

    今天在做ajax请求后台代码时,发现ajax的方法都对,但就是请求不了后台代码,后来在同事帮助下才发现前台定义了两个相同参数导致请求出错. 下面记录一下request三种获取数据的方式: 1. Req ...

  3. tar.xz文件解压

    原文:http://blog.csdn.net/rheostat/article/details/7614451 感谢CSDN的<帝都码农> ======================= ...

  4. java-IO

    框架图 IO(Input Output)流IO流用来处理设备之间的数据传输,Java对数据的操作是通过流的方式,用于操作流的对象都在IO包中. 流按操作数据分为两种:字节流与字符流 .流按流向分为:输 ...

  5. java基础(环境设置,基础语法,函数数组)

    框架图 环境搭建 课程中常见dos命令: dir : 列出当前目录下的文件以及文件夹 md : 创建目录 rd : 删除目录 cd : 进入指定目录 cd.. : 退回到上一级目录 cd/ : 退回到 ...

  6. .Net下的 ORM框架介紹

    在.NET平台下,关于数据持久层框架非常多,本文主要对如下几种做简要的介绍并推荐一些学习的资源: 1.NHibernate 2.NBear 3.Castle ActiveRecord 4.iBATIS ...

  7. iOS开发-NSOperation与GCD区别

    Mac OS X 10.6及iOS4.0之后导入了可以使全体线程更高效运行,并且使并行处理应用更易开发的架构,GCD(Grand Central  Dispatch),同时引入的还有Run Loop, ...

  8. 如何向MyEclipse项目的文件夹中添加JSP页面?

    1.鼠标选中该文件夹:2.鼠标右键单击该文件夹,选择“new->file”菜单项,创建一个空白文件:3.将JSP页面的所有源代码全部复制到该文件4.单击工具栏的“保存”按钮

  9. DataTables 控件使用和心得 (1) - 入门

    什么是DataTables DataTables是一个基于HTML/CSS/JavaScript的前端列表组件. 基于JQuery 开源并且免费(除特殊支持服务) 主要特色: 高性能,响应式,功能完整 ...

  10. JavaScript思维导图—变量

    JavaScript思维导图-来自@王子墨http://julying.com/blog/the-features-of-javascript-language-summary-maps/