0

由于这是一个非常丰富的会议,我再次观看它,在24:17分钟我注意到 Virgil 说

此外,在使用 SQLite 时使用事务,它们不仅会保持数据完整性,还会提高数据库操作的性能

编辑:他对“使用交易”的确切含义是什么,他的意思是告诉我们使用 BEGIN TRANSACTION声明,还是他提到了其他东西?

如果是第一个,那么:

  1. 这是否意味着我们应该使用SQLiteDatabase#rawQuery()方法而不是提供的方法来编写原始 SQL 语句SQLiteDatabase#query()

  2. SELECT它与使用语句和语句有什么区别TRANSACTION

4

2 回答 2

0

根据SQLITE文档:

事务数据库是一种所有更改和查询似乎都是原子的、一致的、隔离的和持久的 (ACID) 的数据库。SQLite 实现了原子的、一致的、隔离的和持久的可序列化事务,即使事务因程序崩溃、操作系统崩溃或计算机电源故障而中断。

在android中通常插入很慢,所以当你想要插入大量数据时,你必须使用事务。当您要向数据库中插入数千条记录时,插入每条记录需要花费大量时间和宝贵资源。在这种情况下,批量插入或更新可以加快进程。

这是一个如何在 android 中使用事务的示例:

database.beginTransaction();
// or use  use beginTransactionNonExclusive() or beginTransactionWithListenerNonExclusive(SQLiteTransactionListener)
// to start a transaction. Non-exclusive mode allows database file to be in readable by other threads executing queries.
database.beginTransactionNonExclusive();
    try {
        String sql = "Insert or Replace into Students (student_number, age, phone) values(?,?,?)";
        SQLiteStatement compileStatement = database.compileStatement(sql);
        for(int i = 0; i < studentList.size(); i++) {
            compileStatement.bindString(1, studentList.get(i).student_numerb());
            compileStatement.bindString(2, studentList.get(i).age());
            compileStatement.bindString(3, studentList.get(i).phone());
            compileStatement.execute();
            database.setTransactionSuccessful();
        } catch(Exception e){
            e.printStackTrace();
        } finally {
            database.endTransaction();
        }
于 2014-08-13T03:38:42.453 回答
0

一个简单的例子来解释你需要数据库事务和使用准备好的语句等。

在插入大量记录,即数千条左右的记录时,我们遇到了“插入速度”的问题。Android中常用的insert命令比较慢,所以我们可以使用事务和prepared statement。

在我们的例子中,我们在插入查询中使用 INSERT OR REPLACE INTO,因为我们想要根据创建的触发器 (INDEX) 更新已经存在的行。

如果您使用 INSERT OR REPLACE INTO 命令,则必须创建触发器。此 SQL 触发器在创建表后执行(请参阅下面的 DatabaseHandler.java)

加快插入速度的另一个重要因素是使用准备好的语句。

您可以在下面找到示例:

MainActivity.java - 包含将在用户单击按钮时执行以向 db 插入大量数据的 AsyncTask。

public class MainActivity extends Activity {


final String TAG = "MainActivity.java";
EditText editTextRecordNum;
TextView tvStatus;

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    View.OnClickListener handler = new View.OnClickListener() {
        public void onClick(View v) {

            switch (v.getId()) {

            case R.id.buttonNormalInsert:
                new AsyncInsertData("normal").execute();
                break;
            case R.id.buttonFastInsert:
                new AsyncInsertData("fast").execute();
                break;
            }
        }
    };

    // EditText for entering desired number of records to be inserted
    editTextRecordNum = (EditText) findViewById(R.id.editTextRecordNum);

    // Button for normal and fast insert
    findViewById(R.id.buttonNormalInsert).setOnClickListener(handler);
    findViewById(R.id.buttonFastInsert).setOnClickListener(handler);

    // status TextView
    tvStatus = (TextView) findViewById(R.id.textViewStatus);

}

// we used AsyncTask so it won't block the UI thread during inserts.
class AsyncInsertData extends AsyncTask<String, String, String> {

    DatabaseHandler databaseHandler;
    String type;
    long timeElapsed;

    protected AsyncInsertData(String type){
        this.type  = type;
        this.databaseHandler = new DatabaseHandler(MainActivity.this);
    }

    // @type - can be 'normal' or 'fast'
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        tvStatus.setText("Inserting " + editTextRecordNum.getText() + " records...");
    }

    @Override
    protected String doInBackground(String... aurl) {

        try {

            // get number of records to be inserted
            int insertCount = Integer.parseInt(editTextRecordNum.getText().toString());

            // empty the table
            databaseHandler.deleteRecords();

            // keep track of execution time
            long lStartTime = System.nanoTime();

            if (type.equals("normal")) {
                databaseHandler.insertNormal(insertCount);
            } else {
                databaseHandler.insertFast(insertCount);
            }

            // execution finised
            long lEndTime = System.nanoTime();

            // display execution time
            timeElapsed = lEndTime - lStartTime;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    protected void onPostExecute(String unused) {
        tvStatus.setText("Done inserting " + databaseHandler.countRecords() + " records. Time elapsed: " + timeElapsed / 1000000 + " ms."); 
    }

}

}

DatabaseHandler.java – 处理数据库操作,例如创建表、清空数据库、统计数据库记录和使用循环插入数据。

public class DatabaseHandler extends SQLiteOpenHelper {


// for our logs
public static final String TAG = "DatabaseHandler.java";

// database version
private static final int DATABASE_VERSION = 7;

// database name
protected static final String DATABASE_NAME = "DatabaseName";

// table details
public String tableName = "locations";
public String fieldObjectId = "id";
public String fieldObjectName = "name";
public String fieldObjectDescription = "description";

// constructor
public DatabaseHandler(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

// creating table
@Override
public void onCreate(SQLiteDatabase db) {

    String sql = "";

    sql += "CREATE TABLE " + tableName;
    sql += " ( ";
    sql += fieldObjectId + " INTEGER PRIMARY KEY AUTOINCREMENT, ";
    sql += fieldObjectName + " TEXT, ";
    sql += fieldObjectDescription + " TEXT ";
    sql += " ) ";

    db.execSQL(sql);

    // create the index for our INSERT OR REPLACE INTO statement.
    // this acts as the WHERE name="name input" AND description="description input"
    // if that WHERE clause is true, I mean, it finds the same name and description in the database,
    // it will be REPLACEd. 
    // ELSE, what's in the database will remain and the input will be INSERTed (new record)
    String INDEX = "CREATE UNIQUE INDEX locations_index ON "
                    + tableName + " (name, description)";

    db.execSQL(INDEX);
}


// When upgrading the database, it will drop the current table and recreate.
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    String sql = "DROP TABLE IF EXISTS " + tableName;
    db.execSQL(sql);

    onCreate(db);
}

// insert data using transaction and prepared statement
public void insertFast(int insertCount) {

    // you can use INSERT only
    String sql = "INSERT OR REPLACE INTO " + tableName + " ( name, description ) VALUES ( ?, ? )";

    SQLiteDatabase db = this.getWritableDatabase();

    /*
     * According to the docs http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
     * Writers should use beginTransactionNonExclusive() or beginTransactionWithListenerNonExclusive(SQLiteTransactionListener) 
     * to start a transaction. Non-exclusive mode allows database file to be in readable by other threads executing queries.
     */
    db.beginTransactionNonExclusive();
    // db.beginTransaction();

    SQLiteStatement stmt = db.compileStatement(sql);

    for(int x=1; x<=insertCount; x++){

        stmt.bindString(1, "Name # " + x);
        stmt.bindString(2, "Description # " + x);

        stmt.execute();
        stmt.clearBindings();

    }

    db.setTransactionSuccessful();
    db.endTransaction();

    db.close();
}

// inserts the record without using transaction and prepare statement
public void insertNormal(int insertCount){
    try{

        SQLiteDatabase db = this.getWritableDatabase();

        for(int x=1; x<=insertCount; x++){

            ContentValues values = new ContentValues();
            values.put(fieldObjectName, "Name # " + x);
            values.put(fieldObjectDescription, "Description # " + x);

            db.insert(tableName, null, values);

        }

        db.close();

    }catch(Exception e){
        e.printStackTrace();
    } 
}

// deletes all records
public void deleteRecords(){

    SQLiteDatabase db = this.getWritableDatabase();
    db.execSQL("delete from "+ tableName);
    db.close();
}

// count records
public int countRecords(){

    SQLiteDatabase db = this.getWritableDatabase();

    Cursor cursor = db.rawQuery("SELECT count(*) from " + tableName, null);
    cursor.moveToFirst();

    int recCount = cursor.getInt(0);

    cursor.close();
    db.close();

    return recCount;
}

}

activity_main.xml – 布局以便我们可以输入要插入的所需记录数,选择我们希望它是“正常”还是“快速”插入,以及操作的状态。

<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<EditText
    android:id="@+id/editTextRecordNum"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:inputType="number"
    android:singleLine="true"
    android:ems="10" >

    <requestFocus />
</EditText>

<Button
    android:id="@+id/buttonNormalInsert"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/editTextRecordNum"
    android:layout_below="@+id/editTextRecordNum"
    android:text="Normal Insert" />

<Button
    android:id="@+id/buttonFastInsert"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBaseline="@+id/buttonNormalInsert"
    android:layout_alignBottom="@+id/buttonNormalInsert"
    android:layout_toRightOf="@+id/buttonNormalInsert"
    android:text="Fast Insert" />

<TextView
    android:id="@+id/textViewStatus"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/buttonNormalInsert"
    android:layout_below="@+id/buttonNormalInsert"
    android:padding="10dp"
    android:text="Status" />

于 2014-08-13T03:31:26.880 回答