返回介绍

SQLite transactions with Visual Basic

发布于 2025-02-22 22:20:17 字数 11993 浏览 0 评论 0 收藏 0

In this chapter, we will work with transactions. First, we provide some basic definitions. Then we will have programs that show, how to work with transactions.

A transaction is an atomic unit of database operations against the data in one or more databases. The effects of all the SQL statements in a transaction can be either all committed to the database or all rolled back.

In SQLite, any command other than the SELECT will start an implicit transaction. Also, within a transaction a command like CREATE TABLE ..., VACUUM , PRAGMA , will commit previous changes before executing.

Manual transactions are started with the BEGIN TRANSACTION statement and finished with the COMMIT or ROLLBACK statements.

SQLite supports three non-standard transaction levels: DEFERRED , IMMEDIATE , and EXCLUSIVE . SQLite automatically puts each command into its own transaction unless we start our own transaction. Note that this may be influenced by the driver too. SQLite Python driver has the autocommit mode turned off by default and the first SQL command starts a new transaction.

Option Strict On

Imports Mono.Data.Sqlite

Module Example

  Sub Main()

    Dim cs As String = "URI=file:test.db"

    Using con As New SqliteConnection(cs)
    
      con.Open()
    
      Using cmd As New SqliteCommand(con)

        cmd.CommandText = "DROP TABLE IF EXISTS Friends"
        cmd.ExecuteNonQuery()
        cmd.CommandText = "CREATE TABLE Friends(Id INTEGER PRIMARY KEY," _ 
                  & "Name TEXT)"
        cmd.ExecuteNonQuery()
        cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Tom')"
        cmd.ExecuteNonQuery()
        cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Rebecca')"
        cmd.ExecuteNonQuery()
        cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Jim')"
        cmd.ExecuteNonQuery()
        cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Robert')"
        cmd.ExecuteNonQuery()
        cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Julian')"
        cmd.ExecuteNonQuery()
    
      End Using

      con.Close()

    End Using
    
  End Sub

End Module

We create a Friends table and fill it with data. We do not explicitly start a transaction, nor we call commit or rollback methods. Yet the data is written to the table. It is because by default, we work in the autocommit mode. In this mode each SQL statement is immediately effective.

cmd.CommandText = "DROP TABLE IF EXISTS Friends"
cmd.ExecuteNonQuery()
cmd.CommandText = "CREATE TABLE Friends(Id INTEGER PRIMARY KEY," _ 
          & "Name TEXT)"
cmd.ExecuteNonQuery()

We drop the Friends table if it already exists. Then we create the table with the CREATE TABLE statement.

cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Tom')"
cmd.ExecuteNonQuery()
cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Rebecca')"
cmd.ExecuteNonQuery()
...

We insert two rows.

sqlite> SELECT * FROM Friends;
1|Tom
2|Rebecca
3|Jim
4|Robert
5|Julian

The Friends table was successfully created.

In the second example we will start a custom transaction with the BeginTransaction() method.

Option Strict On

Imports Mono.Data.Sqlite

Module Example

  Sub Main()

    Dim cs As String = "URI=file:test.db"

    Using con As New SqliteConnection(cs)
    
      con.Open()

      Dim tr As SqliteTransaction = con.BeginTransaction()
    
      Using tr 
      
        Using cmd As New SqliteCommand(con)

          cmd.Transaction = tr
          cmd.CommandText = "DROP TABLE IF EXISTS Friends"
          cmd.ExecuteNonQuery()
          cmd.CommandText = "CREATE TABLE Friends(Id INTEGER PRIMARY KEY," _ 
                    & "Name TEXT)"
          cmd.ExecuteNonQuery()
          cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Tom')"
          cmd.ExecuteNonQuery()
          cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Rebecca')"
          cmd.ExecuteNonQuery()
          cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Jim')"
          cmd.ExecuteNonQuery()
          cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Robert')"
          cmd.ExecuteNonQuery()
          cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Julian')"
          cmd.ExecuteNonQuery()
          cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Jane')"
          cmd.ExecuteNonQuery()
        End Using

        tr.Commit()
      End Using

      con.Close()
    End Using
    
  End Sub

End Module

All SQL commands form a unit. Either all are saved or nothing is saved. This is the basic idea behind transactions.

Dim tr As SqliteTransaction = con.BeginTransaction()

The BeginTransaction() method starts a transaction.

cmd.Transaction = tr

We set the transaction within which the SqliteCommand executes.

tr.Commit()

If everything ran OK, we commit the whole transaction to the database. In case of an exception, the transaction is rolled back behind the scenes.

Explicit rollback call

Now we are going to show an example, where we rollback manually a transaction, in case of an exception.

Option Strict On

Imports Mono.Data.Sqlite

