在关系型数据库中,事务的实现通常采用“日志”(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()
回滚事务。