1. 程式人生 > >android:sqlite 資料庫的事務詳解

android:sqlite 資料庫的事務詳解

sqlite 資料庫的事務詳解,所有的解釋都在程式碼中進行了註釋

關於事務的應用主要都在MainActivity的onClickTransferAccountsSuccess和onClickTransferAccountsError方法中做的註釋,請執行體會

執行結果如下圖


1.佈局檔案activity_main.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:orientation="vertical"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/btn_success"
        android:onClick="onClickTransferAccountsSuccess"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="正確轉賬(正確的事物)" />
    <Button
        android:id="@+id/btn_error"
        android:onClick="onClickTransferAccountsError"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="錯誤轉賬(異常的事物)" />
    <ListView 
        android:id="@+id/lv_many"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        ></ListView>

</LinearLayout>

2.ListView的item佈局檔案item_money.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
    <TextView
        android:id="@+id/tv_id"
         android:layout_width="40dp"
        android:layout_height="wrap_content"
        />
    <TextView
        android:id="@+id/tv_name"
         android:layout_width="60dp"
        android:layout_height="wrap_content"/>
    
      <TextView
        android:id="@+id/tv_money"
         android:layout_width="60dp"
        android:layout_height="wrap_content"/>
      
        <TextView
        android:id="@+id/tv_phone"
         android:layout_width="100dp"
        android:layout_height="wrap_content"/>
        
          <TextView
        android:id="@+id/tv_age"
         android:layout_width="50dp"
        android:layout_height="wrap_content"/>

</LinearLayout>

3.activity的實現類MainActivity.java

package com.smartdot.transaction;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

	private static final String TAG = "MainActivity";
	private OpenHelper helper;
	private ListView lv_many;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		helper = new OpenHelper(this);
		lv_many = (ListView) findViewById(R.id.lv_many);
		setBaseAdapter();//讀取資料庫的資料,並設定lv_many列表的資料
	}
	
	/**
	 * 正確的轉賬方法
	 */
	public void onClickTransferAccountsSuccess(View v) {
		SQLiteDatabase db = helper.getWritableDatabase();
		db.beginTransaction();//開啟事務
		try {
			//馬漢缺錢要王超給他轉賬100元	
			db.execSQL("update user set money=money-100 where name=? and money>=100",new String[]{"王朝"});
			db.execSQL("update user set money=money+100 where name=? and (select money from user u where u.name=?)>=100",new String[]{"馬漢","王朝"});
			db.setTransactionSuccessful();//事務正確結束,如果此方法不執行,則所有的資料增刪改操作都會回滾
			Toast.makeText(MainActivity.this, "轉賬成功!", Toast.LENGTH_SHORT).show();
			Log.i(TAG, "轉賬成功!");
		} catch (Exception e){
			Toast.makeText(MainActivity.this, "伺服器忙,請稍後!", Toast.LENGTH_SHORT).show();
			Log.e(TAG, "伺服器忙,請稍後!");
		} finally {
			db.endTransaction();//關閉事務
			setBaseAdapter();
		}
	}
	
	
	/**
	 * 錯誤的轉賬方法
	 */
	public void onClickTransferAccountsError(View v) {
		SQLiteDatabase db = helper.getWritableDatabase();
		db.beginTransaction();//開啟事務
		try {
			//馬漢缺錢要給他王超轉賬100元	
			db.execSQL("update user set money=money-100 where name=?",new String[]{"王朝"});
			int i = 10/0;//故意設定一個異常
			db.execSQL("update user set money=money+100 where name=?",new String[]{"馬漢"});
			db.setTransactionSuccessful();//事務正確結束,如果此方法不執行,則所有的資料增刪改操作都會回滾
			Toast.makeText(MainActivity.this, "轉賬成功!", Toast.LENGTH_SHORT).show();//此處永遠不會執行
		} catch (Exception e){
			Toast.makeText(MainActivity.this, "伺服器忙,請稍後!", Toast.LENGTH_SHORT).show();
			Log.e(TAG, "伺服器忙,請稍後!");//真正企業開發,一般會報伺服器忙,請稍後。不會丟擲異常給使用者!!!
		} finally {
			db.endTransaction();//關閉事務
			setBaseAdapter();
		}
	}
	
	/**
	 * 重新設定列表的介面卡
	 */
	public void setBaseAdapter() {
		List<Map<String,String>> list = query();//轉完賬查詢記錄
		MyBaseAdapter mBaseAdapter = new MyBaseAdapter(list);//設定listView的介面卡
		lv_many.setAdapter(mBaseAdapter);
	}
	
	/**
	 * 查詢記錄
	 * @return
	 */
	public List<Map<String,String>> query() {
		SQLiteDatabase db = helper.getWritableDatabase();
		Cursor cursor = db.query("user", new String[]{"name","money","age","phone","_id"}, null, null, null, null, null);
		List<Map<String,String>> list = new ArrayList<Map<String,String>>();
		Map<String,String> map;
		while(cursor.moveToNext()) {
			map = new HashMap<String, String>();
			map.put("name", cursor.getString(0));
			map.put("money", cursor.getString(1));
			map.put("age", cursor.getInt(2) + "");
			map.put("phone", cursor.getString(3));
			map.put("id", cursor.getInt(4) + "");
			list.add(map);
		}
		return list;
	}

	
	class MyBaseAdapter extends BaseAdapter {

		public List<Map<String,String>> list ;
		public MyBaseAdapter() {
		}
		public MyBaseAdapter(List<Map<String,String>> list) {
			this.list = list;
		}
		
		@Override
		public int getCount() {
			return list == null?0:list.size();
		}

		@Override
		public Object getItem(int position) {
			// TODO Auto-generated method stub
			return list == null?null:list.get(position);
		}

		@Override
		public long getItemId(int position) {
			// TODO Auto-generated method stub
			return position;
		}

		/**
		 * 通過介面卡把數值填充到ListView中
		 */
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			ConvertViewTag tag ;//用於快取內部的find的物件
			TextView tv_id = null;
			TextView tv_name = null;
			TextView tv_age = null;
			TextView tv_phone = null;
			TextView tv_money = null;
			if(convertView == null) {
				convertView = View.inflate(MainActivity.this, R.layout.item_money,null);
				tv_id = (TextView) convertView.findViewById(R.id.tv_id);
				tv_name = (TextView) convertView.findViewById(R.id.tv_name);
				tv_money = (TextView) convertView.findViewById(R.id.tv_money);
				tv_age = (TextView) convertView.findViewById(R.id.tv_age);
				tv_phone = (TextView) convertView.findViewById(R.id.tv_phone);
				
				tag = new ConvertViewTag();
				tag.tv_id = tv_id;
				tag.tv_money = tv_money;
				tag.tv_age = tv_age;
				tag.tv_name = tv_name;
				tag.tv_phone = tv_phone;
				
				convertView.setTag(tag);//快取獲得的View物件,如果資料多的時候避免二次建立
				
			} else {
				tag = (ConvertViewTag) convertView.getTag();//獲取快取的物件
				tv_id = tag.tv_id;
				tv_name = tag.tv_name;
				tv_money = tag.tv_money;
				tv_age = tag.tv_age;
				tv_phone = tag.tv_phone;
			}
			
			Map<String, String> map = list.get(position);
			tv_id.setText(map.get("id"));
			tv_name.setText(map.get("name"));
			tv_money.setText(map.get("money"));
			tv_age.setText(map.get("age"));
			tv_phone.setText(map.get("phone"));
			
			
			return convertView;
		}
		class ConvertViewTag {
			public TextView tv_id;
			public TextView tv_name;
			public TextView tv_money;
			public TextView tv_age;
			public TextView tv_phone;
		}
	}

}

