mirror of
https://github.com/dotnetcore/FreeSql.git
synced 2026-02-06 16:30:52 +08:00
Page:
事务
Pages
ADO
AOP
API
BaseEntity
Cascade Deletion
Cascade Saving
CodeFirst
DI UnitOfWorkManager
Dapper比较
DbContext
DbFirst
Delete Data
Dynamic Operations
Entity Relationship
EntityFramework比较
FluentApi
Getting Started
Greed Loading
Group Aggregation Query
Home
Import Entity Configuration from Database
Insert Data
Insert or Update
Install
Lazy Loading
Linq to Sql
LinqToSql
Nested Query
Pagination
Parent Child Relationship Query
Query Data
Query from Multi Tables
Query from Single Table
Repository Layer
Repository
Return Data
Unit of Work
Update Data
With Sql
withsql
事务
修改
入门
分组聚合查询
分表分库
分页查询
删除
动态操作
单表查询
多表查询
安装
实体关系
实体特性
导入数据库特性
嵌套查询
工作单元
常见问题
延时加载
性能
支持我们
更新日志
查询
查询父子关系
添加
添加或修改
租户
类型映射
联合查询
联级保存
联级删除
聚合根(实验室)
自定义特性
表达式函数
读写分离
贪婪加载
过滤器
返回数据
首页
骚操作
Clone
This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
dotnet add package FreeSql.DbContext
1、常规事务
UnitOfWork 是对 DbTransaction 事务对象的封装,方便夹带私有数据。
using (var uow = fsql.CreateUnitOfWork())
{
await uow.Orm.Insert(item).ExecuteAffrowsAsync(); //uow.Orm API 和 IFreeSql 一样
await uow.Orm.Ado.ExecuteNoneQueryAsync(sql);
await fsql.Insert(item)... //错误,不在一个事务
var repo = uow.GetRepository<Song>(); //仓储 CRUD
await repo.InsertAsync(item);
uow.Commit();
}
提示:uow 范围内,尽量别使用 fsql 对象,以免不处在一个事务
使用 UnitOfWorkManager 管理 UnitOfWork,如下:
using (var uowManager = new UnitOfWorkManager(fsql))
{
using (var uow = uowManager.Begin())
{
using (var uow2 = uowManager.Begin()) //与 uow 同一个事务
{
uow2.Commit(); //事务还未提交
}
uow.Commit(); //事务提交
}
}
2、仓储事务(依赖注入)
var builder = WebApplication.CreateBuilder(args);
Func<IServiceProvider, IFreeSql> fsqlFactory = r =>
{
IFreeSql fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=freedb.db")
.UseMonitorCommand(cmd => Console.WriteLine($"Sql:{cmd.CommandText}"))
.Build();
return fsql;
};
builder.Services.AddSingleton<IFreeSql>(fsqlFactory);
builder.Services.AddFreeRepository();
builder.Services.AddScoped<UnitOfWorkManager>();
builder.Services.AddScoped<SongService>();
WebApplication app = builder.Build();
public class SongService
{
readonly IBaseRepository<Song> _songRepository;
readonly IBaseRepository<Detail> _detailRepository;
public SongService(IBaseRepository<Song> songRepository, IBaseRepository<Detail> detailRepository)
{
_songRepository = songRepository;
_detailRepository = detailRepository;
}
[Transactional]
async public Task Test1()
{
//所有注入的仓储对象,都是一个事务
await _songRepository.InsertAsync(xxx1);
await _detailRepository.DeleteAsync(xxx2);
this.Test2();
}
[Transactional(Propagation = Propagation.Nested)]
public void Test2() //嵌套事务
{
}
}
具体请移步文档:- AOP 特性标签实现跨方法事务
3、同线程事务
同线程事务内置在 FreeSql.dll,由 fsql.Transaction 管理事务提交回滚(缺点:不支持异步)。
用户购买了价值 100 元的商品:扣余额、扣库存。
fsql.Transaction(() =>
{
//fsql.Ado.TransactionCurrentThread 获得当前事务对象
var affrows = fsql.Update<User>()
.Set(a => a.Wealth - 100)
.Where(a => a.Wealth >= 100).ExecuteAffrows();
//判断别让用户余额扣成负数
//抛出异常,回滚事务,事务退出
if (affrows < 1) throw new Exception("用户余额不足");
affrows = fsql.Update<Goods>()
.Set(a => a.Stock - 1)
.Where(a => a.Stock >= 1).ExecuteAffrows();
if (affrows < 1) throw new Exception("商品库存不足");
});
同线程事务使用简单,需要注意的限制:
-
事务对象在线程挂载,每个线程只可开启一个事务连接,嵌套使用的是同一个事务;
-
事务体内代码不可以切换线程,因此不可使用任何异步方法,包括 FreeSql 提供的数据库异步方法(可以使用任何 Curd 同步方法);
4、悲观锁
var user = fsql.Select<User>().ForUpdate(true).Where(a => a.Id == 1).ToOne();
//SELECT ... FROM User a for update nowait
for update 在 Oracle/PostgreSQL/MySql 是通用的写法,我们对 SqlServer 做了特别适配,执行的 SQL 语句大致如下:
SELECT ... FROM [User] a With(UpdLock, RowLock, NoWait)
5. 外部事务
// 场景:已经有一个开启的 Connection 和 Transaction
using (var conn = new SqlConnection("..."))
{
conn.Open();
using (var tran = conn.BeginTransaction())
{
// 1. 原生/Dapper 操作
// command.Transaction = tran;
// command.ExecuteNonQuery();
// 2. 桥接给 FreeSql
// 使用扩展方法创建适配器,传入现有的 tran
using (var uow = fsql.CreateUnitOfWork(tran))
{
// 在此 uow 下获取的仓储或 Orm,都会使用传入的 tran
var repo = uow.GetRepository<MyEntity>();
repo.Insert(new MyEntity { Name = "FreeSql Insert" });
// 或者直接使用 Orm
uow.Orm.Insert(new MyEntity { Name = "Direct Orm Insert" }).ExecuteAffrows();
// 这里的 Commit 只会触发 FreeSql 的事件,不会提交物理事务
uow.Commit();
}
// 3. 真正的提交由最外层控制
tran.Commit();
}
}
更多资料
Basic
- 入门 Getting Started
- 安装 How to Install
- 添加 Insert Data
- 删除 Delete Data
- 修改 Update Data
- 添加或修改 Insert or Update ✨
- 查询 Query Data
- 仓储层 Repository Layer
- CodeFirst
- DbFirst
- 表达式函数
- 事务
- 过滤器
- ADO
- AOP✨
- 读写分离
- 分表分库
- 租户
- 性能
- 动态操作 Dynamic Operations
- 你不知道的功能✨
- API参考