.net core出来已经有很长一段时间了,而EentityFrameworkCore(后面简称EFCore)是.net framework的EntityFramework在.net core中的实现,至于EntityFramework是什么,这里就不介绍了。

  本文主要介绍EFCore的CodeFirst方式下的数据迁移。

  

  一、创建项目

  首先创建项目结构如下:

  

  说明:

  EFCoreDemo.EntityFrameworkCore:这个是一个标准类库,主要一些EFCore的一些ORM实体与配置。

  EFCoreDemo.ConsoleApp:这个是一个控制台项目,主要用于使用EFCore的使用,因为一般都是使用WebApi或者MVC,然后后使用三层架构,或者一些其他的架构诸如ABP等,使用仓储等模式使用EFCore,但这里为了简单,直接使用一个控制台程序模拟。

  EFCoreDemo.EntityFrameworkCore.Host:这个也是一个控制台程序,主要用于EFCore的数据迁移。

  于是乎,我们的项目引用关系是:

  EFCoreDemo.ConsoleApp 引用 EFCoreDemo.EntityFrameworkCore

   EFCoreDemo.EntityFrameworkCore.Host 引用 EFCoreDemo.EntityFrameworkCore

 

  二、创建实体及上下文

  对EFCoreDemo.EntityFrameworkCore项目使用nuget安装EFCore所需的包:

   # 如果使用MySql,安装 
  Microsoft.EntityFrameworkCore
Pomelo.EntityFrameworkCore.MySql

  # 如果使用SqlServer,安装
  Microsoft.EntityFrameworkCore  
  Microsoft.EntityFrameworkCore.SqlServer

  这里使用的是MySql

  现在假设我们要创建3张表,用户表(Account),活动表(Activity),活动记录表(ActivityRecord)

  于是我们分别创建3个实体与它对应  

  

    /// <summary>
/// 用户表
/// </summary>
public class Account : BaseEntity
{
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 手机号码
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreationTime { get; set; }
}

用户表

  

    /// <summary>
/// 活动表
/// </summary>
public class Activity : BaseEntity
{
/// <summary>
/// 活动名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public DateTime EndTime { get; set; }
/// <summary>
/// 活动状态
/// </summary>
public int Status { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreationTime { get; set; }
}

活动表

  

    /// <summary>
/// 活动记录表
/// </summary>
public class ActivityRecord : BaseEntity
{
/// <summary>
/// 活动Id
/// </summary>
public int ActivityId { get; set; }
/// <summary>
/// 用户Id
/// </summary>
public int AccountId { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreationTime { get; set; }
}

活动记录表

  其中BaseEntity是一个抽象类,主要用来记录主键Id的,推荐每个表都有单列主键,尽量不要使用复合主键,如果有其他唯一标识,可以使用唯一值索引  

    public abstract class BaseEntity
{
/// <summary>
/// Primary Key
/// </summary>
public int Id { get; set; }
}

  这里设置主键类型是int,当然也可以使用其他数据类型,只需将BaseEntity写成泛型类就可以了,如:  

    public abstract class BaseEntity<T>
{
/// <summary>
/// Primary Key
/// </summary>
public T Id { get; set; }
}

  接下来,创建实体映射配置类,同样的,这里也创建一个基类,基类主要做一些通用的配置:    

    public abstract class BaseEntityTypeConfiguration<TEntity> : IEntityTypeConfiguration<TEntity> where TEntity : class
{
/// <summary>
/// 配置实体类型
/// </summary>
/// <param name="builder"></param>
public virtual void Configure(EntityTypeBuilder<TEntity> builder)
{
//映射表名
builder.ToTable("demo_" + typeof(TEntity).Name.ToLower()); //映射主键
if (typeof(BaseEntity).IsAssignableFrom(typeof(TEntity)))
{
builder.HasKey(nameof(BaseEntity.Id));
builder.Property(nameof(BaseEntity.Id)).ValueGeneratedOnAdd();//自增
} //种子数据
var seeds = this.GetSeeds();
if (seeds != null && seeds.Length > 0)
{
builder.HasData(seeds);
}
} /// <summary>
/// 种子数据
/// </summary>
/// <returns></returns>
public virtual TEntity[] GetSeeds()
{
return new TEntity[0];
}
}

