Files
railwaysystem/scripts/qa/ValidateRealDbRollback.java

144 lines
6.7 KiB
Java

package scripts.qa;
import java.io.File;
import java.nio.file.Files;
import java.sql.*;
/**
* 真实 Kingbase 数据库 ROLLBACK-ONLY 事务回滚验证脚本。
* 严禁 COMMIT 任何测试数据。验证真实数据库事务原子性与回滚机制。
*/
public class ValidateRealDbRollback {
public static void main(String[] args) throws Exception {
Class.forName("com.kingbase8.Driver");
File envFile = new File(System.getProperty("user.home"), ".railwaysystem-qa.env");
String pass = "";
if (envFile.exists()) {
for (String line : Files.readAllLines(envFile.toPath())) {
line = line.trim();
if (line.startsWith("QA_DB_PASSWORD=")) {
pass = line.substring("QA_DB_PASSWORD=".length()).trim();
if (pass.startsWith("\"") && pass.endsWith("\"")) {
pass = pass.substring(1, pass.length() - 1);
}
}
}
}
if (pass.isEmpty()) {
throw new IllegalStateException("QA_DB_PASSWORD is required in ~/.railwaysystem-qa.env");
}
// 尝试直连或通过 SSH 端口转发 (14321) 连接
String dbUrl = "jdbc:kingbase8://127.0.0.1:14321/railwaysystem_integrated_qa_20260916?useUnicode=true&characterEncoding=utf8";
try (Connection conn = DriverManager.getConnection(dbUrl, "kingbase", pass)) {
System.out.println("CONNECTED_TO_DB=TRUE");
// 1. 验证当前数据库身份
try (Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT current_database(), current_user")) {
if (rs.next()) {
System.out.println("CURRENT_DATABASE=" + rs.getString(1));
System.out.println("CURRENT_USER=" + rs.getString(2));
if (!"railwaysystem_integrated_qa_20260916".equals(rs.getString(1))) {
throw new IllegalStateException("数据库身份不符,安全终止!");
}
}
}
// 2. 选择一条安全的已有记录读取原始状态
String targetPlanId = null;
int originalPlanStatus = -1;
long targetEnrollmentId = -1;
int originalEnrollmentStatus = -1;
String selectSampleSql = "SELECT p.plan_id, p.plan_status, e.enrollment_id, e.enrollment_status " +
"FROM train_class_plan p " +
"JOIN train_enrollment e ON e.plan_id = p.plan_id " +
"LIMIT 1";
try (Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(selectSampleSql)) {
if (rs.next()) {
targetPlanId = rs.getString(1);
originalPlanStatus = rs.getInt(2);
targetEnrollmentId = rs.getLong(3);
originalEnrollmentStatus = rs.getInt(4);
}
}
if (targetPlanId == null) {
System.out.println("NO_SAMPLE_DATA_FOUND");
return;
}
System.out.println(String.format("SAMPLE_BEFORE: plan_id=%s, plan_status=%d, enrollment_id=%d, enrollment_status=%d",
targetPlanId, originalPlanStatus, targetEnrollmentId, originalEnrollmentStatus));
// 3. 开启事务 (禁用 AutoCommit)
conn.setAutoCommit(false);
try {
// 在未提交事务中模拟结训更新
int mockPlanTargetStatus = (originalPlanStatus == 2) ? 1 : 2;
int mockEnrollmentTargetStatus = (originalEnrollmentStatus == 4) ? 1 : 4;
try (PreparedStatement pst = conn.prepareStatement(
"UPDATE train_class_plan SET plan_status = ?, update_time = now() WHERE plan_id = ?")) {
pst.setInt(1, mockPlanTargetStatus);
pst.setString(2, targetPlanId);
pst.executeUpdate();
}
try (PreparedStatement pst = conn.prepareStatement(
"UPDATE train_enrollment SET enrollment_status = ?, complete_time = now() WHERE enrollment_id = ?")) {
pst.setInt(1, mockEnrollmentTargetStatus);
pst.setLong(2, targetEnrollmentId);
pst.executeUpdate();
}
// 事务内查看临时修改值
int inTxPlanStatus = -1;
int inTxEnrollStatus = -1;
try (Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT p.plan_status, e.enrollment_status FROM train_class_plan p JOIN train_enrollment e ON e.plan_id = p.plan_id WHERE p.plan_id = '" + targetPlanId + "' AND e.enrollment_id = " + targetEnrollmentId)) {
if (rs.next()) {
inTxPlanStatus = rs.getInt(1);
inTxEnrollStatus = rs.getInt(2);
}
}
System.out.println(String.format("IN_TRANSACTION_MODIFIED: plan_status=%d, enrollment_status=%d", inTxPlanStatus, inTxEnrollStatus));
// 4. 显式执行主动 ROLLBACK (严禁 COMMIT)
conn.rollback();
System.out.println("TRANSACTION_ROLLED_BACK=TRUE");
} catch (Exception ex) {
conn.rollback();
throw ex;
} finally {
conn.setAutoCommit(true);
}
// 5. 验证回滚后数据完全恢复原样
int afterRollbackPlanStatus = -1;
int afterRollbackEnrollStatus = -1;
try (Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT p.plan_status, e.enrollment_status FROM train_class_plan p JOIN train_enrollment e ON e.plan_id = p.plan_id WHERE p.plan_id = '" + targetPlanId + "' AND e.enrollment_id = " + targetEnrollmentId)) {
if (rs.next()) {
afterRollbackPlanStatus = rs.getInt(1);
afterRollbackEnrollStatus = rs.getInt(2);
}
}
System.out.println(String.format("AFTER_ROLLBACK_VERIFIED: plan_status=%d, enrollment_status=%d", afterRollbackPlanStatus, afterRollbackEnrollStatus));
boolean intact = (originalPlanStatus == afterRollbackPlanStatus) && (originalEnrollmentStatus == afterRollbackEnrollStatus);
if (intact) {
System.out.println("REAL_DB_TRANSACTION_ROLLBACK_VALIDATION=PASS");
} else {
System.err.println("REAL_DB_TRANSACTION_ROLLBACK_VALIDATION=FAIL (Data altered!)");
System.exit(1);
}
}
}
}