热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

乘风破浪,遇见最佳跨平台跨终端框架.NetCore/.Net生态–MYSQL主从实例+EntityFrameworkCore实现读写分离之实战演练

前言之前写过一篇《乘风破浪,遇见云原生(CloudNative)之DockerDesktopforWindows运行MYSQL多实例并实现主从(Master-Slave)部署》,实

前言

之前写过一篇《乘风破浪,遇见云原生(Cloud Native)之Docker Desktop for Windows 运行MYSQL多实例并实现主从(Master-Slave)部署》,实现了MYSQL主从多实例部署,基于它我们来写一写怎么在Entity Framework Core的配合下实现读写分离,我们通过MediatR来实现CQRS架构设计。


业务背景

某车企开展引荐活动送积分,需要提供一个服务对引荐信息进行管理,通过API接口提供引荐信息的管理能力。

image

简单架构示意图


涉及组件



  • MediatR

  • EntityFrameworkCore

  • Swashbuckle

  • MySqlConnector

  • Newtonsoft.Json


解决方案和分层


https://github.com/TaylorShi/HelloEfCoreMasterSlave


dotnet new sln -o HelloEfCoreMasterSlave

这里我们将采用面向领域驱动设计(DDD)的模式,先将解决方案中项目完成分组:



  • 0.Shared 共享项目,定义业务无关的基础代码和接口定义

  • 1.Infrastructure 基础层,定义仓储、Context

  • 2.Domain 领域层,定义领域模式和领域事件

  • 3.Application 应用层,定义命令和处理程序,协调调度任务

  • 4.Api 应用入口,定义API终结点、验证

  • 5.Test 应用测试,定义API终结点、验证

image


共享项目


Framework.Core

这里面放一些公共的代码,比如全局的已知异常定义IKnowException和实现类KnowException

image


Framework.Domain.Abstractions


领域抽象项目,这里定义包括:




  • IAggregateRoot 聚合根接口

  • IEntityIEntity 实体接口

  • EntityEntity 实体抽象类

  • IDomainEvent 领域事件接口,继承自MediatR.INotification

  • IDomainEventHandler 领域事件处理程序,继承自INotificationHandler

  • ValueObject 值对象


依赖包


dotnet add package MediatR.Extensions.Microsoft.DependencyInjection --version 8.0.0

MediatR.Extensions.Microsoft.DependencyInjection其内部包括




  • MediatR

  • Microsoft.Extensions.DependencyInjection.Abstractions


Framework.Infrastructure.Core


基础层核心项目,这里分组包括




  • Behaviors 行为管理

  • Contexts 上下文管理

  • Extensions 扩展管理

  • Repositorys 仓储管理

  • Transactions 事务管理


行为管理组包括




  • TransactionBehavior 事务行为管理类,继承自IPipelineBehavior,用于命令执行前后添加事务策略。


上下文管理组包括




  • EFContext Entity Framework Core上下文


扩展管理组包括




  • GenericTypeExtensions 通用类型扩展

  • DomainEventExtension 领域事务扩展

  • QueryableExtensions LINQ查询扩展


仓储管理组包括




  • IRepository 实体接口,继承自实体抽象类Entity和聚合根接口IAggregateRoot

  • Repository 实体抽象类,继承自实体接口IRepository、实体抽象类Entity和聚合根接口IAggregateRoot


事务管理组包括




  • ITransaction 事务管理接口

  • IUnitOfWork 工作单元接口


依赖包


dotnet add package Microsoft.EntityFrameworkCore.Relational --version 3.1.0

Microsoft.EntityFrameworkCore.Relational其内部包括




  • Microsoft.EntityFrameworkCore

  • Microsoft.EntityFrameworkCore.Abstractions

  • Microsoft.EntityFrameworkCore.Analyzers


依赖项目




  • Framework.Domain.Abstractions


基础层


Referral.Infrastructure


基础层项目,这里分组包括




  • Contexts 上下文管理

  • EntityConfigurations 实体配置

  • Repositories 实体仓储


上下文管理组包括




  • ReferralContextTransactionBehavior 领域事务行为管理类

  • ReferralMasterContext 业务MasterContext,继承自Entity Framework Core上下文EFContext,代表MYSQL主实例的Context

  • ReferralSlaveContext 业务SlaveContext,继承自Entity Framework Core上下文DbContext,代表MYSQL从实例的Context


