项目场景:

使用FreeSql,包含所有的ORM数据库,都会存在这样的问题。在codefirst模式下,根据代码自动更新数据库,都建议不要在生产环境使用。为什么呢?

其实不建议使用,主要是根据代码自动生成数据时,极有可能会造成数据的丢失,比如修改字段类型,自动更新的结果可能并不是自己想的。

但是有一些使用场景是需要在生产环境自动升级的,比如

我们有一个CS客户端的产品,客户本地离线使用,客户本地部署,数据库也是本地数据库,版本从1000,迭代到了1100,中间发布了100个版本。这中间可能有多次数据库更改。我们的客户也可能遍布全国各地,版本也都不相同。客户如果没有新的需求,可能会一直使用当前旧版本,只有在有新的需求,或者想使用新的功能时,才会升级版本。所以升级的时间也是不确定的,升级要求客户安装新版软件,运行后自动升级。

那就真的不能在生产环境使用呢?

解决方案:

概要描述:

解决的思路其实就是自动升级,但是在判断需要升级时,才自动升级,同时升级前先备份数据库。

具体流程

程序内每次有数据库变更,发布版本时,修改程序内对应版本。比如最开始是1000,最新是1100

在数据库增加SysConfig表,字段包含DbVer表示当前数据库版本号

在数据库增加DbLog表,记录数据库升级日志,此项可选

在首次安装时,检查数据库文件不存在,表示首次安装,首次安装时创建SysConfig表和DbLog表,同时更新SysConfig表DbVer为程序中记录版本号。增加DbLog表日志

以后再次运行时,先获取SysConfig表DbVer,判断与程序中是否一致,

如果数据库比程序中大,说明运行低版本的程序,根据情况可以禁止运行。也可以不同步数据库,继续运行,根据实际情况决定。如果对程序和数据库一致性要求比较高,可以禁止运行。

如果数据库比程序小,说明数据库需要升级,此时先备份现有数据库,然后执行同步数据库。

详细说明:

直接上代码,比啥都清楚

program.cs文件代码

using Bonn.Helper;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using FreeSql.DataAnnotations;
using WindowsClient.Model;
using System.Reflection; namespace WindowsClient
{
static class Program
{
/// <summary>
/// 客户数据库路径
/// </summary>
private static string CustDbPath = Application.StartupPath + $"\\数据库\\cust.db"; /// <summary>
/// 数据库ORM
/// </summary>
public static IFreeSql fsql; /// <summary>
/// 服务器数据库版本
/// </summary>
private static int ServerDbVer = 1000; /// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
try
{ //数据库是否存在,用于插入初始数据,必须在freesql实例化前判断,因为实例化时会自动创建数据库
var custDbPathExists = File.Exists(CustDbPath); //deebug自动同步实体结构到数据库,release手动同步
bool syncDbStructure = false;
#if DEBUG
syncDbStructure = true;
#endif fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.Sqlite, $@"Data Source={CustDbPath}; Pooling=true;Min Pool Size=1")
.UseAutoSyncStructure(syncDbStructure) //deebug自动同步实体结构到数据库,release手动同步
.UseMonitorCommand(cmd => Console.WriteLine($"线程:{cmd.CommandText}\r\n"))
.Build(); //请务必定义成 Singleton 单例模式 if(syncDbStructure)
{
//主要用于开发模式下,让数据库修改快速生效,不加此句时,只有在用到表时才会同步
fsql.CodeFirst.SyncStructure(GetTypesByTableAttribute());
} if (custDbPathExists == false)
{
//数据库文件不存在,表示是首次安装
fsql.CodeFirst.SyncStructure(GetTypesByTableAttribute());
var sysConfig = new SysConfig();
sysConfig.DbVer = ServerDbVer;
var dbResult = fsql.Insert(sysConfig).ExecuteAffrows();
if (dbResult <= 0)
throw new Exception("初始数据库失败。"); var row = new DbLog();
row.DbVer = ServerDbVer;
fsql.Insert(row).ExecuteAffrows();
}
int localDbVer = fsql.Select<SysConfig>().First().DbVer;
if (localDbVer != ServerDbVer)
{
//数据库版本不一样,需要升级
//备份数据库
File.Copy(CustDbPath, Application.StartupPath + $"\\数据库\\cust{DateTime.Now:yyyyMMddHHmmss}.db");
//升级数据库
fsql.CodeFirst.SyncStructure(GetTypesByTableAttribute());
var row = new DbLog();
row.DbVer = ServerDbVer;
fsql.Insert(row).ExecuteAffrows();
} Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FrmMain());
}
catch (Exception e)
{
MessageBox.Show(e.ToString(), "出错啦", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
} public static Type[] GetTypesByTableAttribute()
{
List<Type> tableAssembies = new List<Type>();
foreach (Type type in Assembly.GetAssembly(typeof(IEntity)).GetExportedTypes())
{
foreach (Attribute attribute in type.GetCustomAttributes())
{
if (attribute is TableAttribute tableAttribute)
{
if (tableAttribute.DisableSyncStructure == false)
{
tableAssembies.Add(type);
}
}
}
};
return tableAssembies.ToArray();
}
}
}