Module Example

  Sub Main()

    Dim cs As String = "URI=file:test.db"

    Dim con As SqliteConnection   
    Dim tr As SqliteTransaction
    Dim cmd As SqliteCommand
    
    Try
      con = New SqliteConnection(cs)
    
      con.Open()
  
      tr = con.BeginTransaction()
      cmd = con.CreateCommand()
        
      cmd.Transaction = tr
      cmd.CommandText = "DROP TABLE IF EXISTS Friends"
      cmd.ExecuteNonQuery()
      cmd.CommandText = "CREATE TABLE Friends(Id INTEGER PRIMARY KEY," _
                &  "Name TEXT)"
      cmd.ExecuteNonQuery()
      cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Tom')"
      cmd.ExecuteNonQuery()
      cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Rebecca')"
      cmd.ExecuteNonQuery()
      cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Jim')"
      cmd.ExecuteNonQuery()
      cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Robert')"
      cmd.ExecuteNonQuery()
      cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Julian')"
      cmd.ExecuteNonQuery()
      cmd.CommandText = "INSERT INTO Friends(Name) VALUES ('Jane')"
      cmd.ExecuteNonQuery()
        
      tr.Commit()

    Catch ex As SqliteException
    
      Console.WriteLine("Error: {0}",  ex.ToString())

      If tr IsNot Nothing
        Try         
          tr.Rollback()          
        Catch ex2 As SqliteException
          Console.WriteLine("Transaction rollback failed.")
          Console.WriteLine("Error: {0}",  ex2.ToString())
        Finally        
          tr.Dispose()
        End Try
      End If
    Finally 
      If cmd IsNot Nothing
        cmd.Dispose()
      End If

      If tr IsNot Nothing
        tr.Dispose()
      End If

      If con IsNot Nothing
        Try         
          con.Close()
        Catch ex As SqliteException        
          Console.WriteLine("Closing connection failed.")
          Console.WriteLine("Error: {0}",  ex.ToString())
        Finally        
          con.Dispose()
        End Try
      End If
    End Try  
    
  End Sub

End Module

We create our own Try , Catch , Finally blocks, where we deal with possible issues.

Catch ex As SqliteException

  Console.WriteLine("Error: {0}",  ex.ToString())

  If tr IsNot Nothing
    Try         
      tr.Rollback()          
    Catch ex2 As SqliteException
      Console.WriteLine("Transaction rollback failed.")
      Console.WriteLine("Error: {0}",  ex2.ToString())
    Finally        
      tr.Dispose()
    End Try
  End If

When an exception is thrown during the creation of the Friends table, we call the Rollback() method. Rolling back a transaction might fail too; we check this scenario.

If cmd IsNot Nothing
  cmd.Dispose()
End If

If tr IsNot Nothing
  tr.Dispose()
End If

When all goes OK, we dispose the resources.

If con IsNot Nothing
  Try         
    con.Close()
  Catch ex As SqliteException        
    Console.WriteLine("Closing connection failed.")
    Console.WriteLine("Error: {0}",  ex.ToString())
  Finally        
    con.Dispose()
  End Try
End If

When closing a connection, we might receive another exception. We handle this case here.

Errors

When there is an error in the transaction, the transaction is rolled back an no changes are committed to the database.

Option Strict On

Imports Mono.Data.Sqlite

Module Example

  Sub Main()

    Dim cs As String = "URI=file:test.db"

    Using con As New SqliteConnection(cs)
    
      con.Open()

      Dim tr As SqliteTransaction = con.BeginTransaction()
    
      Using tr 
    
        Using cmd As New SqliteCommand(con)

          cmd.CommandText = "SELECT * FROM Cars LIMIT 5"
          
          cmd.Transaction = tr
          cmd.CommandText = "UPDATE Friends SET Name='Thomas' WHERE Id=1"
          cmd.ExecuteNonQuery()

          cmd.CommandText = "UPDATE Friend SET Name='Bob' WHERE Id=4"
          cmd.ExecuteNonQuery()
          
          tr.Commit()
        End Using
      End Using
      con.Close()
    End Using
    
  End Sub

End Module

In the code example we want to change two names. There are two statements which form a transaction. There is an error in the second SQL statement. Therefore the transaction is rolled back.

cmd.CommandText = "UPDATE Friend SET Name='Bob' WHERE Id=4"
cmd.ExecuteNonQuery()

The name of the table is incorrect. There is no Friend table in the database.

$ mono error.exe 

Unhandled Exception: Mono.Data.Sqlite.SqliteException: SQLite error
no such table: Friend
...

Running the example will display this error message. The transaction is rolled back.

sqlite> SELECT * FROM Friends;
1|Tom
2|Rebecca
3|Jim
4|Robert
5|Julian
6|Jane

No changes took place in the Friends table. Even if the first UPDATE statement was correct.

We will again try to change two rows; this time without using the SqliteTransaction .

Option Strict On

Imports Mono.Data.Sqlite

Module Example

  Sub Main()

    Dim cs As String = "URI=file:test.db"

    Using con As New SqliteConnection(cs)
    
      con.Open()
    
      Using cmd As New SqliteCommand(con)

        cmd.CommandText = "SELECT * FROM Cars LIMIT 5"
        
        cmd.CommandText = "UPDATE Friends SET Name='Thomas' WHERE Id=1"
        cmd.ExecuteNonQuery()

        cmd.CommandText = "UPDATE Friend SET Name='Bob' WHERE Id=4"
        cmd.ExecuteNonQuery()
        
      End Using

      con.Close()
    End Using
    
  End Sub

End Module

We try to update two names in the Friends table, Tom to Thomas and Robert to Bob.

cmd.CommandText = "UPDATE Friend SET Name='Bob' WHERE Id=4"
cmd.ExecuteNonQuery()

This UPDATE statement is incorrect.

$ mono error2.exe 

Unhandled Exception: Mono.Data.Sqlite.SqliteException: SQLite error
no such table: Friend
...

We receive the same error message as in the previous example.

sqlite> SELECT * FROM Friends;
1|Thomas
2|Rebecca
3|Jim
4|Robert
5|Julian
6|Jane

However this time, the first UPDATE statement was saved. The second one was not.

In this part of the SQLite Visual Basic tutorial, we have worked with transactions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文