实体配置组包括




  • ReferralCodeEntityTypeConfiguration 业务领域模型和实体类型配置类,继承自Entity Framework Core实体配置接口IEntityTypeConfiguration


实体仓储组包括




  • IReferralCodeRepository 业务领域仓储接口,继承自实体接口IRepository

  • ReferralCodeRepository 业务领域仓储类,继承自实体抽象类Repository和业务领域仓储接口IReferralCodeRepository


依赖项目




  • Framework.Infrastructure.Core

  • Referral.Domain


领域层


Referral.Domain


领域层项目,这里分组包括




  • Events 领域事件

  • Aggregates 领域模型


领域模型组包括




  • ReferralCode 业务领域模型,继承自实体抽象类Entity和聚合根接口IAggregateRoot


依赖项目




  • Framework.Domain.Abstractions


应用层


Referral.Application


应用层项目,这里分组包括




  • Commands 命令和处理

  • DomainEventHandlers 领域事件处理

  • IntegrationEvents 集成事件定义

  • Queries 查询和处理

  • Extensions 服务扩展


命令和处理组包括




  • CreateReferralCommand 创建引荐命令定义,继承自MediatR命令请求接口IRequest

  • CreateReferralCommandHandler 创建引荐命令处理,继承自MediatR命令处理接口IRequestHandler

  • DeleteReferralCommand 删除引荐命令定义,继承自MediatR命令请求接口IRequest

  • DeleteReferralCommandHandler 删除引荐命令处理,继承自MediatR命令处理接口IRequestHandler

  • ModifyReferralCommand 修改引荐命令定义,继承自MediatR命令请求接口IRequest

  • ModifyReferralCommandHandler 修改引荐命令处理,继承自MediatR命令处理接口IRequestHandler


查询和处理组包括




  • QueryReferralCommand 查询引荐命令定义,继承自MediatR命令请求接口IRequest

  • QueryReferralCommandHandler 查询引荐命令处理,继承自MediatR命令处理接口IRequestHandler


服务扩展组包括




  • CommandHandlerExtensions 命令处理扩展

  • EFContextExtensions EF上下文扩展

  • IntegrationEventsExtensions 集成事件扩展

  • RepositoryExtensions 仓储服务扩展


依赖包


dotnet add package Pomelo.EntityFrameworkCore.MySql --version 3.1.0

Pomelo.EntityFrameworkCore.MySql其内部包括




  • Microsoft.EntityFrameworkCore.Relational

  • Microsoft.EntityFrameworkCore

  • MySqlConnector

  • Pomelo.JsonObject

  • Newtonsoft.Json


依赖项目




  • Referral.Infrastructure


应用入口


Referral.Api


应用入口项目,这里分组包括




  • Controllers API终结点

  • Extensions 扩展


API终结点组包括




  • ReferralController 业务服务终结点


扩展组包括




  • ApplicationUseExtensions 应用启用扩展

  • RoutingEndpointExtensions 路由和终结点扩展


依赖项目




  • Referral.Application


依赖包


dotnet add package Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer --version 5.0.0

Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer其内部包括




  • Microsoft.AspNetCore.Mvc.Versioning

dotnet add package Swashbuckle.AspNetCore --version 6.4.0

Swashbuckle.AspNetCore其内部包括




  • Microsoft.Extensions.ApiDescription.Server

  • Swashbuckle.AspNetCore.Swagger

  • Swashbuckle.AspNetCore.SwaggerGen

  • Swashbuckle.AspNetCore.SwaggerUI

  • Microsoft.OpenApi


实现读写分离


注册多实例上下文

Referral.Infrastructure中,我们构建了两个业务Context,每一个Context会对应一个MYSQL的ConnectionString

我们首先需要将Master和Slave两个节点的连接字符串在appsettings.json中配置出来。

{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"MYSQL-Master": "server=localhost;port=16000;user=root;password=xxxxxxxxxxxxxxx;database=xxxx;charset=utf8mb4;COnnectionReset=false;",
"MYSQL-Slave": "server=localhost;port=17001;user=root;password=xxxxxxxxxxxxxxx;database=xxxx;charset=utf8mb4;COnnectionReset=false;"
}