SysConfig.cs

using FreeSql.DataAnnotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace WindowsClient.Model
{
/// <summary>
///
/// </summary>
[Table(Name = "sys_config")]
public class SysConfig : IEntity
{
/// <summary>
/// 主键
/// </summary>
[Column(Name = "id", IsIdentity = true, IsPrimary = true)]
public int Id { get; set; } /// <summary>
/// 主键
/// </summary>
[Column(Name = "dbVer")]
public int DbVer { get; set; } /// <summary>
/// 创建时间
/// </summary>
[Column(ServerTime = DateTimeKind.Local, CanUpdate = false)]
public DateTime CreateTime { get; set; } /// <summary>
/// 修改时间
/// </summary>
[Column(ServerTime = DateTimeKind.Local, CanUpdate = true)]
public DateTime UpdateTime { get; set; } }
}

DbLog.cs

using FreeSql.DataAnnotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace WindowsClient.Model
{
/// <summary>
///
/// </summary>
[Table(Name = "db_log")]
public class DbLog : IEntity
{
/// <summary>
/// 主键
/// </summary>
[Column(Name = "id", IsIdentity = true, IsPrimary = true)]
public int Id { get; set; } /// <summary>
/// 主键
/// </summary>
[Column(Name = "dbVer")]
public int DbVer { get; set; } /// <summary>
/// 创建时间
/// </summary>
[Column(ServerTime = DateTimeKind.Local, CanUpdate = false)]
public DateTime CreateTime { get; set; } /// <summary>
/// 修改时间
/// </summary>
[Column(ServerTime = DateTimeKind.Local, CanUpdate = true)]
public DateTime UpdateTime { get; set; }
}
}

总结:

以前是手写的SQL语句,现在用FreeSql确实方便多了。感觉FreeSql。

以上方案有需要改进的,或者好的建议,希望大家评论留言。

