前置:user 表 CRUD
TransactionDemo.java
package demo.jdbc;
import java.sql.Connection;import java.sql.SQLException;
public class TransactionDemo { public static void main(String[] args) throws Exception { UserDao dao = new UserDao(); try (Connection conn = Db.open()) { conn.setAutoCommit(false); try { transferEmail(conn, dao, "alice", "alice@example.com", "alice.tx@example.com"); conn.commit(); System.out.println("commit ok: alice email updated"); } catch (SQLException ex) { conn.rollback(); System.out.println("rollback: " + ex.getMessage()); }
try { transferEmail(conn, dao, "bob", "bob@example.com", "bob@example.com"); forceFail(); conn.commit(); } catch (Exception ex) { conn.rollback(); System.out.println("rollback expected: " + ex.getMessage()); System.out.println("bob still: " + dao.findById(conn, findIdByName(conn, dao, "bob")).map(User::getEmail)); } finally { conn.setAutoCommit(true); } } }
private static void transferEmail(Connection conn, UserDao dao, String userName, String expect, String next) throws SQLException { long id = findIdByName(conn, dao, userName); User user = dao.findById(conn, id).orElseThrow(); if (!expect.equals(user.getEmail())) { throw new SQLException("unexpected email for " + userName); } if (dao.updateEmail(conn, id, next) != 1) { throw new SQLException("update failed for " + userName); } }
private static long findIdByName(Connection conn, UserDao dao, String userName) throws SQLException { for (User u : dao.findByStatus(conn, 1)) { if (userName.equals(u.getUserName())) { return u.getId(); } } throw new SQLException("user not found: " + userName); }
private static void forceFail() { throw new IllegalStateException("simulate business error"); }}运行
mvn -q exec:java -Dexec.mainClass=demo.jdbc.TransactionDemo要点
setAutoCommit(false)后,同一Connection上的多次 DML 同属一个事务- 场景 1:
alice改邮箱 →commit持久化 - 场景 2:改
bob后抛异常 →rollback,邮箱仍为bob@example.com
Spring @Transactional 底层即为此逻辑,由 DataSourceTransactionManager 绑定连接。
下一篇:JdbcTemplate