数据库系统保证在一个事务中的所有SQL要么全部执行成功,要么全部不执行。就像转账一样、任何一方出现异常,那么转账就无法成功。
JDBC事务,就是在Java中用来控制数据库事务的。JDBC的一切行为包括事务是基于一个Connection的,通过Connection对象进行事务管理。常用的和事务相关的方法是: setAutoCommit、commit、rollback等。
新建Java项目、模拟银行转账功能、使用JDBC事务保证数据的完整性。
public class DBUtils { private static final ResourceBundle resourceBundle; private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>(); static { resourceBundle = ResourceBundle.getBundle("db"); try { Class.forName(resourceBundle.getString("dirver")); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() { Connection conn = threadLocal.get(); try { if (conn == null) { conn = DriverManager.getConnection(resourceBundle.getString("url"), resourceBundle.getString("user"), resourceBundle.getString("password")); threadLocal.set(conn); } } catch (SQLException sqlException) { sqlException.printStackTrace(); } return conn; } public static void closeDb(Connection conn, Statement statement, ResultSet rs) { try { if (conn != null) { conn.close(); threadLocal.remove();//释放连接后,将threadlocal中的连接对象移除 } if (statement != null) { statement.close(); } if (rs != null) { rs.close(); } } catch (SQLException sqlException) { sqlException.printStackTrace(); } } //开启事务 public static void begin() { try { Connection conn = getConnection(); conn.setAutoCommit(false); } catch (SQLException sqlException) { sqlException.printStackTrace(); } } public static void commit() { Connection conn = null; try { conn = getConnection(); conn.commit(); } catch (SQLException sqlException) { sqlException.printStackTrace(); } finally { //提交事务后释放连接资源 closeDb(conn, null, null); } } public static void rollback() { Connection conn = null; try { conn = getConnection(); conn.rollback(); } catch (SQLException sqlException) { sqlException.printStackTrace(); } finally { //回滚后释放连接资源 closeDb(conn, null, null); } }
public interface AccountDao { //根据id查询表数据 public Account select(int id); //修改Account表数据 public int update(Account account); }
public class AccountDaoImpl implements AccountDao { @Override public Account select(int id) { //实例化Account对象 Account account = new Account(); PreparedStatement preparedStatement = null; ResultSet rs = null; try { //根据卡号查询表数据 String sql = "select id,pwd,balance,name from Account where id=?"; Connection conn = DBUtils.getConnection(); preparedStatement = conn.prepareStatement(sql); preparedStatement.setInt(1, id); rs = preparedStatement.executeQuery(); while (rs.next()) { int aid = rs.getInt(1); String pwd = rs.getString(2); double balance = rs.getDouble(3); String name = rs.getString(4); account.setId(aid); account.setPwd(pwd); account.setBalance(balance); account.setName(name); } } catch (SQLException sqlException) { sqlException.printStackTrace(); } finally { DBUtils.closeDb(null, preparedStatement, rs); } return account; } public int update(Account account) { Connection conn = null; PreparedStatement preparedStatement = null; String sql = "update Account set pwd=?,balance=?,name=? where id=?"; try { conn = DBUtils.getConnection(); preparedStatement = conn.prepareStatement(sql); preparedStatement.setString(1, account.getPwd()); preparedStatement.setDouble(2, account.getBalance()); preparedStatement.setString(3, account.getName()); preparedStatement.setInt(4, account.getId()); int result = preparedStatement.executeUpdate(); return result; } catch (SQLException sqlException) { sqlException.printStackTrace(); } finally { DBUtils.closeDb(null, preparedStatement, null); } return 0; }
public interface AccountService { /** * * @param fromId:转账卡号 * @param toId:接收转账卡号 * @param pwd:密码 * @param money:转账金额 */ public void transfer(int fromId, int toId, String pwd, double money); }
@Override public void transfer(int fromId, int toId, String pwd, double money) { AccountDao accountDao = new AccountDaoImpl(); try { //开启事务 DBUtils.begin(); Account account = accountDao.select(fromId); //判断卡号是否正确 if (account == null) { throw new RuntimeException("卡号有误"); } //判断密码是否正确 if (!pwd.equals(account.getPwd())) { throw new RuntimeException("密码有误"); } //判断金额是否充足 if (account.getBalance() < money) { throw new RuntimeException("余额不足"); } Account toAccount = accountDao.select(toId); //判断对方卡号是否正确 if (toAccount == null) { throw new RuntimeException("对方卡号不存在"); } //修改账户金额、减去转账金额 account.setBalance(account.getBalance() - money); accountDao.update(account); //修改对方账户金额,加上转入金额 toAccount.setBalance(toAccount.getBalance() + money); accountDao.update(toAccount); System.out.println("转账成功"); //提交事务 DBUtils.commit(); } catch (RuntimeException e) { System.out.println("转账失败"); DBUtils.rollback();//回滚事务 e.printStackTrace(); } }
概括来讲、就是先设置conn.setAutoCommit(false)、代码顺利执行完成后使用conn.commit()提交事务,如果有异常就rollback()回滚事务。另外、不管是提交事务还是回滚事务,都要将连接对象释放。