注意,配置节点名称分别是MYSQL-MasterMYSQL-Slave,它们的端口是不一样的。

接下来,在Startup.csConfigureServices中添加MYSQL集群上下文服务AddMySqlClusterContext

public void ConfigureServices(IServiceCollection services)
{
// 添加MYSQL集群上下文服务
services.AddMySqlClusterContext(Configuration.GetValue("MYSQL-Master"), Configuration.GetValue("MYSQL-Slave"));
}

位于EF上下文扩展EFContextExtensions中的AddMySqlClusterContext定义

///


/// EF上下文扩展
///

public static class EFContextExtensions
{
///
/// 添加MYSQL集群上下文服务
///

///


///


///


///
public static IServiceCollection AddMySqlClusterContext(this IServiceCollection services, string masterConnectionString, string slaveConnectionString)
{
// 添加引荐MasterContext
services.AddDbContext(optiOnsAction=>
{
optionsAction.UseMySql(masterConnectionString);
});
// 添加引荐SlaveContext
services.AddDbContext(optiOnsAction=>
{
optionsAction.UseMySql(slaveConnectionString);
});
return services;
}
}

这个我们就分开注册了两个不同的MYSQL实例,其中一个Master用于写,另外一个Slave用于读。


基于MediatR实现CQRS模式

Referral.Api,我们定义了一个业务终结点ReferralController

///


/// 引荐服务
///

[ApiVersion("1.0")]
[Route("api/v{version:ApiVersion}/[controller]/[action]")]
[ApiController]
public class ReferralController : ControllerBase
{
readonly IMediator _mediator;
///
/// 构造函数
///

///


public ReferralController(IMediator mediator)
{
_mediator = mediator;
}
///


/// 创建引荐
///

///


///
[HttpPost]
public async Task Create([FromBody]CreateReferralCommand cmd)
{
// 发送创建引荐的命令
return Ok(await _mediator.Send(cmd, HttpContext.RequestAborted));
}
///


/// 修改引荐
///

///


///
[HttpPost]
public async Task Modify([FromBody]ModifyReferralCommand cmd)
{
// 发送修改引荐的命令
return Ok(await _mediator.Send(cmd, HttpContext.RequestAborted));
}
///


/// 删除引荐
///

///


///
[HttpPost]
public async Task Delete([FromBody]DeleteReferralCommand cmd)
{
// 发送修改引荐的命令
return Ok(await _mediator.Send(cmd, HttpContext.RequestAborted));
}
///


/// 查询引荐
///

///


///
[HttpGet]
public async Task Query([FromQuery]QueryReferralCommand cmd)
{
// 发送查询引荐的命令
return Ok(await _mediator.Send(cmd, HttpContext.RequestAborted));
}
}

这里全部通过MediatR将来自前端的请求通过命令的方式发送出去,等待命令被处理之后,再将结果返回给调用者,实现CQRS模式。


领域模型设计

这个案例中,我们仅设计了一个引荐代码的领域模型ReferralCode

///


/// 引荐代码领域模型
///

public class ReferralCode : Entity, IAggregateRoot
{
///
/// 引荐名称
///

public string Name { get; private set; }
///
/// 引荐代码
///

public string Code { get; private set; }
///
/// 构造函数
///

///


///


public ReferralCode(string name, string code)
{
Name = name;
Code = code;
}
///


/// 修改
///

///


///


public void Modify(string name, string code)
{
Name = name;
Code = code;
}
}

基于封闭原则,所有的Set都被设置为Private,创建通过构造函数来进行,修改通过独立的Modify进行。

Referral.Infrastructure中关于领域模型和实体的映射关系,我们是这样的设计的

///


/// 引荐代码领域模型和实体类型配置类
///

internal class ReferralCodeEntityTypeConfiguration : IEntityTypeConfiguration
{
public void Configure(EntityTypeBuilder builder)
{
builder.HasKey(p => p.Id);
builder.ToTable("referralcode");
builder.Property(p => p.Name).HasMaxLength(120);
builder.Property(p => p.Code).HasMaxLength(200);
}
}

创建引荐命令和处理


创建引荐命令定义


