mirror of
https://github.com/dotnetcore/FreeSql.git
synced 2026-02-03 23:10:54 +08:00
update
115
DI-UnitOfWorkManager.md
Normal file
115
DI-UnitOfWorkManager.md
Normal file
@@ -0,0 +1,115 @@
|
||||
本篇文章内容引导,如何在 asp.net core 项目中使用特性(注解) 的方式管理事务。
|
||||
|
||||
> UnitOfWorkManager 只可以管理 Repository 仓储对象的事务,直接 fsql.Insert\<T>() 是不行的!!但是可以用 repository.Orm.Insert\<T\>!!repository.Orm 是特殊实现的 IFreeSql,与 当前事务保持一致。
|
||||
|
||||
支持六种传播方式(propagation),意味着跨方法的事务非常方便,并且支持同步异步:
|
||||
|
||||
- Requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,默认的选择。
|
||||
- Supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
|
||||
- Mandatory:使用当前事务,如果没有当前事务,就抛出异常。
|
||||
- NotSupported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
|
||||
- Never:以非事务方式执行操作,如果当前事务存在则抛出异常。
|
||||
- Nested:以嵌套事务方式执行。
|
||||
|
||||
### 第一步:引入动态代理库
|
||||
|
||||
> dotnet add package Rougamo.Fody
|
||||
|
||||
```csharp
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class TransactionalAttribute : Rougamo.MoAttribute
|
||||
{
|
||||
public Propagation Propagation { get; set; } = Propagation.Required;
|
||||
public IsolationLevel IsolationLevel { get => m_IsolationLevel.Value; set => m_IsolationLevel = value; }
|
||||
IsolationLevel? m_IsolationLevel;
|
||||
|
||||
static AsyncLocal<IServiceProvider> m_ServiceProvider = new AsyncLocal<IServiceProvider>();
|
||||
public static void SetServiceProvider(IServiceProvider serviceProvider) => m_ServiceProvider.Value = serviceProvider;
|
||||
|
||||
IUnitOfWork _uow;
|
||||
public override void OnEntry(MethodContext context)
|
||||
{
|
||||
var uowManager = m_ServiceProvider.Value.GetService(typeof(UnitOfWorkManager)) as UnitOfWorkManager;
|
||||
_uow = uowManager.Begin(this.Propagation, this.m_IsolationLevel);
|
||||
}
|
||||
public override void OnExit(MethodContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (context.Exception == null) _uow.Commit();
|
||||
else _uow.Rollback();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_uow.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| UnitOfWorkManager 成员 | 说明 |
|
||||
| -- | -- |
|
||||
| IUnitOfWork Current | 返回当前的工作单元 |
|
||||
| void Binding(repository) | 将仓储的事务交给它管理 |
|
||||
| IUnitOfWork Begin(propagation, isolationLevel) | 创建工作单元 |
|
||||
|
||||
### 第二步:配置 Startup.cs 注入、中间件
|
||||
|
||||
```csharp
|
||||
//Startup.cs
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IFreeSql>(fsql);
|
||||
services.AddScoped<UnitOfWorkManager>();
|
||||
services.AddFreeRepository(null, typeof(Startup).Assembly);
|
||||
//批量注入 Service
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
TransactionalAttribute.SetServiceProvider(context.RequestServices);
|
||||
await next();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 第三步:在 Controller 或者 Service 或者 Repository 中使用事务特性
|
||||
|
||||
```csharp
|
||||
public class SongService
|
||||
{
|
||||
readonly IBaseRepository<Song> _repoSong;
|
||||
readonly IBaseRepository<Detail> _repoDetail;
|
||||
readonly SongRepository _repoSong2;
|
||||
|
||||
public SongService(IBaseRepository<Song> repoSong, IBaseRepository<Detail> repoDetail, SongRepository repoSong2)
|
||||
{
|
||||
_repoSong = repoSong;
|
||||
_repoDetail = repoDetail;
|
||||
_repoSong2 = repoSong2;
|
||||
}
|
||||
|
||||
[Transactional]
|
||||
public virtual void Test1()
|
||||
{
|
||||
//这里 _repoSong、_repoDetail、_repoSong2 所有操作都是一个工作单元
|
||||
this.Test2();
|
||||
}
|
||||
|
||||
[Transactional(Propagation = Propagation.Nested)]
|
||||
public virtual void Test2() //嵌套事务,新的(不使用 Test1 的事务)
|
||||
{
|
||||
//这里 _repoSong、_repoDetail、_repoSong2 所有操作都是一个工作单元
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
是不是进方法就开事务呢?
|
||||
|
||||
不一定是真实事务,有可能是虚的,就是一个假的 unitofwork(不带事务)
|
||||
|
||||
也有可能是延用上一次的事务
|
||||
|
||||
也有可能是新开事务,具体要看传播模式
|
||||
@@ -1,141 +0,0 @@
|
||||
**中文** | [English](Unit-of-Work-Manager)
|
||||
|
||||
## ASP.NET Core下FreeSql的仓储事务
|
||||
#### 第一步:配置 Startup.cs 注入
|
||||
引入包
|
||||
```bash
|
||||
dotnet add package FreeSql
|
||||
dotnet add package FreeSql.DbContext
|
||||
dotnet add package FreeSql.Provider.MySqlConnector
|
||||
```
|
||||
配置 Startup.cs 注入
|
||||
```csharp
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
IConfigurationSection Mysql = Configuration.GetSection("Mysql");
|
||||
Fsql = new FreeSqlBuilder()
|
||||
.UseConnectionString(DataType.MySql, Mysql.Value)
|
||||
.UseAutoSyncStructure(true)
|
||||
.UseNameConvert(NameConvertType.PascalCaseToUnderscoreWithLower)
|
||||
.UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText))
|
||||
.Build();
|
||||
services.AddSingleton<IFreeSql>(fsql);
|
||||
services.AddScoped<UnitOfWorkManager>();
|
||||
services.AddFreeRepository(null, typeof(Startup).Assembly);
|
||||
//新增自己的服务,这里只有实现
|
||||
services.AddScoped<TransBlogService>();
|
||||
}
|
||||
```
|
||||
|
||||
- appsettings.json
|
||||
```json
|
||||
{
|
||||
"Mysql": "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=ovov_freesql_repository;Charset=utf8;SslMode=none;Max pool size=10",
|
||||
}
|
||||
```
|
||||
|
||||
| UnitOfWorkManager 成员 | 说明 |
|
||||
| -- | -- |
|
||||
| IUnitOfWork Current | 返回当前的工作单元 |
|
||||
| void Binding(repository) | 将仓储的事务交给它管理 |
|
||||
| IUnitOfWork Begin(propagation, isolationLevel) | 创建工作单元 |
|
||||
|
||||
|
||||
- TransBlogService.cs
|
||||
```csharp
|
||||
private readonly IBaseRepository<Blog, int> _blogRepository;
|
||||
private readonly IBaseRepository<Tag, int> _tagRepository;
|
||||
private readonly UnitOfWorkManager _unitOfWorkManager;
|
||||
|
||||
public TransBlogService(IBaseRepository<Blog, int> blogRepository, IBaseRepository<Tag, int> tagRepository,UnitOfWorkManager unitOfWorkManager)
|
||||
{
|
||||
_blogRepository = blogRepository ;
|
||||
_tagRepository = tagRepository ;
|
||||
_unitOfWorkManager = unitOfWorkManager;
|
||||
}
|
||||
|
||||
public async Task CreateBlogUnitOfWorkAsync(Blog blog,List<Tag>tagList)
|
||||
{
|
||||
using (IUnitOfWork unitOfWork = _unitOfWorkManager.Begin())
|
||||
{
|
||||
try
|
||||
{
|
||||
await _blogRepository.InsertAsync(blog);
|
||||
tagList.ForEach(r =>
|
||||
{
|
||||
r.PostId = blog.Id;
|
||||
});
|
||||
await _tagRepository.InsertAsync(tagList);
|
||||
unitOfWork.Commit();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//实际 可以不Rollback。因为IUnitOfWork内部Dispose,会把没有Commit的事务Rollback回来,但能提前Rollback
|
||||
|
||||
unitOfWork.Rollback();
|
||||
//记录日志、或继续throw;出来
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateBlogAsync(int id)
|
||||
{
|
||||
using (IUnitOfWork unitOfWork = _unitOfWorkManager.Begin())
|
||||
{
|
||||
try
|
||||
{
|
||||
Blog blog = _blogRepository.Select.Where(r => r.Id == id).First();
|
||||
blog.IsDeleted = true;
|
||||
await _blogRepository.UpdateAsync(blog);
|
||||
unitOfWork.Commit();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//记录日志、或继续throw;出来
|
||||
unitOfWork.Rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
| IUnitOfWork 成员 | 说明 |
|
||||
| -- | -- |
|
||||
| IFreeSql Orm | 该对象 Select/Delete/Insert/Update/InsertOrUpdate 与工作单元事务保持一致,可省略传递 WithTransaction |
|
||||
| DbTransaction GetOrBeginTransaction() | 开启事务,或者返回已开启的事务 |
|
||||
| void Commit() | 提交事务 |
|
||||
| void Rollback()| 回滚事务 |
|
||||
| DbContext.EntityChangeReport EntityChangeReport |工作单元内的实体变化跟踪 |
|
||||
|
||||
#### 完整的代码
|
||||
- [Blog.cs](https://github.com/luoyunchong/dotnetcore-examples/blob/master/ORM/FreeSql/OvOv.Core/Domain/Blog.cs)
|
||||
- [Tag.cs](https://github.com/luoyunchong/dotnetcore-examples/blob/master/ORM/FreeSql/OvOv.Core/Domain/Tag.cs)
|
||||
- [TransBlogService.cs](https://github.com/luoyunchong/dotnetcore-examples/blob/master/ORM/FreeSql/OvOv.FreeSql.AutoFac.DynamicProxy/Services/TransBlogService.cs)
|
||||
|
||||
以上使用的是泛型仓储,那我们如果是重写一个仓储 如何保持和``UnitOfWorkManager``同一个事务呢。
|
||||
继承现有的``DefaultRepository<,>``仓储,实现自定义的仓储``BlogRepository.cs``,
|
||||
```csharp
|
||||
public class BlogRepository : DefaultRepository<Blog, int>, IBlogRepository
|
||||
{
|
||||
public BlogRepository(UnitOfWorkManager uowm) : base(uowm?.Orm, uowm)
|
||||
{
|
||||
}
|
||||
|
||||
public List<Blog> GetBlogs()
|
||||
{
|
||||
return Select.Page(1, 10).ToList();
|
||||
}
|
||||
}
|
||||
```
|
||||
其中接口。``IBlogRepository.cs``
|
||||
```csharp
|
||||
public interface IBlogRepository : IBaseRepository<Blog, int>
|
||||
{
|
||||
List<Blog> GetBlogs();
|
||||
}
|
||||
```
|
||||
|
||||
在 startup.cs注入此服务
|
||||
```csharp
|
||||
services.AddScoped<IBlogRepository, BlogRepository>();
|
||||
```
|
||||
@@ -1,156 +0,0 @@
|
||||
[中文](DI-UnitOfWorkManager%E4%BA%8B%E5%8A%A1) | **English**
|
||||
|
||||
## Use FreeSql's repository transaction in ASP.NET Core
|
||||
|
||||
#### Step 1: Configure Startup.cs
|
||||
|
||||
Install NuGet packages:
|
||||
|
||||
```bash
|
||||
dotnet add package FreeSql
|
||||
dotnet add package FreeSql.DbContext
|
||||
dotnet add package FreeSql.Provider.MySqlConnector
|
||||
```
|
||||
|
||||
Configure `Startup.cs`:
|
||||
|
||||
```csharp
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
IConfigurationSection Mysql = Configuration.GetSection("Mysql");
|
||||
Fsql = new FreeSqlBuilder()
|
||||
.UseConnectionString(DataType.MySql, Mysql.Value)
|
||||
.UseAutoSyncStructure(true)
|
||||
.UseNameConvert(NameConvertType.PascalCaseToUnderscoreWithLower)
|
||||
.UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText))
|
||||
.Build();
|
||||
services.AddSingleton<IFreeSql>(fsql);
|
||||
services.AddScoped<UnitOfWorkManager>();
|
||||
services.AddFreeRepository(null, typeof(Startup).Assembly);
|
||||
//Add your own service, here is only an implementation
|
||||
services.AddScoped<TransBlogService>();
|
||||
}
|
||||
```
|
||||
|
||||
Update your `appsettings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"Mysql": "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=ovov_freesql_repository;Charset=utf8;SslMode=none;Max pool size=10",
|
||||
}
|
||||
```
|
||||
|
||||
| UnitOfWorkManager Members | Description |
|
||||
| -- | -- |
|
||||
| IUnitOfWork Current | Return the current unit of work |
|
||||
| void Binding(repository) | Hand over repository transaction to ir for management |
|
||||
| IUnitOfWork Begin(propagation, isolationLevel) | Create unit of work |
|
||||
|
||||
|
||||
- TransBlogService.cs
|
||||
```csharp
|
||||
private readonly IBaseRepository<Blog, int> _blogRepository;
|
||||
private readonly IBaseRepository<Tag, int> _tagRepository;
|
||||
private readonly UnitOfWorkManager _unitOfWorkManager;
|
||||
|
||||
public TransBlogService(IBaseRepository<Blog, int> blogRepository, IBaseRepository<Tag, int> tagRepository,UnitOfWorkManager unitOfWorkManager)
|
||||
{
|
||||
_blogRepository = blogRepository ;
|
||||
_tagRepository = tagRepository ;
|
||||
_unitOfWorkManager = unitOfWorkManager;
|
||||
}
|
||||
|
||||
public async Task CreateBlogUnitOfWorkAsync(Blog blog,List<Tag>tagList)
|
||||
{
|
||||
using (IUnitOfWork unitOfWork = _unitOfWorkManager.Begin())
|
||||
{
|
||||
try
|
||||
{
|
||||
await _blogRepository.InsertAsync(blog);
|
||||
tagList.ForEach(r =>
|
||||
{
|
||||
r.PostId = blog.Id;
|
||||
});
|
||||
await _tagRepository.InsertAsync(tagList);
|
||||
unitOfWork.Commit();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//Actually, Rollback may not be used.
|
||||
//Because the internal Dispose of IUnitOfWork will roll back the transaction without Commit.
|
||||
//But here can be Rollback in advance.
|
||||
|
||||
unitOfWork.Rollback();
|
||||
//Log,
|
||||
//or use throw to continue throwing exceptions upwards
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateBlogAsync(int id)
|
||||
{
|
||||
using (IUnitOfWork unitOfWork = _unitOfWorkManager.Begin())
|
||||
{
|
||||
try
|
||||
{
|
||||
Blog blog = _blogRepository.Select.Where(r => r.Id == id).First();
|
||||
blog.IsDeleted = true;
|
||||
await _blogRepository.UpdateAsync(blog);
|
||||
unitOfWork.Commit();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//Log,
|
||||
//or use throw to continue throwing exceptions upwards
|
||||
unitOfWork.Rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
| IUnitOfWork Members | Description |
|
||||
| -- | -- |
|
||||
| IFreeSql Orm | The object Select/Delete/Insert/Update/InsertOrUpdate is consistent with the unit of work transaction and can be omitted to pass WithTransaction |
|
||||
| DbTransaction GetOrBeginTransaction() | Open the transaction, or return to the opened transaction |
|
||||
| void Commit() | Commit transaction |
|
||||
| void Rollback()| Rollback transaction |
|
||||
| DbContext.EntityChangeReport EntityChangeReport |Entity change tracking within the unit of work |
|
||||
|
||||
#### Complete code
|
||||
- [Blog.cs](https://github.com/luoyunchong/dotnetcore-examples/blob/master/ORM/FreeSql/OvOv.Core/Domain/Blog.cs)
|
||||
- [Tag.cs](https://github.com/luoyunchong/dotnetcore-examples/blob/master/ORM/FreeSql/OvOv.Core/Domain/Tag.cs)
|
||||
- [TransBlogService.cs](https://github.com/luoyunchong/dotnetcore-examples/blob/master/ORM/FreeSql/OvOv.FreeSql.AutoFac.DynamicProxy/Services/TransBlogService.cs)
|
||||
|
||||
The above uses generic repository.
|
||||
|
||||
If you want to rewrite a repository, how do you keep the same transaction as `UnitOfWorkManager`? You can inherit the existing `DefaultRepository<,>` and implement a custom repository `BlogRepository.cs`:
|
||||
|
||||
```csharp
|
||||
public class BlogRepository : DefaultRepository<Blog, int>, IBlogRepository
|
||||
{
|
||||
public BlogRepository(UnitOfWorkManager uowm) : base(uowm?.Orm, uowm)
|
||||
{
|
||||
}
|
||||
|
||||
public List<Blog> GetBlogs()
|
||||
{
|
||||
return Select.Page(1, 10).ToList();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The interface is `IBlogRepository.cs`:
|
||||
|
||||
```csharp
|
||||
public interface IBlogRepository : IBaseRepository<Blog, int>
|
||||
{
|
||||
List<Blog> GetBlogs();
|
||||
}
|
||||
```
|
||||
|
||||
Inject this service in `startup.cs`
|
||||
|
||||
```csharp
|
||||
services.AddScoped<IBlogRepository, BlogRepository>();
|
||||
```
|
||||
@@ -33,7 +33,7 @@ using (var uow = fsql.CreateUnitOfWork())
|
||||
}
|
||||
```
|
||||
|
||||
Reference: [Use TransactionalAttribute + UnitOfWorkManager in ASP.NET Core to achieve multiple transaction propagation](https://github.com/dotnetcore/FreeSql/issues/289)
|
||||
Reference: [Use TransactionalAttribute + UnitOfWorkManager in ASP.NET Core to achieve multiple transaction propagation](DI-UnitOfWorkManager)
|
||||
|
||||
## Interface Definition
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
* [工作单元](%e5%b7%a5%e4%bd%9c%e5%8d%95%e5%85%83) [Unit of Work](Unit-of-Work)
|
||||
* [联级保存](%e8%81%94%e7%ba%a7%e4%bf%9d%e5%ad%98) [Cascade Saving](Cascade-Saving)
|
||||
* [联级删除](%E8%81%94%E7%BA%A7%E5%88%A0%E9%99%A4) [Cascade Deletion](Cascade-Deletion)
|
||||
* [工作单元管理器](DI-UnitOfWorkManager事务) [UoW Manager](Unit-of-Work-Manager)
|
||||
* [工作单元管理器](DI-UnitOfWorkManager)
|
||||
* [DbContext](DbContext)
|
||||
* [CodeFirst](CodeFirst)
|
||||
* [实体特性✨](%e5%ae%9e%e4%bd%93%e7%89%b9%e6%80%a7)
|
||||
|
||||
4
事务.md
4
事务.md
@@ -1,6 +1,6 @@
|
||||
本文所有内容基于单机数据库事务,分布式数据库 TCC/SAGA 方案请移步:https://github.com/2881099/FreeSql.Cloud
|
||||
|
||||
## 0、[ASP.NET Core配置DI使用UnitOfWorkManager,此方法更简单](DI-UnitOfWorkManager事务)
|
||||
## 0、[ASP.NET Core配置DI使用UnitOfWorkManager,此方法更简单](DI-UnitOfWorkManager)
|
||||
|
||||
## 1、UnitOfWork 事务
|
||||
|
||||
@@ -24,8 +24,6 @@ using (var uow = fsql.CreateUnitOfWork())
|
||||
}
|
||||
```
|
||||
|
||||
参考:[在 asp.net core 中使用 TransactionalAttribute + UnitOfWorkManager 实现多种事务传播](https://github.com/dotnetcore/FreeSql/issues/289)
|
||||
|
||||
## 2、DbContext 事务
|
||||
|
||||
```csharp
|
||||
|
||||
18
常见问题.md
18
常见问题.md
@@ -36,13 +36,7 @@ fsql.Aop.ConfigEntityProperty += (s, e) => {
|
||||
|
||||
---
|
||||
|
||||
### 4、TransactionalAttribute + UnitOfWorkManager 事务传播
|
||||
|
||||
[https://github.com/dotnetcore/FreeSql/issues/289](https://github.com/dotnetcore/FreeSql/issues/289)
|
||||
|
||||
---
|
||||
|
||||
### 5、怎么执行 SQL 返回实体列表?
|
||||
### 4、怎么执行 SQL 返回实体列表?
|
||||
|
||||
```csharp
|
||||
//直接查询
|
||||
@@ -57,25 +51,25 @@ fsql.Select<T>().WithMemory(list).ToList();
|
||||
|
||||
---
|
||||
|
||||
### 6、错误:【主库】状态不可用,等待后台检查程序恢复方可使用。xxx
|
||||
### 5、错误:【主库】状态不可用,等待后台检查程序恢复方可使用。xxx
|
||||
|
||||
[https://github.com/dotnetcore/FreeSql/discussions/1080](https://github.com/dotnetcore/FreeSql/discussions/1080)
|
||||
|
||||
---
|
||||
|
||||
### 7、错误:【主库】对象池已释放,无法访问。
|
||||
### 6、错误:【主库】对象池已释放,无法访问。
|
||||
|
||||
[https://github.com/dotnetcore/FreeSql/discussions/1079](https://github.com/dotnetcore/FreeSql/discussions/1079)
|
||||
|
||||
---
|
||||
|
||||
### 8、错误:ObjectPool.Get 获取超时(10秒)。
|
||||
### 7、错误:ObjectPool.Get 获取超时(10秒)。
|
||||
|
||||
[https://github.com/dotnetcore/FreeSql/discussions/1081](https://github.com/dotnetcore/FreeSql/discussions/1081)
|
||||
|
||||
---
|
||||
|
||||
### 9、多平台代码参考,使用自定义SqliteProvider,例如Sqlite用Microsoft.Data.Sqlite或者反射Mono.Data.Sqlite.
|
||||
### 8、多平台代码参考,使用自定义SqliteProvider,例如Sqlite用Microsoft.Data.Sqlite或者反射Mono.Data.Sqlite.
|
||||
|
||||
[arm/树莓派](https://github.com/densen2014/FreeSqlDemos/tree/master/ARM_ConsoleApp)
|
||||
|
||||
@@ -131,7 +125,7 @@ if (Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.And
|
||||
|
||||
---
|
||||
|
||||
### 10、 2.6.100升级到3.0.100 后无法连接 sqlserver 提示证书无效, 提示证书链是由不受信任的颁发机构颁发的.
|
||||
### 9、 2.6.100升级到3.0.100 后无法连接 sqlserver 提示证书无效, 提示证书链是由不受信任的颁发机构颁发的.
|
||||
|
||||
请尝试:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user