SQL Server加C#这套组合,在微软技术栈里算是长青树了。从早期的桌面管理系统,到现在的WebAPI、上位机软件、生产执行系统,到处都能看到它们的身影。很多新手入行问的第一句话就是“我该先学SQL还是先学C#”,也有人在网上发帖求助某个SQL报错怎么解决。我自己从写第一行ADO.NET代码到现在,中间踩过的坑、绕过的弯,少说也够写几十篇笔记了。这篇东西我打算把SQL Server和C#配合开发的全链路捋一遍,从环境搭建到数据库设计,从增删改查到核心实操,尽量用大白话讲清楚,让刚入门的朋友能直接照做,也让想进阶的同行能在里面找到一些新的参考。
1. 一文厘清:SQL Server和C#为什么要配合使用
1.1 这套组合能解决什么问题
先说清楚一个基本问题:SQL Server负责存数据,C#负责写逻辑,两者通过一套标准的数据访问接口进行交互。C#程序里把SQL命令发给SQL Server,数据库执行完把结果返回给C#。这套模式在企业级应用里已经跑通了二十多年,稳定、资料多、招人也好招。
具体到实际项目,这套组合能干的活儿非常多。比如常见的进销存系统,前端界面用WinForm或WPF,中间的业务逻辑用C#编写,后端数据存到SQL Server;再比如工业现场的扫码枪触发事件,扫码枪通过串口或网络把数据送到C#上位机,上位机再往数据库里写入或是查询;再比如很多毕业设计做的OA系统、课程设计里的图书管理系统,数据库用的基本都是SQL Server,代码层用的C#。可以说,只要你在微软技术栈里做应用开发,这套组合就是绕不开的基本功。
1.2 适合什么人来学
如果你是刚接触编程的在校生,这门技术能让你快速实现一个带界面、带数据存储的完整系统,毕业设计不用愁。如果你是从Java或其他语言转过来的,理解这套组合也能帮你快速上手.NET系的开发环境。如果你已经在做上位机开发或桌面软件开发,把SQL Server用熟,等于给自己的工具包里加了一把大号螺丝刀——很多数据层面的需求自己就能搞定。
说白了,这不算是一门“高深”的技术,更像是一门“必须会”的手艺。掌握它不需要太厚的数学功底,也不需要对操作系统内核有多深的理解,但需要对流程有耐心、对细节有敏感度。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备:动手之前别在这些地方栽跟头
2.1 SQL Server版本选择与安装避坑指南
网上随便一搜SQL Server,能看到一堆版本:2008 R2、2012、2016、2019、2022。新手很容易懵,不知道该装哪个。我的建议非常简单:新机器直接装SQL Server 2022 Developer版,这个版本是免费的,功能和企业版几乎没有差别,只是不能用于生产环境而已。学习、开发、做课程设计,完全够用。
如果电脑配置比较老,或者课程要求里指名道姓要用某个老版本,比如SQL Server 2008 R2或2012,那就要注意:这两个版本在Win10、Win11上安装容易出问题。最常见的报错是“The required MSI package...”,还有提示需要安装.NET 3.5的,最好先到控制面板里把.NET Framework 3.5功能打开再装。另外一个老生常谈的坑就是安装到一半卡住,多数情况是之前装过一个残留实例没卸载干净。
如果你不幸遇到卸载SQL Server不干净的问题,记住一个原则:光靠控制面板卸载是不够的。我在后面“常见问题”章节里专门整理了完全卸载步骤,这里先不多说。
2.2 开发工具与数据库管理工具组合
装好SQL Server数据库引擎之后,还要装一个管理工具,通常用SSMS(SQL Server Management Studio)。SSMS从18.x之后的版本都是独立安装包,不再跟着数据库引擎一起走,所以必须去官网单独下载。注意SSMS体积不小,安装时要保持网络稳定。
C#开发环境主流是Visual Studio 2022社区版,免费,功能全。如果你只是写一些控制台测试程序,不涉及界面,也可以装.NET SDK后直接用Visual Studio Code加C#插件,写代码、运行、调试都能胜任。不过做课程设计或上位机界面,还是建议直接用Visual Studio,拖拽控件效率高得多。
连接数据库所需的类库方面,老项目里常见的是System.Data.SqlClient,新版.NET推荐用Microsoft.Data.SqlClient。这两个命名空间在使用上几乎一样,但Microsoft.Data.SqlClient是持续维护的,修复了很多底层问题。新建项目的时候直接装Microsoft.Data.SqlClient的NuGet包就好,别再走回头路。
2.3 安装后的第一个验证操作
环境装完以后,别急着写代码。先用SSMS连一次本地实例,确认能登上,然后在数据库里执行一句最简单的SQL:
sql复制SELECT GETDATE() AS 当前时间
能查出一行时间出来,说明数据库引擎已经正常工作了。这个过程中如果遇到连接不上、报错“实例名不正确”或者“用户登录失败”,多半是服务没启动或认证模式选错了——安装时建议选“混合模式(SQL Server身份验证 + Windows身份验证)”,并给sa账号设置一个强度足够的密码,不然本地开发时冒出一堆连接问题会很烦。
3. 数据库基本功:建库建表与CRUD快速上手
3.1 用SQL脚本创建第一个数据库和表
很多人入门数据库的时候喜欢直接靠SSMS的图形界面操作,鼠标点几下就能建表,看起来爽,但学不到真东西。我更推荐大家直接用T-SQL脚本的方式去建,这样既能理解数据库的底层逻辑,后期迁移、部署、课程设计写报告也都方便。
下面是一个经典的“学生信息表”的建库建表脚本,我把注释写得细一点,方便你逐行理解:
sql复制-- 1. 如果数据库已存在,先删掉(开发环境才这么干)
IF DB_ID('StudentDB') IS NOT NULL
DROP DATABASE StudentDB;
GO
-- 2. 创建数据库
CREATE DATABASE StudentDB;
GO
-- 3. 切换到该数据库
USE StudentDB;
GO
-- 4. 创建学生表
CREATE TABLE dbo.Student
(
Id INT IDENTITY(1,1) PRIMARY KEY, -- 自增主键
StudentNo NVARCHAR(20) NOT NULL, -- 学号
StudentName NVARCHAR(50) NOT NULL, -- 姓名
Gender CHAR(2) NULL, -- 性别
BirthDate DATE NULL, -- 出生日期
Phone NVARCHAR(20) NULL -- 手机号
);
GO
注意几个关键点:IDENTITY(1,1)表示自增值从1开始,每插一条加1,主键字段通常都这么设。NVARCHAR用来存字符串,带N前缀表示Unicode编码,可以正确处理中文。CHAR(2)是定长字符,这里存一个“男/女”刚好合适。
3.2 增删改查:C#和SQL对应的标准写法
数据库建好了,接下来就是最核心的部分——用C#操作这个表。先把增删改查对应关系列出来,你有个全局概念:
| 操作 | SQL语句 | C#对应的CommandText |
|---|---|---|
| 查询 | SELECT * FROM Student | SELECT * FROM Student |
| 新增 | INSERT INTO Student(字段...) VALUES(...) | 同样的语句,参数化写法 |
| 修改 | UPDATE Student SET 字段=值 WHERE 条件 | 同样的语句,参数化写法 |
| 删除 | DELETE FROM Student WHERE 条件 | 同样的语句,参数化写法 |
C#端的登录过程其实大同小异,核心是四步:建连接、建命令、执行/读取、关闭释放。下面给一段标准的查询代码,打开一个连接,读取数据后填充到DataTable里:
csharp复制using System.Data;
using Microsoft.Data.SqlClient;
string connStr = "Server=.;Database=StudentDB;User Id=sa;Password=你的密码;Encrypt=False;TrustServerCertificate=True;";
using (SqlConnection conn = new SqlConnection(connStr))
{
string sql = "SELECT Id, StudentNo, StudentName, Gender FROM Student WHERE StudentName LIKE @keyword";
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
// 参数化查询,防止SQL注入
cmd.Parameters.AddWithValue("@keyword", "%" + keyword + "%");
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
adapter.Fill(dt);
// 此时dt就是内存中的结果集
dataGridView1.DataSource = dt;
}
}
这段代码值得逐行分析:
第一行连接字符串。Server后的点表示本机实例,如果你装的是命名实例,就写成“计算机名\实例名”。Encrypt=False和TrustServerCertificate=True是SQL Server 2022里经常需要设置的两个参数,因为新版默认开启了强制加密,不关掉的话本地调试时会报证书相关的错误。
using关键字一定要用。SqlConnection和SqlCommand都实现了IDisposable接口,用using包裹可以保证结束后自动释放连接,避免连接泄漏。千万别图省事new完不关,那是在给自己埋雷。
参数化查询是必须养成的习惯。AddWithValue方法虽然写起来方便,但它对SqlDbType的处理有时候不够精确,比如传NULL时容易出问题。更稳的做法是直接指定类型,我在后面的“进阶碰到的坑”里再展开讲。
3.3 从零到一:把扫码枪数据写进数据库
热词里有一个很有意思的需求:C#扫码枪触发事件。很多做上位机或仓库管理系统的朋友都碰到过这种场景。扫码枪本质上是把扫码结果变成键盘输入,光标在哪,字符就打到哪。所以处理方式通常有两种:
第一种最简单,把扫码枪连到电脑上,界面上放一个TextBox聚焦,扫码枪扫完自动把条码“打”进文本框并触发回车事件。你在KeyDown事件里捕获Enter键,就能拿到完整条码。第二种是用串口或者网络接口直接接收扫码枪的主动推送,这种方案更接近“事件驱动”,但也要考虑解析多种协议的问题。
不管用哪种方案,拿到条码之后,往SQL Server写就是一次简单的INSERT操作。下面的代码演示了在串口数据到达事件里,把一条扫码记录写入数据库:
csharp复制private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string barcode = serialPort1.ReadExisting().Trim();
if (string.IsNullOrEmpty(barcode)) return;
using (SqlConnection conn = new SqlConnection(connStr))
{
string sql = @"INSERT INTO ScanLog(Barcode, ScanTime)
VALUES(@barcode, GETDATE())";
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.Add("@barcode", SqlDbType.NVarChar, 50).Value = barcode;
conn.Open();
cmd.ExecuteNonQuery();
}
}
}
注意扫码枪的很多型号默认在条码结尾带一个换行符,所以拿到数据后最好Trim一下,不然后续查询比对时会莫名失败。另外,串口事件是在后台线程触发的,如果你要在这个事件里操作界面控件,记得Invoke回UI线程。
4. 进阶实操:存储过程、事务与性能优化
4.1 存储过程:把复杂逻辑放进数据库
存储过程这个东西,在ORM框架满天飞的今天被很多人忽略了。但实际企业开发里,尤其是老项目、复杂报表、批量数据处理场景,存储过程的地位依然稳固。它的好处是:执行计划可以被数据库缓存,网络传输量小(只传一个存储过程名和参数),而且权限可以控制得比较细。
拿一个最常见的学生选课场景来说,每次选课需要做两步操作:先查课容量有没有满,没满就插入一条选课记录,同时把已选人数加一。这种多步骤操作如果写死在C#里,程序进程挂掉了中间步骤可能只执行了一半。把它包成一个存储过程,数据库端事务来保证一致性,则会稳妥很多。
存储过程的创建脚本长这样:
sql复制CREATE PROCEDURE dbo.usp_SelectCourse
@StudentId INT,
@CourseId INT,
@Result INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @CurrentCount INT;
DECLARE @MaxCount INT;
SELECT @CurrentCount = SelectedCount FROM dbo.Course WHERE CourseId = @CourseId;
SELECT @MaxCount = MaxCount FROM dbo.Course WHERE CourseId = @CourseId;
IF @CurrentCount >= @MaxCount
BEGIN
SET @Result = -1; -- 表示已满
RETURN;
END
BEGIN TRANSACTION;
BEGIN TRY
INSERT INTO dbo.StudentCourse(StudentId, CourseId, SelectTime)
VALUES(@StudentId, @CourseId, GETDATE());
UPDATE dbo.Course SET SelectedCount = SelectedCount + 1
WHERE CourseId = @CourseId;
COMMIT TRANSACTION;
SET @Result = 1; -- 成功
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
SET @Result = -2; -- 异常
END CATCH
END
C#端调用时,通过SqlCommand把CommandType改成StoredProcedure,然后添加参数,其中OUTPUT参数要设置Direction属性:
csharp复制using (SqlCommand cmd = new SqlCommand("dbo.usp_SelectCourse", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@StudentId", studentId);
cmd.Parameters.AddWithValue("@CourseId", courseId);
SqlParameter resultParam = new SqlParameter("@Result", SqlDbType.Int);
resultParam.Direction = ParameterDirection.Output;
cmd.Parameters.Add(resultParam);
conn.Open();
cmd.ExecuteNonQuery();
int result = (int)resultParam.Value;
}
这里有个小细节:OUTPUT参数必须先new一个SqlParameter出来再设置Direction,不能在AddWithValue之后直接改Direction,否则某些驱动下会报参数方向冲突。
4.2 事务:保证数据的完整性
事务是数据库最核心的机制之一,理解它不费劲,记住四个字母就行:ACID。原子性、一致性、隔离性、持久性。用生活化的说法,事务就是一个“要么全做,要么全不做”的包裹。
C#操作事务有底层写法,也有封装好的写法。底层写法比较直观,我贴一段经典代码:
csharp复制using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
SqlTransaction tran = conn.BeginTransaction();
try
{
SqlCommand cmd1 = new SqlCommand("UPDATE Account SET Balance = Balance - 100 WHERE Id = 1", conn, tran);
cmd1.ExecuteNonQuery();
SqlCommand cmd2 = new SqlCommand("UPDATE Account SET Balance = Balance + 100 WHERE Id = 2", conn, tran);
cmd2.ExecuteNonQuery();
tran.Commit();
}
catch
{
tran.Rollback();
}
}
注意一个常见陷阱:命令必须绑定同一个连接和同一个事务实例,如果忘了把tran传给SqlCommand的构造函数,执行时会报“操作已处于事务状态”之类的错误。建议项目里直接用封装好的方法,比如SqlHelper类里把事务逻辑统一封装,避免每处调用都写一遍try/catch。
4.3 索引如何快、为什么会慢
SQL Server慢查询的排查一直是面试热门和实战痛点。一张表数据量从几万行涨到几百万行之后,查询速度断崖式下跌的情况我见过太多次。根因多半是索引没用对。
索引在SQL Server里的作用类似书后面的目录。没有目录,你要从第一页翻到最后一页;有了目录,直接定位到指定页码。主键默认会建一个聚集索引,也就是按主键顺序物理排列数据。如果你经常按非主键字段查询,就要额外建普通索引。
举个例子,如果学生表经常要按学号StudentNo查,那就在这个字段上建个索引:
sql复制CREATE INDEX IX_Student_StudentNo ON dbo.Student(StudentNo);
但索引也不是越多越好——每多一个索引,插入、更新、删除时的维护成本就会增加。正确姿势是:先看实际查询最频繁的是哪些字段,再针对性地建索引。用SSMS的“显示估计的执行计划”功能,可以直观地看到哪些查询走了全表扫描,哪些走了索引查找。这里我的经验是,宁可少建几个索引,也别把表搞成“索引页比数据页还大”的状态。
4.4 连接池:每次开连接其实并不慢
很多初学者担心频繁打开关闭数据库连接会影响性能,于是尝试用一个静态连接从头用到尾。这个想法看起来很聪明,实际是给自己挖坑。
SQL Server的ADO.NET驱动默认开启了连接池。连接字符串里没特殊指定的情况下,连接关闭后不是立刻销毁TCP通道,而是回收到连接池里复用。默认池大小是100,在普通应用里足够用了。所以你应该放心地“用完即关”,每次操作都写using块。
唯一要注意的是,如果在多线程环境里疯狂开连接,连接池被占满时会出现“连接池已达到最大大小”的报错。这种时候要先排查是不是有连接泄漏——也就是连接打开了没关。大多数情况下,把一个SqlConnection的using包掉,这个报错就不会出现。
5. 实战扩展:上位机、OA系统与数据库课程设计
5.1 C#上位机如何与数据库联动
“C#上位机”是热词里的高频词,尤其在工控圈和智能制造领域,需求量大。上位机软件从设备(PLC、扫码枪、相机、仪表)那边取数据,经过逻辑处理后展示给操作工看,同时把关键数据落到数据库里,方便追溯和分析。
一个典型的上位机系统结构大致是这个样子:设备数据采集模块(串口/网口)、数据解析模块、界面展示模块、数据库读写模块。通信协议一般用TCP或Modbus,比如海康相机跟上位机通讯常用TCP协议,VisionMaster有自己的SDK,C#通过SDK回调拿图像结果,再结合业务逻辑写库。
这里最容易被忽视的是线程问题。上位机里数据采集线程和数据库写入操作如果耦合在同一个线程,界面会卡死;如果多个线程同时操作同一个控件,又会报线程间操作无效。我的做法是:采集线程只负责把数据丢进队列,一个独立的数据库写入线程专门消费这个队列。
代码层面的伪逻辑大概长这样:
csharp复制// 采集线程收到数据后
ConcurrentQueue<string> dataQueue = new ConcurrentQueue<string>();
// 写入线程循环处理
while (true)
{
if (dataQueue.TryDequeue(out string data))
{
// 执行SQL写入
}
Thread.Sleep(50);
}
这个模式虽然叫法简单,但能避开90%的上位机数据写入问题。如果涉及批量写入,可以用SqlBulkCopy来做,一次能导入上万条记录,比一条条INSERT快几十倍。
5.2 简单OA系统怎么做数据库表设计
热词里有“简单OA系统C#”,这个其实说是“简单”,但涉及的表设计、权限模型和工作流模型对新手来说可能还挺绕。
一个符合多数课程设计和初级项目要求的OA系统,最核心的表有这么几张:用户表(Users)、部门表(Departments)、角色表(Roles)、审批单据表(ApprovalForms)、审批记录表(ApprovalRecords)。用户和角色是多对多关系,一张单子和审批记录是一对多关系。
用户表的简化创建脚本:
sql复制CREATE TABLE dbo.Users
(
UserId INT IDENTITY(1,1) PRIMARY KEY,
UserName NVARCHAR(50) NOT NULL,
PasswordHash NVARCHAR(200) NOT NULL,
DepartmentId INT NULL FOREIGN KEY REFERENCES dbo.Departments(DepartmentId),
IsEnabled BIT NOT NULL DEFAULT 1
);
CREATE TABLE dbo.UserRoles
(
UserId INT NOT NULL FOREIGN KEY REFERENCES dbo.Users(UserId),
RoleId INT NOT NULL FOREIGN KEY REFERENCES dbo.Roles(RoleId),
PRIMARY KEY (UserId, RoleId)
);
密码字段我建议存哈希而不是明文,哪怕只是一个练习项目,也别把安全习惯丢掉。很多课程设计里用户表直接放一个Password列存明文,答辩时不深究还好,真到工作里养成这种习惯会出大问题。
审批流程则是OA系统里比较有代表性的点。典型的“提交单据-上级审批-通过/驳回”可以抽象成一张状态表:单据表里加一个Status字段,0表示待审批,1表示通过,2表示驳回。审批人每次操作,往审批记录表插一行数据。当领导要看某个人的审批历史时,一条JOIN查询就能搞定。
5.3 Excel导入数据库的常见实现
入职做进销存或者报表系统时,经常会收到“把Excel导入系统”的需求。Excel导入数据库,实现方案有不少,但最稳的路线我觉得还是用NPOI或者MiniExcel先读取Excel内容到内存的DataTable,再用SqlBulkCopy一次性写入数据库。
MiniExcel的用法相对简单,几行代码就能把Excel读成DataTable或List对象:
csharp复制var rows = MiniExcel.Query<StudentImportModel>(filePath).ToList();
然后创建一个DataTable,字段结构和目标表对应起来,最后调用SqlBulkCopy:
csharp复制using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connStr))
{
bulkCopy.DestinationTableName = "dbo.Student";
bulkCopy.ColumnMappings.Add("学号", "StudentNo");
bulkCopy.ColumnMappings.Add("姓名", "StudentName");
bulkCopy.WriteToServer(dt);
}
这里有个容易踩的坑:Excel里的列名和表字段名往往对不上,所以ColumnMappings这个步骤不能省。另外批量写入前建议先校验一遍数据的完整性,尤其是日期格式、必填项,免得导到一半主键冲突或者数据类型转换报错,回滚又是一地鸡毛。
6. 常见问题与排查技巧实录
6.1 SQL Server安装与卸载问题
SQL Server安装出错的情况不少,这里列几个最常见的:
| 场景 | 典型报错/现象 | 解决思路 |
|---|---|---|
| 安装时提示需要MSI包 | The required MSI package... | 补装.NET 3.5,或使用安装包自带的redist文件 |
| 连接时找不到实例 | 服务器名称“.”或“local”连不上 | 确认SQL Server服务是否启动,用“sqlcmd -L”查看本机实例名 |
| sa登录失败 | 用户“sa”登录失败 | 到SSMS里用Windows身份登录,修改sa账号的认证状态和密码 |
| 卸载不干净 | 重装时报已有实例存在 | 按“控制面板卸载-删除安装目录-删除注册表-删服务”顺序逐步清理 |
完全卸载SQL Server这个事,我自己的步骤是:先用控制面板把所有SQL Server相关的程序都卸载掉,包括SSMS和LocalDB;然后删除安装目录(通常是C:\Program Files\Microsoft SQL Server)和C:\Program Files (x86)\Microsoft SQL Server;接着用regedit把HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server注册表项清理掉;最后用管理员权限在命令行执行services.msc确认SQL Server相关服务已经消失。这套流程走完,一般能装回干净环境。
6.2 运行时报错排查速查表
| 报错信息 | 原因与解决 |
|---|---|
| 阻止了对组件“ad hoc distributed queries”的访问 | 开启了OpenRowset/OpenDatasource功能,需要执行sp_configure开启Ad Hoc Distributed Queries |
| 连接未关闭 | 连接泄漏严重,检查所有数据库操作是否用了using或finally |
| 超时时间已到,但尚未从池中获取连接 | 连接池被耗尽,重点排查连接泄漏和慢查询 |
| 列名无效或对象名无效 | SQL写错或表名带了dbo前缀错误,检查是否有大小写或空格问题 |
| 无法打开登录所请求的数据库 | 数据库被分离或权限不足,排查连接字符串里的InitialCatalog是否配置正确 |
6.3 日常开发中容易忽略的细节
参数长度不匹配的问题值得单独拿出来提醒。AddWithValue在处理字符串参数时,默认长度为NVARCHAR的默认长度,如果表字段是NVARCHAR(200),而参数实际传了2000个字符,SQL Server在生成执行计划时可能会发生隐式转换,导致性能下降甚至报错。所以用Add方法显式声明SqlDbType和大小会更稳:
csharp复制cmd.Parameters.Add("@name", SqlDbType.NVarChar, 50).Value = name;
还有一个在批量写数据时经常踩的坑:SQL Server参数总数默认上限是2100。如果你写循环一条条INSERT,每个语句用两个参数,那循环超过1050次可能会报错。这种场景下就别拼参数化SQL了,用SqlBulkCopy才更合适。
最后是NULL值问题。C#里的null传到SQL Server里就是NULL,但有些字段是NOT NULL的,传null进去就会报“不能将NULL值插入列”的错。处理方式是在入库前做一次null检查,或者用DBNull.Value显式转换。这也是刚入门的朋友常犯的一个低级但恼火的错误。
6.4 学习路径与后续扩展建议
SQL Server和C#这套组合,学起来并不要求一次吃成胖子。我的建议路线是先学会用SSMS建库建表、写SELECT、INSERT、UPDATE、DELETE,然后写一个简单的WinForm程序连接数据库展示一个表格的数据。这一圈走通,基础就算打好了。
之后可以试着加权限管理、事务、存储过程,再了解索引和查询计划的基本概念。如果工作方向偏上位机,就多研究串口通讯、TCP Socket、数据采集与入库的并发处理;如果偏业务系统,就多研究表设计、状态机流转和报表统计。
数据库这个领域特别依赖动手。光看文章、看视频是学不会的,真正上手敲一遍SQL,改一改表结构,踩一踩报错的坑,那些知识点才真正是你的。SQL Server顺手了以后,再去看达梦、Oracle、MySQL这些,原理上大多相通,切换成本并不会太高。C#那边也是一样,连接、命令、适配器、事务这套模型吃透后,任何数据层框架(EF Core、Dapper)你都能更快上手。
我自己的体会是,编程的瓶颈往往不在语法和框架,而在对数据流的理解。什么时候该写SQL,什么时候该在程序里处理,什么时候该用事务保一致性,这些判断才是长期积累下来的财富。把这套组合练熟,以后遇到再复杂的系统,你也不会慌。