///


/// 创建引荐命令定义
///

public class CreateReferralCommand : IRequest
{
///
/// 引荐名称
///

public string Name { get; set; }
///
/// 引荐代码
///

public string Code { get; set; }
}

创建引荐命令处理


///


/// 创建引荐命令处理
///

internal class CreateReferralCommandHandler : IRequestHandler
{
///
/// 引荐代码仓储
///

readonly IReferralCodeRepository _referralCodeRepository;
///
/// 构造函数
///

///


public CreateReferralCommandHandler(IReferralCodeRepository referralCodeRepository)
{
_referralCodeRepository = referralCodeRepository;
}
///


/// 处理程序
///

///


///


///
public async Task Handle(CreateReferralCommand request, CancellationToken cancellationToken)
{
var referralCode = new ReferralCode(request.Name, request.Code);
await _referralCodeRepository.AddAsync(referralCode, cancellationToken);
return true;
}
}

这里从容器中获取业务仓储实例_referralCodeRepository,通过它的AddAsync方法实现添加动作。


删除引荐命令和处理


删除引荐命令定义


///


/// 删除引荐命令定义
///

public class DeleteReferralCommand : IRequest
{
///
/// 引荐ID
///

public int Id { get; set; }
}

删除引荐命令处理


///


/// 删除引荐命令处理
///

internal class DeleteReferralCommandHandler : IRequestHandler
{
///
/// 引荐代码仓储
///

readonly IReferralCodeRepository _referralCodeRepository;
///
/// 构造函数
///

///


public DeleteReferralCommandHandler(IReferralCodeRepository referralCodeRepository)
{
_referralCodeRepository = referralCodeRepository;
}
///


/// 处理程序
///

///


///


///
public async Task Handle(DeleteReferralCommand request, CancellationToken cancellationToken)
{
return await _referralCodeRepository.DeleteAsync(request.Id);
}
}

这里从容器中获取业务仓储实例_referralCodeRepository,通过它的DeleteAsync方法实现删除动作。


修改引荐命令和处理


修改引荐命令定义


///


/// 修改引荐命令定义
///

public class ModifyReferralCommand : IRequest
{
///
/// 引荐ID
///

public int Id { get; set; }
///
/// 引荐名称
///

public string Name { get; set; }
///
/// 引荐代码
///

public string Code { get; set; }
}

修改引荐命令处理


///


/// 修改引荐命令处理
///

internal class ModifyReferralCommandHandler : IRequestHandler
{
///
/// 引荐代码仓储
///

readonly IReferralCodeRepository _referralCodeRepository;
///
/// 构造函数
///

///


public ModifyReferralCommandHandler(IReferralCodeRepository referralCodeRepository)
{
_referralCodeRepository = referralCodeRepository;
}
///


/// 处理程序
///

///


///


///
public async Task Handle(ModifyReferralCommand request, CancellationToken cancellationToken)
{
var referralCode = await _referralCodeRepository.GetAsync(request.Id, cancellationToken);
if (referralCode != null)
{
referralCode.Modify(request.Name, request.Code);
await _referralCodeRepository.UpdateAsync(referralCode);
return true;
}
return false;
}
}

这里从容器中获取业务仓储实例_referralCodeRepository,先通过GetAsync查询要修改的数据是否存在,如果存在那么通过UpdateAsync更新它。


查询引荐命令处理


查询引荐命令定义


///


/// 查询引荐命令定义
///

public class QueryReferralCommand : IRequest>
{
///
/// 引荐ID
///

public int Id { get; set; }
///
/// 引荐名称
///

public string Name { get; set; }
///
/// 引荐代码
///

public string Code { get; set; }
}

查询引荐命令处理


///


/// 查询引荐命令处理
///

public class QueryReferralCommandHandler : IRequestHandler>
{
readonly ReferralSlaveContext _referralSlaveContext;
///
/// 构造函数
///

///


public QueryReferralCommandHandler(ReferralSlaveContext referralSlaveContext)
{
_referralSlaveCOntext= referralSlaveContext;
}
///


/// 处理程序
///

///


///


///
public async Task> Handle(QueryReferralCommand request, CancellationToken cancellationToken)
{
IQueryable query = _referralSlaveContext.ReferralCodes;
if (request.Id > 0)
{
query = query.Where(x => x.Id == request.Id);
}
if (!string.IsNullOrEmpty(request.Name))
{
query = query.Where(x => x.Name == request.Name);
}
if (!string.IsNullOrEmpty(request.Code))
{
query = query.Where(x => x.Code == request.Code);
}
return await query.ToListAsync();
}
}

