Java 下载地址
| 来源 | 地址 |
|---|---|
| 官方发布页 | Temurin 21.0.12.1 |
| 官方安装包 | Windows x64 JRE ZIP |
| 国内镜像一 | 清华大学 |
| 国内镜像二 | 南京大学 |
下载顺序:官方 → 清华 → 南京大学。官方连续 5 秒平均速度低于 1 MiB/s(约 1 MB/s),或 30 秒内没有下载完,自动切换国内镜像。国内镜像每个最多等待 1800 秒;连接失败或 SHA256 不符则尝试下一源。已有校验通过的安装包会直接复用。
故障清单
| 编号 | 日期 | 故障现象 | 定位结果 | 处理结果 |
|---|---|---|---|---|
| 001 | 2026-10-20 | 堡垒机 DBeaver 反复崩溃,持续产生大体积 .mdmp 文件 | Java 21.0.5 的 AWT 图形模块在处理显示设备变化时崩溃,与远程桌面显示切换相关缺陷吻合 | 单独切换至 Java 21.0.12.1;实际 JVM 路径已核对,多次远程桌面断开、重连后未新增崩溃文件;删除 132 个历史崩溃文件,释放 36.51 GiB |
001 堡垒机 DBeaver 崩溃及转储文件增长
1. 环境和原因
| 项目 | 本次信息 |
|---|---|
| 服务器 | iZknjq99u9wk14Z,内网 IP 172.19.223.223 |
| 系统 | Windows Server 2025 Datacenter,64 位 |
| DBeaver | 25.2.0,安装在当前 Administrator 用户目录 |
| 原 Java | DBeaver 自带 Temurin 21.0.5 |
| 新 Java | Temurin 21.0.12.1 |
| 故障代码 | EXCEPTION_ACCESS_VIOLATION (0xc0000005) |
| 故障模块 | awt.dll,线程 AWT-EventQueue-0 |
| 关键调用栈 | Win32GraphicsConfig.getBounds、Win32GraphicsDevice.initNativeScale、displayChanged |
DBeaver 要求 Java 21,原 Java 的主版本符合要求。本次处理针对旧 Java 补丁中的图形模块问题,不需要调整项目代码或数据库配置。
操作方式:下载新 Java → 解压到 DBeaver 的 runtimes → 在 dbeaver.ini 中指定新 Java → 重启 DBeaver 生效。没有修改系统 PATH、JAVA_HOME 或 PyCharm。
runtimes 是本次修复创建的目录,需要保留。正常启动这份 DBeaver,包括服务器重启后,都会继续使用配置指定的新 Java。
2. 排查命令
在堡垒机上打开管理员 PowerShell。以下路径针对本次机器,其他机器使用时先调整。
正常处理按第 2~6 节的 PowerShell 代码块逐段执行,使用同一个窗口;标为 text 的内容只是路径或配置示例,不需要执行。回退是最后单独的可选操作,默认跳过。第 3 步失败就停止,不继续执行后面的步骤。
$ErrorActionPreference = 'Stop'
$db = Join-Path $env:LOCALAPPDATA 'DBeaver'
$case = Join-Path $db '10.20故障排查'
$jbrBin = 'C:\Program Files\JetBrains\PyCharm 2024.1.7\jbr\bin'
$JavaReady = $false
$DBeaverVerified = $false
查看登录用户和当前连接,避免操作时影响其他人:
quser
Get-NetTCPConnection -State Established | ForEach-Object {
[pscustomobject]@{
Process = (Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).ProcessName
PID = $_.OwningProcess
LocalPort = $_.LocalPort
RemoteIP = $_.RemoteAddress
RemotePort = $_.RemotePort
}
} | Sort-Object Process, RemoteIP | Format-Table -AutoSize
连接存在不等于正在执行 SQL。本次只有 Administrator 一个登录会话,未见明显的外部数据库连接。
查看系统、Java 版本和启动配置:
Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, OSArchitecture
$iniText = [IO.File]::ReadAllText("$db\dbeaver.ini")
$vm = [regex]::Match($iniText, '(?m)^[ \t]*-vm[ \t]*\r?\n([^\r\n]+)')
if ($vm.Success) {
$javaPath = $vm.Groups[1].Value.Trim().Trim('"')
if (![IO.Path]::IsPathRooted($javaPath)) { $javaPath = Join-Path $db $javaPath }
$javaHome = Split-Path (Split-Path $javaPath -Parent) -Parent
if (!(Test-Path -LiteralPath "$javaHome\release")) { throw '请核对 -vm 指定的 Java 路径。' }
Get-Content -LiteralPath "$javaHome\release" |
Select-String '^(JAVA_VERSION|IMPLEMENTOR|OS_ARCH)='
} elseif (Test-Path -LiteralPath "$db\jre\release") {
Get-Content -LiteralPath "$db\jre\release" | Select-String '^(JAVA_VERSION|IMPLEMENTOR|OS_ARCH)='
} else { '未找到默认 jre,请核对下面的启动配置。' }
$iniText
查看崩溃文件和最近一次调用栈,不要用文本工具打开大型 .mdmp:
Get-ChildItem -LiteralPath $db -File | Where-Object Name -match '^hs_err_pid\d+\.(log|mdmp)$' |
Sort-Object LastWriteTime -Descending |
Select-Object Name, @{N='MB';E={[math]::Round($_.Length / 1MB, 2)}}, LastWriteTime
$log = Get-ChildItem -LiteralPath $db -Filter 'hs_err_pid*.log' -File |
Sort-Object LastWriteTime -Descending | Select-Object -First 1
if ($log) {
Select-String -LiteralPath $log.FullName `
-Pattern '^#.*JRE version:|^#.*Problematic frame:|^Current thread|^Java frames:' `
-Context 0, 25 | Out-String -Width 240
}
本次最新日志使用的是 DBeaver 自带 Java 21.0.5,不是 PyCharm 的 Java 17。仅凭文件保存在 PyCharm 目录下,不能确定是哪个程序崩溃,应看对应 .log。
3. 下载并切换 Java
首次切换前保存工作并退出 DBeaver,然后执行下面整段。已配置本次新 Java 时直接跳过,不需要退出,也不重复下载或切换。下载、校验或 Java 检查失败都会停止,不修改启动配置。每次首次解压使用独立的新目录,不覆盖或移动任何已有 Java。以后更换版本时,三个下载地址、版本检查和官方 SHA256 要一起更新。
$JavaReady = $false
$DBeaverVerified = $false
& {
$ErrorActionPreference = 'Stop'
$ini = Join-Path $db 'dbeaver.ini'
if (!(Test-Path -LiteralPath $ini)) { throw '未找到 DBeaver 配置。' }
$text = [IO.File]::ReadAllText($ini)
$currentVm = [regex]::Match($text, '(?m)^[ \t]*-vm[ \t]*\r?\n([^\r\n]+)')
if ($currentVm.Success) {
$currentJava = $currentVm.Groups[1].Value.Trim().Trim('"')
if (![IO.Path]::IsPathRooted($currentJava)) { $currentJava = Join-Path $db $currentJava }
$currentJava = [IO.Path]::GetFullPath($currentJava)
$currentHome = Split-Path (Split-Path $currentJava -Parent) -Parent
if ($currentJava.StartsWith("$db\runtimes\", [StringComparison]::OrdinalIgnoreCase) -and
(Test-Path -LiteralPath $currentJava) -and
(Test-Path -LiteralPath "$currentHome\release") -and
(Select-String -LiteralPath "$currentHome\release" -Pattern '^JAVA_VERSION="21\.0\.12\.1(?:\+[^\"]*)?"' -Quiet)) {
Write-Host "已配置新 Java,保留原位并跳过切换:$currentJava"
$script:JavaReady = $true
return
}
}
if (Get-Process -Name dbeaver,dbeaver-cli -ErrorAction SilentlyContinue) {
throw '请先退出 DBeaver。'
}
if ((Test-Path -LiteralPath $case) -and
((Get-Item -LiteralPath $case).Attributes -band [IO.FileAttributes]::ReparsePoint)) {
throw '资料目录是链接,请先核对路径。'
}
New-Item -ItemType Directory -Path $case -Force | Out-Null
$curl = (Get-Command curl.exe -ErrorAction Stop).Source
$name = 'OpenJDK21U-jre_x64_windows_hotspot_21.0.12.1_1.zip'
$zip = Join-Path $case $name
$expected = 'D35F31E712F0FCF6AC5A093EDC90204FBFF22F720BA3950BD09D331D5E621636'
$sources = @(
@{Name='官方'; Url="https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.12.1%2B1/$name"; Timeout=30; CheckSpeed=$true}
@{Name='清华'; Url="https://mirrors.tuna.tsinghua.edu.cn/Adoptium/21/jre/x64/windows/$name"; Timeout=1800; CheckSpeed=$false}
@{Name='南京大学'; Url="https://mirror.nju.edu.cn/adoptium/21/jre/x64/windows/$name"; Timeout=1800; CheckSpeed=$false}
)
function Get-JavaPackage {
param($Sources, $Zip, $Expected, $Curl)
if ((Test-Path -LiteralPath $Zip) -and
(Get-FileHash -LiteralPath $Zip -Algorithm SHA256).Hash -eq $Expected) {
Write-Host "复用已校验的安装包:$Zip"
return
}
$part = "$Zip.part"
$errorFile = "$Zip.download-error.txt"
foreach ($source in $Sources) {
Write-Host "正在从$($source.Name)下载……"
$curlArgs = @('--fail', '--location', '--silent', '--show-error',
'--stderr', $errorFile, '--connect-timeout', '10',
'--max-time', [string]$source.Timeout, '--output', $part)
if ($source.CheckSpeed) {
$curlArgs += @('--speed-limit', '1048576', '--speed-time', '5')
}
$PSNativeCommandUseErrorActionPreference = $false
& $Curl @curlArgs $source.Url
$exitCode = $LASTEXITCODE
if ($exitCode -eq 0 -and (Test-Path -LiteralPath $part) -and
(Get-FileHash -LiteralPath $part -Algorithm SHA256).Hash -eq $Expected) {
Move-Item -LiteralPath $part -Destination $Zip -Force
Write-Host "$($source.Name)下载完成,SHA256 校验通过。"
return
}
if (Test-Path -LiteralPath $part) { Remove-Item -LiteralPath $part -Force }
Write-Host "$($source.Name)下载失败、超时、速度不足或校验不符,尝试下一源。"
}
throw "所有来源均未取得校验通过的安装包,未修改配置。下载错误见:$errorFile"
}
Get-JavaPackage -Sources $sources -Zip $zip -Expected $expected -Curl $curl
$stamp = Get-Date -Format 'yyyyMMdd_HHmmss_fff'
$target = Join-Path $db "runtimes\temurin21_$stamp"
$runtimeRoot = Join-Path $db 'runtimes'
if ((Test-Path -LiteralPath $runtimeRoot) -and
((Get-Item -LiteralPath $runtimeRoot).Attributes -band [IO.FileAttributes]::ReparsePoint)) {
throw 'runtimes 是链接,未解压或修改配置。'
}
New-Item -ItemType Directory -Path $target | Out-Null
Expand-Archive -LiteralPath $zip -DestinationPath $target
$runtime = Get-ChildItem -LiteralPath $target -Directory | Where-Object {
Test-Path -LiteralPath (Join-Path $_.FullName 'bin\javaw.exe')
} | Select-Object -First 1
if (!$runtime) { throw '解压后未找到 Java。' }
if (!(Select-String -LiteralPath "$($runtime.FullName)\release" `
-Pattern '^JAVA_VERSION="21\.0\.12\.1(?:\+[^\"]*)?"' -Quiet)) {
throw '解压后的 Java 版本不符,未修改配置。'
}
$java = Join-Path $runtime.FullName 'bin\java.exe'
$javaw = Join-Path $runtime.FullName 'bin\javaw.exe'
$versionFile = Join-Path $target 'java-version.txt'
$test = Start-Process -FilePath $java -ArgumentList '-version' `
-WindowStyle Hidden -Wait -PassThru -RedirectStandardError $versionFile
Get-Content -LiteralPath $versionFile
if ($test.ExitCode -ne 0) { throw '新 Java 启动失败。' }
$match = [regex]::Match($text, '(?m)^[ \t]*-vmargs[ \t]*\r?$')
if (!$match.Success) { throw '未找到 -vmargs,未修改配置。' }
$before = $text.Substring(0, $match.Index)
$before = [regex]::Replace($before, '(?m)^[ \t]*-vm[ \t]*\r?\n[^\r\n]*(?:\r?\n|$)', '')
$newText = "-vm`r`n$javaw`r`n" + $before + $text.Substring($match.Index)
if (Get-Process -Name dbeaver,dbeaver-cli -ErrorAction SilentlyContinue) {
throw 'DBeaver 已启动,请退出后重试。'
}
if ([IO.File]::ReadAllText($ini) -cne $text) { throw '配置已变化,请重试。' }
$backup = Join-Path $case "dbeaver.ini.before-java21-$stamp.bak"
$temp = "$ini.new-$stamp"
[IO.File]::WriteAllText($temp, $newText, [Text.UTF8Encoding]::new($false))
$stateFile = Join-Path $case 'java21-repair.json'
$stateTemp = Join-Path $case "java21-repair.new-$stamp.json"
$state = @{
ChangedAtUtc = (Get-Date).ToUniversalTime().ToString('o')
JavaHome = $runtime.FullName
Backup = $backup
DBeaverRoot = $db
}
$state | ConvertTo-Json | Set-Content -LiteralPath $stateTemp -Encoding UTF8
if (Test-Path -LiteralPath $stateFile) {
Copy-Item -LiteralPath $stateFile -Destination "$case\java21-repair.before-$stamp.json"
}
[IO.File]::Replace($temp, $ini, $backup)
Move-Item -LiteralPath $stateTemp -Destination $stateFile -Force
$script:JavaReady = $true
Write-Host "已切换:$javaw"
Write-Host "配置备份:$backup"
}
-vm 和 Java 路径必须各占一行,放在 -vmargs 前面。配置示例:
-vm
C:\Users\Administrator\AppData\Local\DBeaver\runtimes\temurin21_20261020_150658\jdk-21.0.12.1+1-jre\bin\javaw.exe
4. 启动并验证
打开 DBeaver,测试数据库连接和简单查询,再进行几次远程桌面断开、重连。
if (!$JavaReady) { throw '第 3 步未成功,请停止后续操作。' }
if (!(Get-Process -Name dbeaver -ErrorAction SilentlyContinue)) {
Start-Process -FilePath "$db\dbeaver.exe" -WorkingDirectory $db
}
查看实际使用的新 Java。本次 DBeaver 启动了单独的 javaw.exe 子进程,因此不能只检查 dbeaver.exe 的模块:
$DBeaverVerified = $false
if (!$JavaReady) { throw '第 3 步未成功,请停止后续操作。' }
$stateFile = "$case\java21-repair.json"
if (!(Test-Path -LiteralPath $stateFile)) { $stateFile = "$db\java21-repair.json" }
$state = Get-Content -LiteralPath $stateFile -Raw | ConvertFrom-Json
$javaw = Join-Path $state.JavaHome 'bin\javaw.exe'
$vm = [regex]::Match([IO.File]::ReadAllText("$db\dbeaver.ini"), '(?m)^[ \t]*-vm[ \t]*\r?\n([^\r\n]+)')
if (!$vm.Success -or $vm.Groups[1].Value.Trim().Trim('"') -ine $javaw) {
throw '启动配置与修复记录不一致,请核对,暂不清理或整理。'
}
$all = @(Get-CimInstance Win32_Process)
$ids = @($all | Where-Object Name -eq 'dbeaver.exe' | ForEach-Object ProcessId)
if (!$ids.Count) { throw 'DBeaver 未运行,请打开后重试。' }
do {
$children = @($all | Where-Object {
$_.ParentProcessId -in $ids -and $_.ProcessId -notin $ids
} | ForEach-Object ProcessId)
$ids += $children
} while ($children.Count)
$javaProcesses = @($all | Where-Object {
$_.ProcessId -in $ids -and $_.Name -eq 'javaw.exe' -and $_.ExecutablePath -ieq $javaw
})
if (!$javaProcesses.Count) { throw '未找到使用新 Java 的进程,需继续核对。' }
$javaProcesses | Select-Object ProcessId, ParentProcessId, ExecutablePath
foreach ($p in $javaProcesses) {
(Get-Process -Id $p.ProcessId).Modules | Where-Object ModuleName -eq 'jvm.dll' |
Select-Object FileName
}
$since = [datetimeoffset]::Parse($state.ChangedAtUtc).UtcDateTime
$newCrashes = @(Get-ChildItem -LiteralPath $db -File | Where-Object {
$_.Name -match '^hs_err_pid\d+\.(log|mdmp)$' -and $_.LastWriteTimeUtc -ge $since
})
if ($newCrashes.Count) {
$newCrashes | Select-Object Name, Length, LastWriteTime
throw '发现新的崩溃文件,停止清理和整理,继续排查。'
} else {
'未发现新的崩溃文件。'
$DBeaverVerified = $true
}
本次确认的新 Java 路径:
C:\Users\Administrator\AppData\Local\DBeaver\runtimes\temurin21_20261020_150658\jdk-21.0.12.1+1-jre
5. 清理历史崩溃文件
完成上面的验证后执行。只清理两个指定目录中、修复时间之前的 hs_err_pid数字.log/.mdmp,不递归。文本日志先备份,配置和软件文件保留。
& {
$ErrorActionPreference = 'Stop'
if (!$DBeaverVerified) { throw '请先完成第 4 步验证,未删除文件。' }
$stateFile = "$case\java21-repair.json"
if (!(Test-Path -LiteralPath $stateFile)) { $stateFile = "$db\java21-repair.json" }
$state = Get-Content -LiteralPath $stateFile -Raw | ConvertFrom-Json
$vm = [regex]::Match([IO.File]::ReadAllText("$db\dbeaver.ini"), '(?m)^[ \t]*-vm[ \t]*\r?\n([^\r\n]+)')
if (!$vm.Success -or $vm.Groups[1].Value.Trim().Trim('"') -ine (Join-Path $state.JavaHome 'bin\javaw.exe')) {
throw 'Java 配置已变化,未删除文件。'
}
$since = [datetimeoffset]::Parse($state.ChangedAtUtc).UtcDateTime
$files = @(foreach ($root in @($db, $jbrBin)) {
if (Test-Path -LiteralPath $root) {
Get-ChildItem -LiteralPath $root -File | Where-Object {
$_.Name -match '^hs_err_pid\d+\.(log|mdmp)$'
}
}
})
if (@($files | Where-Object LastWriteTimeUtc -ge $since).Count) {
throw '存在修复后产生的崩溃文件,先排查,暂不清理。'
}
$old = @($files | Where-Object {
$_.CreationTimeUtc -lt $since -and $_.LastWriteTimeUtc -lt $since -and
!($_.Attributes -band [IO.FileAttributes]::ReparsePoint)
})
if (!$old.Count) { '没有需要清理的历史崩溃文件。'; return }
$backup = Join-Path $case ('crash-backup_' + (Get-Date -Format 'yyyyMMdd_HHmmss_fff'))
New-Item -ItemType Directory -Path $backup | Out-Null
$old | Select-Object FullName, Length, LastWriteTimeUtc |
Export-Csv "$backup\清理清单.csv" -NoTypeInformation -Encoding UTF8
$i = 0
foreach ($file in ($old | Where-Object Extension -eq '.log')) {
$i++
Copy-Item -LiteralPath $file.FullName -Destination (
Join-Path $backup ("{0:D4}_{1}" -f $i, $file.Name)
)
}
$freed = [long]0
$count = 0
foreach ($file in $old) {
$current = Get-Item -LiteralPath $file.FullName
if ($current.Length -ne $file.Length -or
$current.CreationTimeUtc -ne $file.CreationTimeUtc -or
$current.LastWriteTimeUtc -ne $file.LastWriteTimeUtc) { continue }
Remove-Item -LiteralPath $file.FullName -Force
$freed += $file.Length
$count++
}
'删除 {0} 个文件,释放 {1:N2} GiB;文本日志备份:{2}' -f $count, ($freed / 1GB), $backup
}
本次实际删除 132 个文件,释放 36.51 GiB。保留的文本日志、清单约 6.35 MB,配置备份 1.43 KB,修复记录 0.3 KB;另保留原 Java 54.48 MB、下载包 46.73 MB,合计约 107.56 MB。
6. 资料整理和回退
统一资料目录及主要文件:
C:\Users\Administrator\AppData\Local\DBeaver\10.20故障排查
├─ crash-backup_20261020_151514\ 文本日志及清理清单
├─ dbeaver.ini.before-java21-20261020_150658.bak
├─ java21-repair.json
├─ 旧Java_jre\ 原 Java,用于回退
└─ OpenJDK21U-jre_x64_windows_hotspot_21.0.12.1_1.zip
整理现有资料时使用以下命令;已整理的项目会跳过,目标存在时保留双方、不覆盖。只收集根目录的日志备份、配置备份、修复记录、未使用的原 jre 和本次下载包。当前 runtimes 和正在使用的 dbeaver.ini 保持原位。
& {
$ErrorActionPreference = 'Stop'
if (!$DBeaverVerified) { throw '请先完成第 4 步验证,未移动资料。' }
if ((Test-Path -LiteralPath $case) -and
((Get-Item -LiteralPath $case).Attributes -band [IO.FileAttributes]::ReparsePoint)) {
throw '资料目录是链接,未移动资料。'
}
$stateFile = "$case\java21-repair.json"
if (!(Test-Path -LiteralPath $stateFile)) { $stateFile = "$db\java21-repair.json" }
$state = Get-Content -LiteralPath $stateFile -Raw | ConvertFrom-Json
$javaw = Join-Path $state.JavaHome 'bin\javaw.exe'
$vm = [regex]::Match([IO.File]::ReadAllText("$db\dbeaver.ini"), '(?m)^[ \t]*-vm[ \t]*\r?\n([^\r\n]+)')
if (!$vm.Success -or $vm.Groups[1].Value.Trim().Trim('"') -ine $javaw -or
!$javaw.StartsWith("$db\runtimes\", [StringComparison]::OrdinalIgnoreCase)) {
throw '未确认配置使用 runtimes 内的新 Java,停止整理。'
}
$oldUsers = @(Get-CimInstance Win32_Process | Where-Object {
$_.ExecutablePath -and $_.ExecutablePath.StartsWith(
"$db\jre\", [StringComparison]::OrdinalIgnoreCase)
})
if ($oldUsers.Count) { throw '原 jre 仍有进程使用,停止整理。' }
New-Item -ItemType Directory -Path $case -Force | Out-Null
$sources = @(Get-ChildItem -LiteralPath $db -Directory -Filter 'crash-backup_*' |
ForEach-Object FullName)
$sources += @(Get-ChildItem -LiteralPath $db -File -Filter 'dbeaver.ini.before-java21-*.bak' |
ForEach-Object FullName)
$download = Join-Path $env:USERPROFILE 'Downloads\DBeaver-Java21_20261020_150050\OpenJDK21U-jre_x64_windows_hotspot_21.0.12.1_1.zip'
$sources += @("$db\java21-repair.json", "$db\jre", $download)
$stamp = Get-Date -Format 'yyyyMMdd_HHmmss_fff'
foreach ($source in $sources) {
if (!(Test-Path -LiteralPath $source)) { continue }
$name = Split-Path $source -Leaf
if ($name -eq 'jre') { $name = '旧Java_jre' }
if ($name -eq 'java21-repair.json' -and (Test-Path -LiteralPath "$case\java21-repair.json")) {
$name = "java21-repair.root-copy-$stamp.json"
}
$target = Join-Path $case $name
$sourceFull = (Resolve-Path -LiteralPath $source).ProviderPath
$targetFull = [IO.Path]::GetFullPath($target)
if (!$targetFull.StartsWith("$case\", [StringComparison]::OrdinalIgnoreCase) -or
(!$sourceFull.StartsWith("$db\", [StringComparison]::OrdinalIgnoreCase) -and $sourceFull -ine $download)) {
throw '整理路径越界。'
}
if ($sourceFull -ine [IO.Path]::GetFullPath($source) -or
((Get-Item -LiteralPath $source).Attributes -band [IO.FileAttributes]::ReparsePoint)) {
throw "源路径不符合预期:$source"
}
if (Test-Path -LiteralPath $target) { Write-Host "目标已存在,保留双方:$target"; continue }
Move-Item -LiteralPath $sourceFull -Destination $targetFull
}
$archivedBackup = Join-Path $case (Split-Path $state.Backup -Leaf)
if ($state.Backup -ine $archivedBackup -and (Test-Path -LiteralPath $archivedBackup)) {
if (!(Test-Path -LiteralPath $state.Backup) -or
(Get-FileHash -LiteralPath $state.Backup).Hash -eq (Get-FileHash -LiteralPath $archivedBackup).Hash) {
$state.Backup = $archivedBackup
$state | ConvertTo-Json | Set-Content "$case\java21-repair.json" -Encoding UTF8
}
}
Get-ChildItem -LiteralPath $case | Select-Object Name, Mode
}
可选:需要时回退
正常处理不执行回退。下面默认 $RunRollback = $false,按顺序复制也只会提示跳过;只有需要恢复旧 Java 时,才改成 $true,并先保存工作、退出 DBeaver。回退不删除或移动新 Java。
& {
$ErrorActionPreference = 'Stop'
$RunRollback = $false
if (!$RunRollback) { '正常流程跳过回退。'; return }
$state = Get-Content "$case\java21-repair.json" -Raw | ConvertFrom-Json
$active = @(Get-CimInstance Win32_Process | Where-Object {
$_.Name -match '^dbeaver.*\.exe$' -or
($_.ExecutablePath -and $_.ExecutablePath.StartsWith(
"$($state.JavaHome)\", [StringComparison]::OrdinalIgnoreCase))
})
if ($active.Count) { throw '请先保存工作并退出 DBeaver。' }
if (!(Test-Path -LiteralPath $state.Backup)) { throw '找不到原配置备份。' }
$backupText = [IO.File]::ReadAllText($state.Backup)
if ([IO.File]::ReadAllText("$db\dbeaver.ini") -ceq $backupText) {
'当前配置已与原备份一致,无需重复回退。'; return
}
$oldJava = Join-Path $case '旧Java_jre'
$originalJava = Join-Path $db 'jre'
$backupVm = [regex]::Match($backupText, '(?m)^[ \t]*-vm[ \t]*\r?\n([^\r\n]+)')
if (!$backupVm.Success -and !(Test-Path -LiteralPath "$originalJava\bin\javaw.exe")) {
if (!(Test-Path -LiteralPath "$oldJava\bin\javaw.exe")) { throw '原 Java 不完整,未回退。' }
if (Test-Path -LiteralPath $originalJava) { throw '原 jre 位置已有内容,请先核对。' }
if ((Split-Path ([IO.Path]::GetFullPath($oldJava)) -Parent) -ine $case -or
(Split-Path ([IO.Path]::GetFullPath($originalJava)) -Parent) -ine $db) {
throw 'Java 回退路径越界。'
}
Move-Item -LiteralPath $oldJava -Destination $originalJava
}
if ($backupVm.Success) {
$backupJava = $backupVm.Groups[1].Value.Trim().Trim('"')
if (![IO.Path]::IsPathRooted($backupJava)) { $backupJava = Join-Path $db $backupJava }
if (!(Test-Path -LiteralPath $backupJava)) { throw '备份指定的 Java 不存在,未回退。' }
}
Copy-Item -LiteralPath "$db\dbeaver.ini" -Destination (
Join-Path $case ('dbeaver.ini.回退前_' + (Get-Date -Format 'yyyyMMdd_HHmmss_fff') + '.bak')
)
Copy-Item -LiteralPath $state.Backup -Destination "$db\dbeaver.ini" -Force
'已恢复原配置和原 Java,重新打开 DBeaver 生效。'
}