  然后分别对用户表(Account),活动表(Activity),活动记录表(ActivityRecord)三个实体类创建映射配置类  

  

    public class AccountEntityTypeConfiguration : BaseEntityTypeConfiguration<Account>
{
/// <summary>
/// 配置实体类型
/// </summary>
/// <param name="builder"></param>
public override void Configure(EntityTypeBuilder<Account> builder)
{
base.Configure(builder);
} /// <summary>
/// 种子数据
/// </summary>
/// <returns></returns>
public override Account[] GetSeeds()
{
return new Account[] {
new Account(){
Id=1,
Name="admin",
Phone="110",
Age=100,
CreationTime=new DateTime(2020,02,02)//注意,种子数据不要使用DateTime.Now之类的,避免每次都会迁移数据
}
};
}
}

AccountEntityTypeConfiguration

  

    public class ActivityEntityTypeConfiguration : BaseEntityTypeConfiguration<Activity>
{
/// <summary>
/// 配置实体类型
/// </summary>
/// <param name="builder"></param>
public override void Configure(EntityTypeBuilder<Activity> builder)
{
base.Configure(builder);
}
}

ActivityEntityTypeConfiguration

  

    public class ActivityRecordEntityTypeConfiguration : BaseEntityTypeConfiguration<ActivityRecord>
{
/// <summary>
/// 配置实体类型
/// </summary>
/// <param name="builder"></param>
public override void Configure(EntityTypeBuilder<ActivityRecord> builder)
{
base.Configure(builder);
}
}

ActivityRecordEntityTypeConfiguration

  到这里,有些朋友可能会觉着这样做很麻烦,倒不如直接使用特性标识实体类来的简单,但笔者认为,使用特性标识确实简单,但它的局限性太大:

  1、使用特性让实体看起来不干净,而且当描述实体关系时不是很方便

  2、特性功能有限,很多复杂的关系实现不了,而初始化数据也不方便实现

  3、当特性不能满足我们的需求是,我们可能需要将配置移到其他地方去,如DbContext的OnModelCreating方法,这样就造成了配置的分散

  总之,当使用CodeFirst方式开发时,推荐使用单独的映射配置类去实现,尽可能不要使用特性

  接着就可以创建DbContext上下文了:  