这里从容器中获取SlaveContext实例_referralSlaveContext,通过判断查询入参的条件来拼接IQueryable,最后通过ToListAsync获取筛选结果。

但是上面这种写法有点啰嗦,我们引入一个LINQ查询扩展QueryableExtensions以便优化它。

///


/// LINQ查询扩展
///

public static class QueryableExtensions
{
///
/// 分页查询
///

///
///


///


///


///
///
public static IQueryable PageBy(this IQueryable query, int skipCount, int maxResultCount)
{
if (query == null)
{
throw new ArgumentNullException("query");
}
return query.Skip(skipCount).Take(maxResultCount);
}
///


/// 根据If条件筛选
///

///
///


///


///


///
public static IQueryable WhereIf(this IQueryable query, bool condition, Expression> predicate)
{
return condition
? query.Where(predicate)
: query;
}
///


/// 根据If条件筛选
///

///
///


///


///


///
public static IQueryable WhereIf(this IQueryable query, bool condition, Expression> predicate)
{
return condition
? query.Where(predicate)
: query;
}
}

最终我们可以将前面的查询优化为如下的写法

///


/// 处理程序
///

///


///


///
public async Task> Handle(QueryReferralCommand request, CancellationToken cancellationToken)
{
IQueryable query = _referralSlaveContext.ReferralCodes
.WhereIf(request.Id > 0, x => x.Id == request.Id)
.WhereIf(!string.IsNullOrEmpty(request.Name), x => x.Name == request.Name)
.WhereIf(!string.IsNullOrEmpty(request.Code), x => x.Code == request.Code);
return await query.ToListAsync();
}

自动事务加持

通过MediatR实现命令和查询分离的同时,其实我们还做了一个自动事务的设计,它有个类似中间件的逻辑,我们在Referral.Application中定义了一个命令处理扩展CommandHandlerExtensions,我们看下它的定义

///


/// 命令处理扩展
///

public static class CommandHandlerExtensions
{
///
/// 添加命令处理服务
///

///


///
public static IServiceCollection AddCommandHandlers(this IServiceCollection services)
{
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ReferralContextTransactionBehavior<,>));
return services.AddMediatR(typeof(ReferralCode).Assembly, typeof(CreateReferralCommand).Assembly);
}
}

这里将ReferralContextTransactionBehavior<,>注册为IPipelineBehavior<,>的实现。它本质是事务行为管理类TransactionBehavior的实现。

它的处理核心逻辑是

///


/// 处理程序
///

///


///


///


///
public async Task Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate next)
{
var respOnse= default(TResponse);
var typeName = request.GetGenericTypeName();
try
{
// 如果当前开启了事务,那么就继续后面的动作
if (_dbContext.HasActiveTransaction)
{
return await next();
}
var strategy = _dbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
Guid transactionId;
using (var transaction = await _dbContext.BeginTransactionAsync())
using (_logger.BeginScope("TransactionContext:{TransactionId}", transaction.TransactionId))
{
_logger.LogInformation("----- 开始事务 {TransactionId} ({@Command})", transaction.TransactionId, typeName, request);
respOnse= await next();
_logger.LogInformation("----- 提交事务 {TransactionId} {CommandName}", transaction.TransactionId, typeName);
await _dbContext.CommitTransactionAsync(transaction);
transactiOnId= transaction.TransactionId;
}
});
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "处理事务出错 {CommandName} ({@Command})", typeName, request);
throw;
}
}

它的逻辑是在执行命令的处理程序之前先判断上下文是否开启事务,如果没有开启事务就创建一个事务,再来执行命令处理的逻辑,处理完毕之后,再来提交这个事务。


