【EF Core 2.0】Transaction事務會對DbContext底層創建和關閉數據庫連接的行爲有所影響

數據庫


我們先在SQL Server數據庫中建立一個Book表:

CREATE TABLE [dbo].[Book](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [BookName] [nvarchar](50) NULL,
    [BookDescription] [nvarchar](50) NULL,
    [ISBN] [nvarchar](20) NULL,
    [CreateTime] [datetime] NULL,
 CONSTRAINT [PK_Book] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Book] ADD  CONSTRAINT [DF_Book_CreateTime]  DEFAULT (getdate()) FOR [CreateTime]
GO

然後插入如下數據:

INSERT [dbo].[Book] ([BookName], [BookDescription], [ISBN]) VALUES (N'Chinese', N'Chinese', N'0001')
GO
INSERT [dbo].[Book] ([BookName], [BookDescription], [ISBN]) VALUES (N'English', N'English', N'0002')
GO
INSERT [dbo].[Book] ([BookName], [BookDescription], [ISBN]) VALUES (N'Japanese', N'Japanese', N'0003')
GO
INSERT [dbo].[Book] ([BookName], [BookDescription], [ISBN]) VALUES (N'Russian', N'Russian', N'0004')
GO
INSERT [dbo].[Book] ([BookName], [BookDescription], [ISBN]) VALUES (N'Italian', N'Italian', N'0005')
GO

查詢Book表的數據,如下圖所示:

現在我們使用EF Core將Book表映射到.NET Core控制檯項目中的Book實體上,Book實體如下所示:

using System;
using System.Collections.Generic;

namespace EFCoreDB.Entities
{
    public partial class Book
    {
        public int Id { get; set; }
        public string BookName { get; set; }
        public string BookDescription { get; set; }
        public string Isbn { get; set; }
        public DateTime? CreateTime { get; set; }
    }
}

不使用事務


然後我們在.NET Core控制檯項目Program類的Main方法中,使用DbContext(也就是FinanceDigitalToolContext)讀取BookName爲"Chinese"的Book實體,然後使用DbContext.SaveChanges方法兩次更改其BookDescription屬性的值,再從數據庫中將其查詢出來顯示,代碼如下:

using EFCoreDB.Entities;
using System;
using System.Linq;
using System.Linq.Expressions;

namespace EFCoreDB
{
    class Program
    {
        static void Main(string[] args)
        {
            using (FinanceDigitalToolContext dbContext = new FinanceDigitalToolContext())
            {
                Expression<Func<Book, bool>> bookExpression = b => b.BookName == "Chinese";//構造查詢條件,來查詢BookName爲Chinese的Book

                var chineseBook = dbContext.Book.First(bookExpression);//獲取BookName爲Chinese的Book實體chineseBook

                chineseBook.BookDescription = "This is a Chinese book";//更改chineseBook的BookDescription屬性
                dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫

                chineseBook.BookDescription = "This is a very good Chinese book";//再次更改chineseBook的BookDescription屬性
                dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫

                chineseBook = dbContext.Book.First(bookExpression);//重新獲取BookName爲Chinese的Book實體chineseBook

                //顯示當前chineseBook的當前BookDescription屬性值
                Console.WriteLine(chineseBook.BookName + " book has description: \"" + chineseBook.BookDescription + "\"");
            }

            Console.WriteLine("Press key to quit....");

            Console.ReadLine();
        }
    }
}

執行上面的代碼,我們使用EF Core的日誌功能,輸出每次DbContext訪問數據庫時的後臺日誌信息:

首先在執行:

var chineseBook = dbContext.Book.First(bookExpression);//獲取BookName爲Chinese的Book實體chineseBook

時,EF Core的日誌如下所示:

=============================== EF Core log started ===============================
Opening connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Opened connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN]
FROM [Book] AS [b]
WHERE [b].[BookName] = N'Chinese'
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Executed DbCommand (129ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN]
FROM [Book] AS [b]
WHERE [b].[BookName] = N'Chinese'
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
A data reader was disposed.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Closing connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Closed connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Context 'Book' started tracking 'FinanceDigitalToolContext' entity. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values.
=============================== EF Core log finished ===============================

從日誌中我們可以看出來,dbContext.Book.First(bookExpression)在數據庫中開啓了一個數據庫連接,並使用SQL語句做了查詢,然後關閉了數據庫連接。

然後在執行下面的代碼

chineseBook.BookDescription = "This is a Chinese book";//更改chineseBook的BookDescription屬性
dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫

時,EF Core的日誌如下所示:

=============================== EF Core log started ===============================
SaveChanges starting for 'FinanceDigitalToolContext'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
DetectChanges starting for 'FinanceDigitalToolContext'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Unchanged 'Book.BookDescription' detected as changed and will be marked as modified. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see property values.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
An 'Book' entity tracked by 'FinanceDigitalToolContext' changed from 'Unchanged' to 'Modified'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
DetectChanges completed for 'FinanceDigitalToolContext'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Opening connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Opened connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Beginning transaction with isolation level 'ReadCommitted'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Executing DbCommand [Parameters=[@p1='?' (DbType = Int32), @p0='?' (Size = 50)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Book] SET [BookDescription] = @p0
WHERE [ID] = @p1;
SELECT @@ROWCOUNT;
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Executed DbCommand (19ms) [Parameters=[@p1='?' (DbType = Int32), @p0='?' (Size = 50)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Book] SET [BookDescription] = @p0
WHERE [ID] = @p1;
SELECT @@ROWCOUNT;
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
A data reader was disposed.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Committing transaction.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Closing connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Closed connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Disposing transaction.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
An 'Book' entity tracked by 'FinanceDigitalToolContext' changed from 'Modified' to 'Unchanged'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
SaveChanges completed for 'FinanceDigitalToolContext' with 1 entities written to the database.
=============================== EF Core log finished ===============================

同樣從日誌中我們可以看出來在執行dbContext.SaveChanges方法時,EF Core在數據庫中開啓了一個數據庫連接,並使用SQL語句做了數據庫更改,然後關閉了數據庫連接。然後chineseBook這個Book實體的EntityState從Modified變爲了Unchanged。

然後執行代碼

chineseBook = dbContext.Book.First(bookExpression);//重新獲取BookName爲Chinese的Book實體chineseBook

時,EF Core的日誌如下所示:

=============================== EF Core log started ===============================
Opening connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Opened connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN]
FROM [Book] AS [b]
WHERE [b].[BookName] = N'Chinese'
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Executed DbCommand (21ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN]
FROM [Book] AS [b]
WHERE [b].[BookName] = N'Chinese'
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
A data reader was disposed.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Closing connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Closed connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================

從日誌中我們可以看出來,dbContext.Book.First(bookExpression)在數據庫中還是開啓了一個數據庫連接,並使用SQL語句做了查詢,然後關閉了數據庫連接。

 

總結下來,上面的代碼和日誌發生的事情如下:

  • dbContext.Book.First(bookExpression)開啓和關閉了一個數據庫連接,查詢BookName爲Chinese的Book實體chineseBook
  • 第一個dbContext.SaveChanges()開啓和關閉了一個數據庫連接,更改chineseBook的BookDescription屬性值"This is a Chinese book"到數據庫
  • 第二個dbContext.SaveChanges()開啓和關閉了一個數據庫連接,更改chineseBook的BookDescription屬性值"This is a very good Chinese book"到數據庫
  • dbContext.Book.First(bookExpression)開啓和關閉了一個數據庫連接,重新查詢BookName爲Chinese的Book實體chineseBook

所以綜上所述DbContext一共開啓了和關閉了四個數據庫連接。

 

使用事務


現在我們更改Program類Main方法中的代碼,將兩次DbContext.SaveChanges方法的調用都放在一個TransactionScope事務範圍中,所以現在兩次DbContext.SaveChanges方法提交的SQL都會在同一個數據庫事務中,代碼如下所示:

using EFCoreDB.Entities;
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Transactions;

namespace EFCoreDB
{
    class Program
    {
        static void Main(string[] args)
        {
            using (FinanceDigitalToolContext dbContext = new FinanceDigitalToolContext())
            {
                Expression<Func<Book, bool>> bookExpression = b => b.BookName == "Chinese";//構造查詢條件,來查詢BookName爲Chinese的Book

                var chineseBook = dbContext.Book.First(bookExpression);//獲取BookName爲Chinese的Book實體chineseBook

                //使用TransactionScope事務範圍來開啓一個數據庫事務
                using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew))
                {
                    chineseBook.BookDescription = "This is a Chinese book";//更改chineseBook的BookDescription屬性
                    dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫,由於TransactionScope事務範圍的存在,所以DbContext.SaveChanges方法提交的SQL語句都存在於TransactionScope的事務當中

                    chineseBook.BookDescription = "This is a very good Chinese book";//再次更改chineseBook的BookDescription屬性
                    dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫,由於TransactionScope事務範圍的存在,所以DbContext.SaveChanges方法提交的SQL語句都存在於TransactionScope的事務當中

                    transactionScope.Complete();//提交TransactionScope事務範圍中的SQL語句到數據庫,數據庫事務結束
                }

                chineseBook = dbContext.Book.First(bookExpression);//重新獲取BookName爲Chinese的Book實體chineseBook

                //顯示當前chineseBook的當前BookDescription屬性值
                Console.WriteLine(chineseBook.BookName + " book has description: \"" + chineseBook.BookDescription + "\"");
            }

            Console.WriteLine("Press key to quit....");

            Console.ReadLine();
        }
    }
}

