在关系型数据库中,事务的实现通常采用“日志”(Log)技术。当一个事务开始时,系统将对所有需要修改的数据进行备份,并在内存缓冲区中维护一个日志记录。这些修改操作仅在事务提交时才被写回到磁盘上的数据库文件中,从而保证原始数据不会受到破坏。
如果事务执行过程中发生错误,例如系统崩溃、断电等,导致事务无法正常结束,则系统可以通过读取日志记录来恢复数据。具体步骤如下:
-
读取日志:系统首先会读取所有已经提交但还未写入磁盘的事务日志,并将其应用到数据库文件中,以恢复最新的数据状态。
-
恢复数据库:接下来,系统会根据日志中的操作记录,逆序地执行每个操作,并将其结果应用到数据库文件中,从而使数据库恢复到事务提交前的状态。
-
清空日志:一旦数据成功恢复,系统会将所有已经提交的事务日志清空,以准备下一次操作。
需要注意的是,由于事务日志需要占用额外的磁盘空间和系统资源,因此在设计系统时需要权衡日志文件大小和性能要求之间的平衡。
1.0首先需要安装 MySQL 的 Java 驱动程序,可以从官网下载相应版本的驱动文件,然后将其添加到项目类路径中。
接下来,我们连接数据库并创建一个新的表:
import java.sql.*;
public class Main {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try {
// 连接数据库
conn = DriverManager.getConnection("jdbc:mysql://localhost/mydatabase", "username", "password");
// 创建新表
stmt = conn.createStatement();
String createTableQuery = "CREATE TABLE customers (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255), address VARCHAR(255))";
stmt.executeUpdate(createTableQuery);
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭资源
try {
if (stmt != null) stmt.close();
if (conn != null) conn.close();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
}
2.0现在我们已经创建了一个 customers
表。接下来,我们将向该表插入两行数据,并将这些操作封装在一个事务中:
import java.sql.*;
public class Main {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
// 连接数据库
conn = DriverManager.getConnection("jdbc:mysql://localhost/mydatabase", "username", "password");
// 开始事务
conn.setAutoCommit(false);
// 插入第一行数据
String insertQuery = "INSERT INTO customers (name, address) VALUES (?, ?)";
pstmt = conn.prepareStatement(insertQuery);
pstmt.setString(1, "John");
pstmt.setString(2, "Highway 21");
pstmt.executeUpdate();
// 插入第二行数据
pstmt.setString(1, "Peter");
pstmt.setString(2, "Lowstreet 4");
pstmt.executeUpdate();
// 提交事务
conn.commit();
System.out.println("Transaction committed successfully!");
} catch (SQLException e) {
// 回滚事务
try {
if (conn != null) conn.rollback();
} catch (SQLException excep) {
excep.printStackTrace();
}
e.printStackTrace();
} finally {
// 关闭资源
try {
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
}
在上面的代码中,我们使用 setAutoCommit(false)
开始一个新的事务,并将两个插入操作封装在其中。如果事务执行成功,则使用 commit()
提交事务;否则,则使用 rollback()
回滚事务。