三种启动方式:服务面板、SQL Server 配置管理器、命令行 net start。都能起,场合不同。
「自动」不等于「正在运行」:本机 93 个自动、517 个手动,实际在跑的是 104 个。
net start 报「服务名无效」返回码 2,八成是实例名拼错;依赖缺一环报错误 1068。
3.1 讲了服务是什么,这一节讲怎么让它从「停止」变成「正在运行」。 操作本身不难,难在失败了看不懂反馈。 教材列了三种方式,配了截图。 这一节把三种方式的反馈都跑一遍——本机没有 SQL 引擎,但命令行对不存在服务的报错是真的, 跟真机上敲错实例名的报错一模一样。 另外补了两件教材没细讲的事: 「自动」和「正在运行」为什么对不上,以及依赖链断在哪一环会报 1068。
一、三种方式,各有各的场合
| 方式 | 入口 | 强在哪 | 弱在哪 |
|---|---|---|---|
| 服务面板 | services.msc | 看全局,能改启动类型 | 分不清哪条是哪个实例 |
| 配置管理器 | SQLServerManager15.msc | 能改协议和端口 | 只在装了 SQL 的机器上 |
| 命令行 | net start 服务名 | 能写脚本、能远程 | 报错只有返回码 |
配置管理器的价值不在「能启动」,在「能改协议」。TCP/IP 协议启不启用、端口号改成多少、 要不要允许远程连接——这些只有它管得动。服务面板里那条服务只是个开关,改不了协议。 命令行的价值在「能自动化」。 重启服务这件事在运维里是常态,每次点鼠标不现实, 写成脚本才能跟监控、发布流程接起来。 服务面板的价值在「一次看全」。 想知道这台机器上总共装了几个实例、各自的 Agent 起没起, 按名称排一下序最快。三样东西不是替代关系。
二、「自动」不等于「正在运行」
这三个词经常被当成一回事,其实完全不是:
启动类型是「配置」,运行状态是「当前」,「自动」只是说「开机时会尝试拉起」。
演示里数了一遍本机:注册表里 Start=2(自动)93 个,Start=3(手动)517 个,
而 net start 列出来正在跑的 104 个。运行中的比「自动」还多。
多出来的部分是从哪儿来的?按需触发。 那些「手动」服务平时睡着,有程序调它的接口就被拉起来,
跑完过一阵再自己关。所以「手动服务在跑」不是异常。
反过来,「自动」里也可能有几个躺着没起。 比如依赖的服务起晚了、或者启动时磁盘还没就绪。
这种服务在事件查看器里会留一条 7000 或 7009 的日志。
所以「我设了自动」和「它在跑」是两句话,不能互相替代。
三、命令行启动:返回码比文字有用
net start 的报错文字只有那么几句,真正能用来判断的是返回码。演示里跑了两种:
> net start MSSQLSERVER
服务名无效。
请键入 NET HELPMSG 2185 以获得更多的帮助。
返回码 2(服务不存在)
> net start Themes
请求的服务已经启动。
请键入 NET HELPMSG 2182 以获得更多的帮助。
返回码 2(服务已经在跑)
两句完全不同的话,返回码都是 2。 所以脚本里不能靠返回码区分「名字敲错了」和「已经起着」——
要看文字,或者干脆先查状态再决定起不起。
「服务名无效」这条反馈值得单独记。 装完 SQL Server 报这个,无非两种原因:
实例名拼错了(默认实例叫 MSSQLSERVER,不是 SQLSERVER),
或者把括号里的显示名当成了服务名(敲成 SQL Server (MSSQLSERVER))。
返回码 5 是另一种常见情况:拒绝访问。 说明名字对了,但没有管理员权限。
启动和停止服务都要提权,普通命令行窗口不行,得用管理员身份打开。
四、依赖链:1068 是怎么来的
服务之间是有依赖的,注册表里写在 DependOnService 这个多字符串值里。
本机 782 个服务里有 251 个声明了依赖。
| 服务 | 依赖谁 |
|---|---|
| iphlpsvc | RpcSS、winmgmt、tcpip |
| NlaSvc | NSI、RpcSs、TcpIp |
| NcaSvc | BFE、dnscache、NSI |
依赖是一层套一层的。 演示里顺着链条排了一条:Fax → TapiSrv → RpcSs → RpcEptMapper,四层。
要最上面那个起来,底下三个得先起来。
只要链条里断一环,报的就是错误 1068:依赖服务或组无法启动。这个错误号很误导,
它不说「谁没起来」,只说「有东西没起来」。
查法是顺着 DependOnService 一层层往下找,找到第一个不在运行的就是它。
SQL Server 自己也有依赖。 引擎依赖 LanmanServer(文件共享服务)和 RpcSs,代理还依赖引擎。
所以偶尔会见到「代理起不来,报 1068」——那其实是引擎没起,代理在等它。
这里复刻的是判定逻辑,没有真去启动系统服务。 真启动要管理员权限,而且会改这台机器的状态;
上面那两行「错误 1068」是按注册表里的依赖关系算出来的,跟系统的判定规则一致。
五、动手 Demo:三种方式的真实反馈
这一段跑三件事:数一遍「自动」和「正在运行」的差额、跑两条 net start 看真实报错、
再顺着注册表里的依赖关系排一条启动链,并按这条链复刻 1068 的判定。
import subprocess
def sh(cmd):
"""跑一条 cmd 命令;系统消息是 GBK,要按 GBK 解。"""
p = subprocess.run(cmd, shell=True, capture_output=True)
out = (p.stdout or b"") + (p.stderr or b"")
return p.returncode, out.decode("gbk", "replace").strip()
# 1) 「自动」和「正在运行」差多少
rc, out = sh(u"net start")
running = len([x for x in out.splitlines() if x.strip()]) - 2
print(u"net start 列出 %d 个在跑,返回码 %d" % (running, rc))
# 2) 两种结果的返回码
for cmd in (u"net start MSSQLSERVER", u"net start Themes"):
rc, out = sh(cmd)
print(u"> %s" % cmd)
print(u" 返回码 %d:%s" % (rc, out.splitlines()[0]))
# 3) 依赖链与 1068 的判定
def can_start(name, up, dep):
low = set(x.lower() for x in up)
miss = [d for d in dep.get(name, []) if d.lower() not in low]
if miss:
return u"错误 1068:依赖服务或组无法启动(缺 %s)" % miss[0]
return u"启动成功"
up = {u"RpcSs", u"RpcEptMapper", u"PlugPlay"}
print(can_start(u"Spooler", up, DEP))
实跑输出:
--------------------------------------------------------------------
三种启动方式与它们的真实反馈
--------------------------------------------------------------------
① 「自动」不等于「正在运行」
--------------------------------------------------------------------
注册表里 Start=2(自动):93 个
注册表里 Start=3(手动):517 个
net start 实际列出的运行中服务:106 个
net start 返回码:0
运行中的比「自动」多,因为按需触发的手动服务也被叫起来了;
而「自动」里有几个可能启动失败躺在那儿——这三组数本来就对不上。
② 命令行启动的真实反馈(三种结果)
--------------------------------------------------------------------
> net start MSSQLSERVER
服务名无效。
请键入 NET HELPMSG 2185 以获得更多的帮助。
返回码 2(服务不存在)
> net start Themes
请求的服务已经启动。
请键入 NET HELPMSG 2182 以获得更多的帮助。
返回码 2(服务已经在跑)
第一条是本章最该记住的一条反馈:服务名无效,返回码 2。
装完 SQL Server 却报这个,八成是实例名拼错了——默认实例叫 MSSQLSERVER,
Express 叫 MSSQL$SQLEXPRESS,中间那个美元符号不能少也不能换成反斜杠。
③ 启动顺序:依赖没起来,自己也起不来
--------------------------------------------------------------------
注册表里声明了依赖的服务:251 个
| 服务 | 依赖谁 |
|---|---|
| iphlpsvc | RpcSS、winmgmt、tcpip |
| NlaSvc | NSI、RpcSs、TcpIp |
| AppVClient | RpcSS、netprofm、AppvVfs |
| NcaSvc | BFE、dnscache、NSI |
依赖是一层套一层的。真起不来时报的是错误 1068:依赖服务或组无法启动。
下面按注册表里的依赖关系把一条链完整排一遍。
Fax 的启动链(4 层):
1. Fax
2. TapiSrv
3. RpcSs
4. RpcEptMapper
服务名不区分大小写,注册表里写的是 RpcSs、命令里敲 rpcss 都认。
要 Fax 起来,得从链条最底下那个开始,一个不起来后面全报 1068。
在「只起了 RPC 三件套」的机器上启动 Spooler:错误 1068:依赖服务或组无法启动(缺 http)
在「只起了 RPC 三件套」的机器上启动 W32Time:启动成功
这里复刻的是判定逻辑,没有真去启动系统服务——真启动要管理员权限,而且会改这台机器的状态。
④ 三种方式各用在什么场合
--------------------------------------------------------------------
| 方式 | 入口 | 强在哪 | 弱在哪 |
|---|---|---|---|
| 后台「服务」面板 | services.msc | 看全局,能改启动类型 | 慢,找不到实例对应哪个 |
| SQL Server 配置管理器 | SQLServerManager15.msc | 专管 SQL 服务与协议 | 只在装了 SQL 的机器上 |
| 命令行 net start | net start 服务名 | 能写进脚本、能远程执行 | 报错只有数字返回码 |
配置管理器的价值不在「能启动」,在「能改协议」——
TCP/IP 协议启用、端口号、是否允许远程连接,这些只有它管得动。
第一段那两个数放在一起看才有意思:在跑的比「自动」还多。差的那部分是按需触发的手动服务,
它们被程序叫起来,跑完再自己歇。
第二段的重点是「两句话、同一个返回码」。 服务名无效 和 请求的服务已经启动 都是返回码 2,
所以脚本里不能只看返回码,得看文字或者先查状态。
第三段的依赖链是从注册表真读出来的:本机 251 个服务声明了依赖。
排在最上面那几条(iphlpsvc、NlaSvc)都是网络相关的,这符合直觉——网络栈是底。
最后那个 1068 是按依赖关系算的,不是真去启动服务。真启动要提权、会改机器状态,
而且演示价值不大——真正有用的是这个判定规则本身:依赖里有一个不在运行,就报 1068,
而且不告诉你是谁。
30 秒实验
- 在你自己机器上先跑
net start,再跑net start MSSQLSERVER(如果你装了)。 对照一下:报的是「服务名无效」还是「请求的服务已经启动」? - 打开服务面板,随便挑一个正在跑的服务,右键看属性里的「依存关系」页。 上面那栏是「它依赖谁」,下面那栏是「谁依赖它」——下面那栏出事的时候, 症状往往出现在别的服务上。
- 想一想:为什么脚本里判断「服务起来没有」不能靠
net start的返回码? 因为两种完全不同的结果都返回 2。 正确做法是先用sc query查状态,再决定要不要起。
常见误区
- 「设成自动就一定会起来」。不一定。 依赖没就绪、磁盘没挂上、账户密码过期,都会让它起不来。自动只代表「开机时会尝试」, 起没起要另外看。
- 「报服务名无效,就是没装」。多数时候是名字敲错了。
默认实例叫
MSSQLSERVER,不是SQLSERVER; 命名实例是MSSQL$SQLEXPRESS,中间是美元符号不是括号。 先核对名字,再怀疑安装。 - 「1068 是引擎坏了」。1068 只说明依赖链上有东西没起来。 顺着「依存关系」页往下找,找到第一个不在运行的服务——它才是要修的那个, 引擎本身可能一点问题都没有。
自测三问(点开对答案)
1. 为什么本机「正在运行」的服务比「自动」的还多? —— **因为「手动」不等于「不运行」。** 现代 Windows 大量服务是「按需触发」—— 有程序调它的接口就起来,用完再关。所以运行中的服务数会超过「自动」的配置数。 2. `net start MSSQLSERVER` 报「服务名无效」,最可能是什么原因? —— **实例名拼错了。** 默认实例是 `MSSQLSERVER`(中间没有空格),命名实例是 `MSSQL$SQLEXPRESS`。 把服务面板里的显示名 `SQL Server (MSSQLSERVER)` 整串敲进去,也会报这一句。 3. 看到「错误 1068:依赖服务或组无法启动」,第一步查什么? —— **查这个服务的「依存关系」页**,顺着依赖一层层往下找,找到第一个没在运行的服务。 SQL Server 代理报 1068,最常见的原因就是引擎没起——代理在等引擎。下一篇 3.3 讲「注册服务器」。 注意它不是「连接到服务器」——注册只是在 SSMS 里存一条记录,不验证、不缓存、不保持连接。 这一节的重点是把「注册」和「可用」这两件事分开。
- ☐ (本篇完,下一篇 3.3 注册 SQL Server 服务器)