執行上面的代碼,我們還是使用EF Core的日誌功能,輸出每次DbContext訪問數據庫時的後臺日誌信息:

 

首先執行

var chineseBook = dbContext.Book.First(bookExpression);//獲取BookName爲Chinese的Book實體chineseBook

時,EF Core的日誌如下所示:

=============================== EF Core log started ===============================
Opening connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Opened connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN]
FROM [Book] AS [b]
WHERE [b].[BookName] = N'Chinese'
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Executed DbCommand (139ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN]
FROM [Book] AS [b]
WHERE [b].[BookName] = N'Chinese'
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
A data reader was disposed.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Closing connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Closed connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Context 'Book' started tracking 'FinanceDigitalToolContext' entity. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values.
=============================== EF Core log finished ===============================

從日誌中我們可以看出來,dbContext.Book.First(bookExpression)在數據庫中開啓了一個數據庫連接,並使用SQL語句做了查詢,然後關閉了數據庫連接。

然後執行

using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew))
{

TransactionScope的事務範圍開始,此時數據庫事務已經開始,EF Core沒有輸出日誌

然後執行

chineseBook.BookDescription = "This is a Chinese book";//更改chineseBook的BookDescription屬性
dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫,由於TransactionScope事務範圍的存在,所以DbContext.SaveChanges方法提交的SQL語句都存在於TransactionScope的事務當中

時,EF Core的日誌如下所示:

=============================== EF Core log started ===============================
SaveChanges starting for 'FinanceDigitalToolContext'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
DetectChanges starting for 'FinanceDigitalToolContext'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Unchanged 'Book.BookDescription' detected as changed and will be marked as modified. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see property values.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
An 'Book' entity tracked by 'FinanceDigitalToolContext' changed from 'Unchanged' to 'Modified'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
DetectChanges completed for 'FinanceDigitalToolContext'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Opening connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Opened connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Enlisted in an ambient transaction with isolation level 'Serializable'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Executing DbCommand [Parameters=[@p1='?' (DbType = Int32), @p0='?' (Size = 50)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Book] SET [BookDescription] = @p0
WHERE [ID] = @p1;
SELECT @@ROWCOUNT;
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Executed DbCommand (79ms) [Parameters=[@p1='?' (DbType = Int32), @p0='?' (Size = 50)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Book] SET [BookDescription] = @p0
WHERE [ID] = @p1;
SELECT @@ROWCOUNT;
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
A data reader was disposed.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
An 'Book' entity tracked by 'FinanceDigitalToolContext' changed from 'Modified' to 'Unchanged'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
SaveChanges completed for 'FinanceDigitalToolContext' with 1 entities written to the database.
=============================== EF Core log finished ===============================

從日誌中我們可以看出來在執行dbContext.SaveChanges方法時,EF Core在數據庫中開啓了一個數據庫連接,並使用SQL語句做了數據庫更改,但是沒有關閉數據庫連接。然後chineseBook這個Book實體的EntityState從Modified變爲了Unchanged。

然後執行

chineseBook.BookDescription = "This is a very good Chinese book";//再次更改chineseBook的BookDescription屬性
dbContext.SaveChanges();//用DbContext.SaveChanges方法保存更改到數據庫,由於TransactionScope事務範圍的存在,所以DbContext.SaveChanges方法提交的SQL語句都存在於TransactionScope的事務當中

時,EF Core的日誌如下所示:

=============================== EF Core log started ===============================
SaveChanges starting for 'FinanceDigitalToolContext'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
DetectChanges starting for 'FinanceDigitalToolContext'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Unchanged 'Book.BookDescription' detected as changed and will be marked as modified. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see property values.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
An 'Book' entity tracked by 'FinanceDigitalToolContext' changed from 'Unchanged' to 'Modified'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
DetectChanges completed for 'FinanceDigitalToolContext'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Executing DbCommand [Parameters=[@p1='?' (DbType = Int32), @p0='?' (Size = 50)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Book] SET [BookDescription] = @p0
WHERE [ID] = @p1;
SELECT @@ROWCOUNT;
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Executed DbCommand (22ms) [Parameters=[@p1='?' (DbType = Int32), @p0='?' (Size = 50)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Book] SET [BookDescription] = @p0
WHERE [ID] = @p1;
SELECT @@ROWCOUNT;
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
A data reader was disposed.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
An 'Book' entity tracked by 'FinanceDigitalToolContext' changed from 'Modified' to 'Unchanged'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
SaveChanges completed for 'FinanceDigitalToolContext' with 1 entities written to the database.
=============================== EF Core log finished ===============================

從日誌中我們可以看出來在執行dbContext.SaveChanges方法時,EF Core在數據庫中並沒有開啓新的數據庫連接,而是沿用了上一個DbContext.SaveChanges方法開啓的數據庫連接來提交SQL語句到數據庫。然後chineseBook這個Book實體的EntityState從Modified變爲了Unchanged。

然後執行

    transactionScope.Complete();//提交TransactionScope事務範圍中的SQL語句到數據庫,數據庫事務結束
}

提交TransactionScope的事務到數據庫,此時數據庫事務結束,TransactionScope的事務範圍也結束,EF Core沒有輸出日誌

然後執行

chineseBook = dbContext.Book.First(bookExpression);//重新獲取BookName爲Chinese的Book實體chineseBook

時,EF Core的日誌如下所示:

=============================== EF Core log started ===============================
Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN]
FROM [Book] AS [b]
WHERE [b].[BookName] = N'Chinese'
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Executed DbCommand (24ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [b].[ID], [b].[BookDescription], [b].[BookName], [b].[CreateTime], [b].[ISBN]
FROM [Book] AS [b]
WHERE [b].[BookName] = N'Chinese'
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
A data reader was disposed.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Closing connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================
=============================== EF Core log started ===============================
Closed connection to database 'FinanceDigitalTool' on server 'CNGDCAAITSQL01'.
=============================== EF Core log finished ===============================

從日誌中我們可以看出來,dbContext.Book.First(bookExpression)在數據庫中也沒有開啓新的數據庫連接,而是繼續沿用了第一個DbContext.SaveChanges方法開啓的數據庫連接,使用SQL語句做了查詢,之後關閉了第一個DbContext.SaveChanges方法開啓的數據庫連接,所以可以看到第一個DbContext.SaveChanges方法開啓的數據庫連接,現在才被關閉,這和不使用事務時是完全不一樣的。

 

總結下來,使用事務後的代碼和日誌發生的事情如下:

  • dbContext.Book.First(bookExpression)開啓和關閉了一個數據庫連接,查詢BookName爲Chinese的Book實體chineseBook
  • using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew)){開啓了TransactionScope事務範圍,數據庫事務開始
  • 第一個dbContext.SaveChanges()開啓一個數據庫連接,但是沒有關閉數據庫連接,更改chineseBook的BookDescription屬性值"This is a Chinese book"到數據庫
  • 第二個dbContext.SaveChanges()沒有開啓新的數據庫連接,而是沿用了上一個DbContext.SaveChanges方法開啓的數據庫連接,更改chineseBook的BookDescription屬性值"This is a very good Chinese book"到數據庫
  • transactionScope.Complete()提交TransactionScope事務範圍的數據庫事務到數據庫,數據庫事務結束
  • }TransactionScope事務範圍結束
  • dbContext.Book.First(bookExpression)沒有開啓新的數據庫連接,而是沿用了第一個DbContext.SaveChanges方法開啓的數據庫連接,重新查詢BookName爲Chinese的Book實體chineseBook,最後關閉了第一個DbContext.SaveChanges方法開啓的數據庫連接。

所以綜上所述DbContext這次一共只開啓和關閉了兩個數據庫連接,並且第二個數據庫連接執行了三次數據庫操作(兩次DbContext.SaveChanges更改數據,一次Book.First查詢數據)才被關閉。

 

由此我們可以看到EF Core在處於事務中時,會優化底層開啓和關閉數據庫連接的機制,因爲EF Core覺得兩次DbContext.SaveChanges方法提交的SQL語句既然都在同一個事務中,所以就沒有必要每次都開啓和關閉一個數據庫連接,而是沿用了第一次DbContext.SaveChanges方法開啓的數據庫連接,所以這和沒有使用事務的時候是完全不一樣的。

 

在efcore平臺時,你使用TransactionScope將會出現異常,微軟會提示你去查看相關資料,這回資料挺準!https://docs.microsoft.com/en-us/ef/core/saving/transactions

本文章主要說了幾點內容

  1. 默認的事務-savechanges依舊是一個事務
  2. 單個上下文實現事務
  3. 不同上下文之間實現事務
using (var context = new BloggingContext())

        {

            using (var transaction = context.Database.BeginTransaction())

            {

                try

                {

                    context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });

                    context.SaveChanges();


                    context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/visualstudio" });

                    context.SaveChanges();


                    var blogs = context.Blogs

                        .OrderBy(b => b.Url)

                        .ToList();


                    // Commit transaction if all commands succeed, transaction will auto-rollback

                    // when disposed if either commands fails

                    transaction.Commit();

                }

                catch (Exception)

                {

                    // TODO: Handle failure

                }

            }

        }

 

發佈了189 篇原創文章 · 獲贊 153 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章