    public class DemoDbContext : DbContext
{
public DemoDbContext(DbContextOptions options) : base(options)
{ } #region Method
/// <summary>
/// 配置
/// </summary>
/// <param name="optionsBuilder"></param>
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.EnableSensitiveDataLogging();
base.OnConfiguring(optionsBuilder);
}
/// <summary>
/// 初始化
/// </summary>
/// <param name="modelBuilder"></param>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyFromAssembly(typeof(DemoDbContext));
}
#endregion
}

  这里的DbContext没有创建那些DbSet属性,不表示不能创建,只是为了说明EFCore的迁移不依赖那些而已。

  其中modelBuilder.ApplyFromAssembly是一个拓展方法:  

    public static class EntityFrameworkCoreExtensions
{
/// <summary>
/// 从程序集加载配置
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="modelBuilder"></param>
/// <returns></returns>
public static ModelBuilder ApplyFromAssembly<T>(this ModelBuilder modelBuilder)
=> modelBuilder.ApplyFromAssembly(typeof(T));
/// <summary>
/// 从程序集加载配置
/// </summary>
/// <param name="modelBuilder"></param>
/// <param name="type"></param>
/// <returns></returns>
public static ModelBuilder ApplyFromAssembly(this ModelBuilder modelBuilder, Type type)
=> modelBuilder.ApplyFromAssembly(type.Assembly);
/// <summary>
/// 从程序集加载配置
/// </summary>
/// <param name="modelBuilder"></param>
/// <param name="assembly"></param>
/// <returns></returns>
public static ModelBuilder ApplyFromAssembly(this ModelBuilder modelBuilder, Assembly assembly)
{
return modelBuilder.ApplyConfigurationsFromAssembly(assembly, t => !t.IsAbstract);
}
}

  到这里,EFCoreDemo.EntityFrameworkCore项目就基本上完成了,项目结构如下:

  

  三、开始迁移

  注意,这里说明一下,其实数据迁移也是可以在EFCoreDemo.EntityFrameworkCore中完成的,但是数据迁移不是我们业务上下文的的一部分,他只是我们开发过程中用到的,所以没有必要将它们放在一起,最好将它独立出来,比如这里,将它独立到一个单独的控制台程序中,这个就是EFCoreDemo.EntityFrameworkCore.Host项目:

  首先,对EFCoreDemo.EntityFrameworkCore.Host使用nuget安装:  

    Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.Tools

  这两个包是迁移所需的工具包。

  创建一个迁移上下文:  

    public class MigrationDbContext : DemoDbContext
{
public MigrationDbContext(DbContextOptions options) : base(options)
{
}
}

  可以看到,这个迁移数据上下文其实是继承了DemoDbContext类,然后其他的什么都没做,那为什么不直接使用DemoDbContext?

  当然,使用DemoDbContext也是可以的,甚至可以将MigrationDbContext继承DbContext,然后将DemoDbContext中的内容复制一份到MigrationDbContext也是可以的。

  而这里单独创建一个MigrationDbContext主要是为了迁移的方便,因为EFCore生成迁移时默认是从启动项目中去查找DbContext类的,如果DbContext类在其他类库中,那么就需要自己指定-Context参数。

  其次,单独的MigrationDbContext上下文,也能保证生成的迁移文件在当前项目,而不会跑到其他项目中去!

  接着创建一个迁移时使用的上下文工厂类,这个类需要实现IDesignTimeDbContextFactory<DbContext>接口:  

    public class DemoMigrationsDbContextFactory : IDesignTimeDbContextFactory<MigrationDbContext>
{
public MigrationDbContext CreateDbContext(string[] args)
{var builder = new DbContextOptionsBuilder<MigrationDbContext>()
.UseMySql("Server=192.168.209.128;Port=3306;Database=demodb;Uid=root;Pwd=123456"); return new MigrationDbContext(builder.Options);
}
}

  到这里,EFCoreDemo.EntityFrameworkCore.Host项目就完成了,项目结构如下:

  

  到这里,就可以生成迁移文件了。

  通过【导航栏=》工具=》NuGet包管理器=》程序包管理器控制台】打开控制台:

  

 然后输入 Add-Migration init_20200727

  

 这里使用的 Add-Migration 命令生成迁移文件,其中 init_20200727 是迁移名称。

   Add-Migration命令常用参数如下:  

    -o|--output-dir <PATH>    存放迁移文件的相对路径,默认是Migrations
-c|--context <DBCONTEXT> 迁移使用的上下文
-a|--assembly <PATH> 迁移使用的程序集
-s|--startup-assembly <PATH> 迁移时的启动程序集
--project-dir <PATH> 项目路径
--language <LANGUAGE> 语言,默认是C#

  注意,要将 EFCoreDemo.EntityFrameworkCore.Host 设置成启动项目,然后将控制台的默认项目也设置成 EFCoreDemo.EntityFrameworkCore.Host ,否则生成迁移文件的是否会报错

  Your startup project 'EFCoreDemo.EntityFrameworkCore' doesn't reference Microsoft.EntityFrameworkCore.Design. This package is required for the Entity Framework Core Tools to work. Ensure your startup project is correct, install the package, and try again.

  

  More than one DbContext was found. Specify which one to use. Use the '-Context' parameter for PowerShell commands and the '--context' parameter for dotnet commands.

  

  Add-Migration 命令执行成功后,会生成一个Migrations目录,目录下会有三个文件:

  

  20200727075220_init_20200727.cs:这个是我们的迁移文件,其中两个方法,Up方法时往数据库迁移数据时执行,Down方法时撤销迁移时执行

   20200727075220_init_20200727.Designer.cs:这个设计文件,记录的是当前迁移之后实体映射的一个快照

   MigrationDbContextModelSnapshot.cs:这个是当前实体映射的快照

  注意,上面的文件名中,20200727075220是时间戳(UTC时间),后面的init_20200727是迁移名称,EFCore的迁移执行顺序是按照时间戳的顺序执行的。

  如果需要修改迁移的执行顺序,可以自行改变这个时间戳,但是不是改变文件名,而是对应的Designer.cs文件中的Migration特性标识的那个时间戳!

  生成迁移文件之后,如果要撤销此次的迁移文件,可以使用 Remove-Migration 命令

  接着我们可以使用 Update-Database 命令开始执行迁移:

  

  注意:Update-Database命令会执行所有的数据迁移,可以指定一个迁移名称去执行单个数据迁移

  执行完Update-Database后,可以看看数据库:

  

  其中除了我们业务需要的表之外,还有一张名称为__EFMigrationsHistory的表,这个表其实就是EFCore的迁移记录表

  注:这里说的是使用Nuget命令来生成迁移和执行迁移,但是如果要上线,总不能使用nuget连接线上数据库操作吧?这里有两种解决办法:

  1、在nuget中使用Script-Migration命令将迁移生成脚本,然后到线上去执行

  2、使用程序去执行迁移,比如控制台程序,或者在项目启动时执行,具体可参考下一篇:EntityFrameworkCore数据迁移(二)

  

  四、再次迁移

  上面的迁移其实是生成了数据库和其中的一些表,但是我们的需求是不断变化的。

  前面我们虽然创建了表,但是里面字段约束等等基本上都放过了,比如字段长度,外键约束等等,现在我们补上:

  1、Account中的姓名和手机号码长度不超过100,而且姓名为必须(非空);

  2、Activity中名称长度也不超过100,且必须(非空);

  3、Activity中增加备注列,长度不超过1000

   4、ActivityRecord对ActivityId和AccountId增加外键约束

  首先,Activity增加列,只需要在实体中添加对应的属性就可以了:  

  

    /// <summary>