参考



  • 《乘风破浪,遇见云原生(Cloud Native)之Docker Desktop for Windows 运行MYSQL多实例并实现主从(Master-Slave)部署》

  • Get Error : Entity type 'Course' is defined with a single key property, but 2 values were passed to the 'DbSet.Find' method

  • “开源、共享、创新”, 中国最具前景开发者峰会落幕魔都

  • 增删改查,命名

  • 再讲IQueryable,揭开表达式树的神秘面纱

  • .NET 复习笔记 / LINQ,从IQueryable说起

  • .NET 在云原生时代的蜕变,让我在云时代脱颖而出

  • 多语言(Java、.NET、Node.js)混合架构下开源调用链追踪APM项目初步选型

  • China.NETConf2019 - 用ASP.NETCore构建可检测的高可用服务

  • 设计模式之美:Mediator(中介者)



推荐阅读
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 服务器上的操作系统有哪些,如何选择适合的操作系统?
    本文介绍了服务器上常见的操作系统,包括系统盘镜像、数据盘镜像和整机镜像的数量。同时,还介绍了共享镜像的限制和使用方法。此外,还提供了关于华为云服务的帮助中心,其中包括产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题和视频帮助等技术文档。对于裸金属服务器的远程登录,本文介绍了使用密钥对登录的方法,并提供了部分操作系统配置示例。最后,还提到了SUSE云耀云服务器的特点和快速搭建方法。 ... [详细]
  • 解决github访问慢的问题的方法集锦
    本文总结了国内用户在访问github网站时可能遇到的加载慢的问题,并提供了解决方法,其中包括修改hosts文件来加速访问。 ... [详细]
  • 2018深入java目标计划及学习内容
    本文介绍了作者在2018年的深入java目标计划,包括学习计划和工作中要用到的内容。作者计划学习的内容包括kafka、zookeeper、hbase、hdoop、spark、elasticsearch、solr、spring cloud、mysql、mybatis等。其中,作者对jvm的学习有一定了解,并计划通读《jvm》一书。此外,作者还提到了《HotSpot实战》和《高性能MySQL》等书籍。 ... [详细]
  • 如何用JNI技术调用Java接口以及提高Java性能的详解
    本文介绍了如何使用JNI技术调用Java接口,并详细解析了如何通过JNI技术提高Java的性能。同时还讨论了JNI调用Java的private方法、Java开发中使用JNI技术的情况以及使用Java的JNI技术调用C++时的运行效率问题。文章还介绍了JNIEnv类型的使用方法,包括创建Java对象、调用Java对象的方法、获取Java对象的属性等操作。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 一次上线事故,30岁+的程序员踩坑经验之谈
    本文主要介绍了一位30岁+的程序员在一次上线事故中踩坑的经验之谈。文章提到了在双十一活动期间,作为一个在线医疗项目,他们进行了优惠折扣活动的升级改造。然而,在上线前的最后一天,由于大量数据请求,导致部分接口出现问题。作者通过部署两台opentsdb来解决问题,但读数据的opentsdb仍然经常假死。作者只能查询最近24小时的数据。这次事故给他带来了很多教训和经验。 ... [详细]
  • 本文介绍了Hive常用命令及其用途,包括列出数据表、显示表字段信息、进入数据库、执行select操作、导出数据到csv文件等。同时还涉及了在AndroidManifest.xml中获取meta-data的value值的方法。 ... [详细]
  • PeopleSoft安装镜像版本及导入语言包的方法
    本文介绍了PeopleSoft安装镜像的两个版本,分别是VirtualBox虚拟机版本和NativeOS版本,并详细说明了导入语言包的方法。对于Windows版本,可以通过psdmt.exe登录进入,并使用datamover脚本导入语言包。对于Linux版本,同样可以使用命令行方式执行datamover脚本导入语言包。导入语言包后,可以实现多种语言的登录。参考文献提供了相关链接以供深入了解。 ... [详细]
  • 1.脚本功能1)自动替换jar包中的配置文件。2)自动备份老版本的Jar包3)自动判断是初次启动还是更新服务2.脚本准备进入ho ... [详细]
  • (九)Docker常用安装
    一、总体步骤1、搜索镜像2、拉取镜像3、查看镜像4、启动镜像5、停止镜像6、移除镜像二、安装tomcat1、dockerhub上面查找tomcat镜像 dockersearchto ... [详细]
author-avatar
东亚病夫出世_332
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有