FreeSql生产环境自动升级数据库解决方案的更多相关文章

  1. 系统环境: CentOS 64位+千万不要在生产环境中升级glibc!

    # cd /lib64# LD_PRELOAD=/lib64/libc-2.15.so ln -sf /lib64/libc-2.15.so libc.so.6 libc-2.15.so 这个文件名根 ...

  2. 生产环境中,数据库升级维护的最佳解决方案flyway

    官网:https://flywaydb.org/ 转载:http://casheen.iteye.com/blog/1749916 1.  引言 想到要管理数据库的版本,是在实际产品中遇到问题后想到的 ...

  3. 生产环境中mysql数据库由主从关系切换为主主关系

    目录 一.清除原从数据库数据及主从关系 1.1.关闭主从数据库原有的主从关系 1.2.清除从数据库原有数据 二.将主库上的数据备份到从库 2.1.备份主库数据到从库 2.2.在从库使用tsc.sql文 ...

  4. [MySQL-MM] 生产环境自动恢复MM中一台M2库的过程,分享从零开始写的自动化重建脚本以及思路 (转)

    必须是MM架构,而且一台主库M1是完好无损的,一台主库M2可以根据M1主库来进行重建:如果MS架构,自己可以稍微做一下脚本修改动作,也能使用,架构如下图所示: 3  总体思路,建立主脚本a_build ...

  5. linux日志审计项目案例实战(生产环境日志审计项目解决方案)

    所谓日志审计,就是记录所有系统及相关用户行为的信息,并且可以自动分析.处理.展示(包括文本或者录像) 推荐方法:sudo配合syslog服务,进行日志审计(信息较少,效果不错) 1.安装sudo命令. ...

  6. 生产环境自动备份win服务器所有web项目(IIS+项目代码)

    @echo offrem 功能:每月自动备份本服务器所有web项目rem 日期:2022.3.10rem 制作人:zl rem 定义变量Y为备份时间:YYYYMMset y=%date:~0,4%%d ...

  7. 黄聪:禁止wordpress版本自动升级的解决方案

    在WordPress配置文件中找到wp-config.php,添加如下常量 define( 'AUTOMATIC_UPDATER_DISABLED', true );

  8. 理解Docker(6):若干企业生产环境中的容器网络方案

    本系列文章将介绍 Docker的相关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...

  9. MySQL 8 升级数据库

    开始升级前 因为从MySQL 8.0 到MySQL 5.7,或者从MySQL 8.0 到之前的 MySQL 8.0版本都是不支持的.所有在在升级前要做好数据库备份,包括mysql 系统schema(数 ...

  10. LNMP一键安装包 PHP自动升级脚本

    LNMP一键安装包 PHP自动升级脚本 2011年03月15日 上午 | 作者:VPS侦探 前一段时间完成了lnmp一键安装包的PHP自动升级脚本,今天发布出来,如果想升级PHP版本的lnmp用户可以 ...

随机推荐

  1. docker 常用命令 快捷命令

    一.查询节点 docker ps -a 二.docker重启停止 systemctl restart docker systemctl stop docker docker restart * 三.一 ...

  2. UtilMeta - 简洁高效的 Python 后端元框架

    最近开源了我开发多年的一个 Python 后端框架:UtilMeta 项目介绍 UtilMeta 是一个用于开发 API 服务的后端元框架,基于 Python 类型注解标准高效构建声明式接口与 ORM ...

  3. Android加载PDF方案(pdf.js,支持缩放)

    都知道,Android本身的webview是不支持pdf加载的(比不上iOS的webview,谁让人家NB呢),因此通过连接Google的一个服务器转换成功后返回给WebView显示.但是,但是,但是 ...

  4. Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo

    前言   驱动的开发需要先熟悉基本概念类型,本篇讲解linux杂项设备基础,还是基于虚拟机ubuntu去制作驱动,只需要虚拟机就可以尝试编写注册杂项设备的基本流程.   linux三大设备驱动 字符设 ...

  5. 【Azure 应用服务】App Service For Linux 怎么安装Composer,怎么安装PHP扩展,怎么来修改站点根路径启动程序?

    问题一:App Service 的默认启动路径为wwwroot,如何修改到到PHP代码运行目录呢? 如Laravel的启动目录为public/?那如何修改呢? App Service 的默认 PHP ...

  6. 如何运维多集群数据库?58 同城 NebulaGraph Database 运维实践

    图计算业务背景介绍 我们为什么选择 NebulaGraph? 在公司各个业务线中,有不少部门都有着关系分析等图探索场景,随着业务发展,相关的需求越来越多.大量需求使用多模数据库来实现,开发成本和管理成 ...

  7. 四: Mysql用户管理

    # 用户与权限管理 MySQL用户可以分为普通用户和root用户, root用户是超级管理员,拥有所有权限,包括创建用户.删除用户和修改用户的密码等管理权限:普通用户只拥有被授予的各种权限. MySQ ...

  8. Vue3学习(二十三)- 保存文档内容正常显示

    写在前面 情人节已经接近尾声了,虽然跟我没什么关系,但是我还是很渴望,能遇到一个良人相伴一生. 现在时间: 内心异常平静,相对吵闹我更喜欢安静的晚上,没人打扰,enjoy自己独处的时间! 保存内容显示 ...

  9. Java处理子父级菜单的方式二

    处理存在子父级关系的数据是写代码的过程中常见的操作,前面讲解过使用递归的方法来做, 可以参考这篇博客 https://www.cnblogs.com/yilangcode/p/16831867.htm ...

  10. SQL执行一次完成新增或者修改操作-2022新项目

    一.业务场景 当前项目中数据库使用的postgresql,pgsql有很多的优点,比如开源免费,适合二次开发.pgsql有很多搭配使用的开源软件,比较易于拓展,语法和标准的SQL语法基本上差异不大.因 ...