/// 活动表
/// </summary>
public class Activity : BaseEntity
{
/// <summary>
/// 活动名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public DateTime EndTime { get; set; }
/// <summary>
/// 活动状态
/// </summary>
public int Status { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreationTime { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}

Activity

  ActivityRecord要增加外键约束,首先在ActivityRecord中新增Activity和Account的类型引用:  

  

    /// <summary>
/// 活动记录表
/// </summary>
public class ActivityRecord : BaseEntity
{
/// <summary>
/// 活动Id
/// </summary>
public int ActivityId { get; set; }
/// <summary>
/// 用户Id
/// </summary>
public int AccountId { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreationTime { get; set; } public Activity Activity { get; set; }
public Account Account { get; set; }
}

ActivityRecord

  其他的,为实现这几项约束,我不使用特性,只需要在上面的实体映射配置中用代码实现就可以了:  

  

    public class AccountEntityTypeConfiguration : BaseEntityTypeConfiguration<Account>
{
/// <summary>
/// 配置实体类型
/// </summary>
/// <param name="builder"></param>
public override void Configure(EntityTypeBuilder<Account> builder)
{
base.Configure(builder); builder.Property(p => p.Name).HasMaxLength(100).IsRequired(true);
builder.Property(p => p.Phone).HasMaxLength(100);
} /// <summary>
/// 种子数据
/// </summary>
/// <returns></returns>
public override Account[] GetSeeds()
{
return new Account[] {
new Account(){
Id=1,
Name="admin",
Phone="110",
Age=100,
CreationTime=new DateTime(2020,02,02)//注意,种子数据不要使用DateTime.Now之类的,避免每次都会迁移数据
}
};
}
}

AccountEntityTypeConfiguration

  

    public class ActivityEntityTypeConfiguration : BaseEntityTypeConfiguration<Activity>
{
/// <summary>
/// 配置实体类型
/// </summary>
/// <param name="builder"></param>
public override void Configure(EntityTypeBuilder<Activity> builder)
{
base.Configure(builder); builder.Property(p => p.Name).HasMaxLength(100).IsRequired(true);
}
}

ActivityEntityTypeConfiguration

  

    public class ActivityRecordEntityTypeConfiguration : BaseEntityTypeConfiguration<ActivityRecord>
{
/// <summary>
/// 配置实体类型
/// </summary>
/// <param name="builder"></param>
public override void Configure(EntityTypeBuilder<ActivityRecord> builder)
{
base.Configure(builder); builder.HasOne(p => p.Activity).WithMany().HasForeignKey(p => p.ActivityId);
builder.HasOne(p => p.Account).WithMany().HasForeignKey(p => p.AccountId);
}
}

ActivityRecordEntityTypeConfiguration

  然后,接着在程序包管理器控制台输入命令生成迁移文件:

  

  注意设置项目启动项和默认程序

  执行成功后,在Migrations目录下又会多两个迁移文件。

  另外,说明一下,上面的迁移执行抛出了警告,这个是因为我的迁移中修改了数据列的长度,可能会导致数据丢失所致。

  接着执行Update-Database命令执行迁移,将其更新至数据库:

  

  最后,忘了说明了,前面说了,如果想撤销迁移,可以使用Remove-Migration命令,但是如果已经执行Update-Database将迁移更新至数据库后,Remove-Migration命令将会抛出异常:

  The migration '20200727094748_alter_20200727' has already been applied to the database. Revert it and try again. If the migration has been applied to other databases, consider reverting its changes using a new migration.

  

  此时只需要先执行 Update-Database -Migration <migration> ,这个命令后面携带的参数是迁移名称(可以去数据库中__EFMigrationsHistory表查看),执行这个命令表示将数据库迁移执行到指定名称的迁移处,后续全部的迁移都会被撤销!

  比如,如果我们想撤销20200727094748_alter_20200727这个迁移,可以先执行 Update-Database -Migration 20200727092850_init_20200727 ,注意,这里的迁移名称是要撤销的迁移的上一个!也就是20200727092850_init_20200727!

  执行完上面命令后再执行 Remove-Migration 就可以了

  

  

  五、应用使用

  实体模型创建好了,数据迁移也完成了,可以到应用了吧。

  上面可以看到,我们将实体模型与数据迁移分成了两个项目,这样EFCoreDemo.ConsoleApp只需要引用EFCoreDemo.EntityFrameworkCore去使用实体模型就够了,因为它跟数据迁移完全没关系!

  修改Program:  

  

    class Program
{
static void Main(string[] args)
{
var builder = new DbContextOptionsBuilder<DemoDbContext>()
.UseMySql("Server=192.168.209.128;Port=3306;Database=demodb;Uid=root;Pwd=123456"); using (var db = new DemoDbContext(builder.Options))
{
//查询管理员信息
var admin = db.Set<Account>().Find(1); //新建活动
var activity = new Activity()
{
Name = "活动1",
StartTime = DateTime.Now,
EndTime = DateTime.Now.AddMonths(1),
Status = 1,
Remark = "备注",
CreationTime = DateTime.Now
};
db.Set<Activity>().Add(activity); //新增活动记录
var record = new ActivityRecord()
{
Account = admin,
Activity = activity,
CreationTime = DateTime.Now
};
db.Set<ActivityRecord>().Add(record); db.SaveChanges();
} using (var db = new DemoDbContext(builder.Options))
{
var records = db.Set<ActivityRecord>().Include(f => f.Activity).Include(f => f.Account).ToArray();
foreach (var record in records)
{
Console.WriteLine($"{record.Account.Name}参加了{record.Activity.Name}");
}
} Console.ReadKey();
}
}

Program

  执行后输出:

  

EntityFrameworkCore数据迁移(一)的更多相关文章

  1. EntityFrameworkCore数据迁移(二)

    接上一篇 EntityFrameworkCore数据迁移(一) 其实上一篇该写的都已经写完了,但是后来又想到两个问题,想了想还是也写出来吧 问题一 上一篇介绍的迁移过程,都是通过在程序包管理器控制台使 ...

  2. Asp.net Core 2.0+EntityFrameWorkCore 2.0添加数据迁移

    Asp.net Core 由于依赖注入的广泛使用,配置数据迁移,与Asp.net大不相同,本篇介绍一下Asp.net Core添加数据迁移的过程 添加Nuget包 Install-Package Mi ...

  3. [EF Core]数据迁移(二)

    摘要 在实际项目中,大多都需要对业务逻辑以及操作数据库的逻辑进行分成操作,这个时候该如何进行数据的迁移呢? 步骤 上篇文章:EF Core数据迁移操作 比如,我们将数据上下文放在了Data层. 看一下 ...

  4. EF Core数据迁移操作

    摘要 在开发中,使用EF code first方式开发,那么如果涉及到数据表的变更,该如何做呢?当然如果是新项目,删除数据库,然后重新生成就行了,那么如果是线上的项目,数据库中已经有数据了,那么删除数 ...

  5. ASP.NET CORE系列【六】Entity Framework Core 之数据迁移

    原文:ASP.NET CORE系列[六]Entity Framework Core 之数据迁移 前言 最近打算用.NET Core写一份简单的后台系统,来练练手 然后又用到了Entity Framew ...

  6. .Net5 IdentityServer4下SqlServer和Mysql数据迁移

    1.概念 以下概念从官网整理的,我也是看官网一步一步学习的 官网地址 https://identityserver4.readthedocs.io/en/latest/index.html 1.1 I ...

  7. Entity Framework Core中的数据迁移命令

    使用程序包管理控制台输入命令. 数据迁移命令: Add-Migration  对比当前数据库和模型的差异,生成相应的代码,使数据库和模型匹配的. Remove-Migration 删除上次的迁移 Sc ...

  8. ABP框架使用Oracle数据库,并实现从SQLServer中进行数据迁移的处理

    ABP框架的数据访问底层是基于EFCore(Entity Framework Core)的,是微软标志性且成熟的ORM,因此它本身是支持多种主流数据库MySQL,SqlServer,Oracle,SQ ...

  9. EasySharding.EFCore 如何设计使用一套代码完成的EFCore Migration 构建Saas系统多租户不同业务需求且满足租户自定义分库分表、数据迁移能力?

    下面用一篇文章来完成这些事情 多租户系统的设计单纯的来说业务,一套Saas多租户的系统,面临很多业务复杂性,不同的租户存在不同的业务需求,大部分相同的表结构,那么如何使用EFCore来完成这样的设计呢 ...

随机推荐

  1. 文件管理与XMl、JSON解析

    1.使用内部存储器 你可以直接保存文件在设备的内部存储.默认情况下,文件保存在你的应用程序的内部存储,其他应用程序或用户不能访问.当用户卸载你的应用城西是,这些文件被删除. (一)在内部存储创建并写入 ...

  2. Springboot Oauth2 集成Swagger2权限验证实战

    Swagger是什么?能干什么?在这就不展开讲解了.本文主要讲解如何集成OAuth2的Password模式权限验证,验证接口是否具有权限. 引入依赖 <dependency> <gr ...

  3. awk统计命令(求和、求平均、求最大值、求最小值)

    本节内容:awk统计命令 1.求和 cat data|awk '{sum+=$1} END {print "Sum = ", sum}' 2.求平均 cat data|awk '{ ...

  4. 【Java多线程】ExecutorService和ThreadPoolExecutor

    ExecutorService Java.util.concurrent.ExecutorService接口代表一种异步执行机制,它能够在后台执行任务.因此ExecutorService与thread ...

  5. feign中开启熔断的书写步骤

    /**   1.在pom.xml中引入依赖    2.在application.yaml中开启hystrix 3.在方法上配置熔断类     4.书写接口的实现类 **/ //1.在pom.xml中引 ...

  6. 【C/C++】引用&的含义/语法/作为函数参数/函数返回值/本质/常量引用

    含义 引用不产生副本,只是给原变量起了别名. 对引用变量的操作就是对原变量的操作. 基本语法 数据类型 &别名 = 原名 e.g. int a = 10; int &b = a; // ...

  7. 【阿菜做实践】利用go语言写一个简单的Pow样例

    本篇博客的主要内容是用go写一个简单的Proof-of-Work共识机制,不涉及到网络通信环节,只是一个本地的简单demo.开发IDE用的是JB Golang. 整个项目的文件结构如下: PoWdem ...

  8. Java 多线程的一次整理

    一天没有出过家门,实属无聊,没事瞎写写 1. 基本概念 1.1 多进程和多线程的概念 程序是由指令和数据组成,指令要运行,数据要加载,指令被 CPU 加载运行,数据被加载到内存,指令运行时可由 CPU ...

  9. C++STL标准库学习笔记(四)multiset续

    自定义排序规则的multiset用法 前言: 在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标记了出来,只不过这一次的笔记主要是我的补充 ...

  10. house of force----gyctf_2020_force!!

    做这道题前线学习一下house of force的用法 Linux下堆溢出利用2-House of force基本原理_haibiandaxia的博客-CSDN博客 老样子例行检查(这里我就不放了) ...