zoukankan      html  css  js  c++  java
  • Android SQLite数据库之事务的学习

    SQLite是Android系统内置的一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,通常只需要几百K的内存就足够了。SQLite不仅支持标准的SQL语法,还遵循了数据库的ACID事务。

    模拟一个应用场景:进行一次转账操作,银行会将转账的金额先从你的账户中扣除,然后再向收款方的账户中添加等量的金额。看上去好像没有什么问题,可是当你的账户的金额刚刚被扣除,这是由于一些异常原因导致对方收款失败(比如突然断电),这一部分钱就凭空消失了,当然银行自然会考虑到这个问题,它会保证扣钱和收款的操作要么一起完成,要么都不会成功,而使用的技术就是事物了。

    Android为了让我们能够更加方便的管理数据库,专门提供了一个SQLiteOpenHelper辅助类,借助这个类我们可以很方便的对数据库进行创建和升级。由于SQLiteOpenHelper是一个抽象类,我们需要自己创一个辅助类去继承他。

    创建MyDatabaseHelper

    package com.tonycheng.databasetest;
    
    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;
    import android.widget.Toast;
    
    /**
     * Created by tonycheng on 2015/6/27.
     */
    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)";
    
        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);
            Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    
    }

    写一个简单的XML布局文件,就两个按钮,一个创数据库,一个用来测试事物操作。

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
        android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
        <Button
            android:id="@+id/create_database"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Create Database"
            />
        <Button
            android:id="@+id/replace_data"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Replace data"
            />
    
    </LinearLayout>

    最后在MainActivity中修改代码:

    第一步创建一个数据库:

    package com.tonycheng.databasetest;
    
    import android.content.ContentValues;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.support.v7.app.ActionBarActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    
    public class MainActivity extends ActionBarActivity {
        private MyDatabaseHelper dbHelper;
        private Button btn_createDatabase;
        private Button btn_raplaceData;
    
        private static final String TAG = "MainActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,1);
            btn_createDatabase = (Button) findViewById(R.id.create_database);
            btn_raplaceData = (Button) findViewById(R.id.replace_data);
            btn_createDatabase.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dbHelper.getWritableDatabase();
                }
            });
        }
    }

    onCreat()方法中构建了一个MyDatabaseHelper对象,并通过构造函数的参数将数据库名指定为BookStore.db,版本号指定为1。然后在按钮的onClick事件中调用getWritableDatabase()方法创数据库。

    向BookStore.db数据库中添加一条数据:在添加一个Add Data按钮

     btn_addData.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    SQLiteDatabase db = dbHelper.getWritableDatabase();
    //第一种方法: ContentValues values = new ContentValues(); //开始组装第一条数据 values.put("name","The Da Vinci Code "); values.put("author","Dan Brown"); values.put("pages",510); values.put("price", 19.95); db.insert("book", null, values);
    //第二种方法 //使用SQL插入数据(同理设用于其他集中操作) //两种添加数据的方法,如果你觉得上面一种方法太繁琐,就是用SQL语句来创建,他们的效果是一样的 db.execSQL("insert into book(name,author,pages,price) values(?,?,?,?)",new String[]{ "The Da Vinci Code","Dan Brown","510","19.95" }); } });

    这样数据库中就有一条数据了,我们老进行事物操作:我们从book表中删除这条数据,再添加一条新的数据:

     /**
             * 使用事物来进行数据库操作,两种操作要么都完成,要么都失败(事物)
             */
            btn_raplaceData.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    SQLiteDatabase db = dbHelper.getWritableDatabase();
                    db.beginTransaction();//开启事物
                    try {
                        db.delete("book",null,null);
                        if (true){
                            //这里手动抛出一个异常,让事物失败
                          //  throw new NullPointerException();//由于我们手动抛出了一个异常,这样添加数据的代码就无法执行了,但是由于事物的存在,此时旧数据也无法删除
                        }
                        db.execSQL("insert into book(name,author,pages,price) values(?,?,?,?)", new String[]{
                                "android ", "tonycheng", "550", "79"
                        });
                        db.setTransactionSuccessful();
                    }finally {
                        db.endTransaction();
                    }
                }
            });

    运行上面的代码,发现表中的数据没有被删除,这是由于我们启用了事务,故意手动抛出了一个异常,导致旧数据也无法删除,如果没有启用事务,book表中的旧数据时会被删除的,而由于异常,添加数据的代码就无法执行。而这样在一些场合下是会出大问题的。由此,事务的重要性就体现出来了。至此,我们事务的一个简单的模拟就完成了。

  • 相关阅读:
    LeetCode Binary Tree Inorder Traversal
    LeetCode Populating Next Right Pointers in Each Node
    LeetCode Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode Reverse Linked List II
    LeetCode Populating Next Right Pointers in Each Node II
    LeetCode Pascal's Triangle
    Palindrome Construct Binary Tree from Preorder and Inorder Traversal
    Pascal's Triangle II
    LeetCode Word Ladder
    LeetCode Binary Tree Zigzag Level Order Traversal
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/6991405.html
Copyright © 2011-2022 走看看