4.SQLiteOpenHelper的實現類OpenHelper.java

package com.smartdot.transaction;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

/**
 * 實現android提供的抽象類SQLiteOpenHelper,用於sqlite資料庫的操作
 * 
 * @author wangguang
 * 
 */
public class OpenHelper extends SQLiteOpenHelper {

	/**
	 * 第一次呼叫資料庫,對出具庫進行訪問。
	 * 
	 * @param context
	 */
	public OpenHelper(Context context) {
		// 資料版本version只能比之前高,不得低於之前設定的版本號
		super(context, "transaction.db", null, 1);// 系統建立資料庫
	}

	/**
	 * 當資料庫(表)發生改變時可呼叫此方法
	 * 
	 * @param Context
	 *            context 上下文
	 * @param int version 資料庫版本
	 */
	public OpenHelper(Context context, int version) {
		// 資料版本version只能比之前高,不得低於之前設定的版本號
		super(context, "smartdot.db", null, version);
	}

	/**
	 * 當資料庫第一次建立的時候建立<br>
	 * 這個表特別適合做建立表的操作
	 */
	@Override
	public void onCreate(SQLiteDatabase db) {
		String creatTable = "create table user (_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,name varchar,money varchar(20),phone varchar,age int,sex int)";
		db.execSQL(creatTable);
		db.execSQL(
				"INSERT INTO USER (NAME,money,PHONE,SEX,AGE) VALUES(?,?,?,?,?)",
				new Object[] { "王朝", "100000", "18701545309", 1, 30 });// 新增測試資料
		db.execSQL(
				"INSERT INTO USER (NAME,money,PHONE,SEX,AGE) VALUES(?,?,?,?,?)",
				new Object[] { "馬漢", "1000", "18701545309", 1, 30 });// 新增測試資料

	}

	/**
	 * 當資料庫版本發生改變的時候呼叫此方法,此方法適合修改資料庫的處理修改表,新增表,刪除表<br>
	 * 
	 * @param SQLiteDatabase
	 *            db<br>
	 * @param int oldVersion 老版本號<br>
	 * @param int newVersion 新版本號<br>
	 */
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

	}

}