JDBC中的事务-Transaction

时间:2022-07-18 22:18:01
JDBC中的事务-Transaction

事务-Transaction

某些情况下我们希望对数据库的某一操作要么整体成功,要么整体失败,经典的例子就是支付宝提现。例如我们发起了支付宝到银行卡的100元提现申请,我们希望的结果是支付宝余额减少100元,银行卡余额增加100元,而不是支付宝的100元被扣除,而银行卡的100元却没收到。也就是说,要么100元从支付宝扣除的同时银行卡也会多出一百元,要么这次提现失败支付宝的100元还在,银行卡也没有收到钱。支付宝扣钱和银行卡收钱,这两件事要么都成功要么都失败。

JDBC中的事务-Transaction

事物的ACID特性:

满足ACID特性的操作,我们可以说它是一个事物。

  1. 原子性:该操作是最小逻辑单元整体,已经不可分隔。
  2. 一致性:要么所有都执行,要么所有都不执行。
  3. 隔离性:多个事务相互隔离,互不影响。
  4. 持久性:事物的执行结果永久生效。

JDBC中的事务-Transaction

对事物的控制:

在JDBC中可以调用Connection对象的setAutoCommit(false)这个接口,将commit()之前的所有操作都看成是一个事物。同时,如果事务执行过程中发生异常,可以调用rollback()接口进行回滚到事务开始之前的状态。

JDBC中的事务-Transaction

示例代码:

下面代码演示了将cjk的100元转账到ly的账户上:

package org.lyk.main;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import org.apache.commons.dbcp2.BasicDataSource;

public class Main

{

public static String DBDRIVER = "com.mysql.jdbc.Driver";

public static String DB_URL = "jdbc:mysql://localhost:3306/mldn";

public static String USERNAME = "root";

public static String PASSWORD = "admin";

public static BasicDataSource bds = null;

public static void main(String[] args)

{

dbPoolInit();

transferAmount();

System.out.println("///Done~~~");

}

public static void dbPoolInit()

{

bds = new BasicDataSource();

bds.setDriverClassName(DBDRIVER);

bds.setUrl(DB_URL);

bds.setUsername(USERNAME);

bds.setPassword(PASSWORD);

}

public static boolean transferAmount()

{

boolean retVal = true;

String sql = "UPDATE user SET amount=? WHERE userid=?";

Connection conn = null;

PreparedStatement stmt = null;

ResultSet rs = null;

try

{

conn = bds.getConnection();

conn.setAutoCommit(false);

stmt = conn.prepareStatement(sql);

stmt.setInt(1, 0);

stmt.setString(2, "cjk");

stmt.execute();

stmt.setInt(1, 100);

stmt.setString(2, "ly");

stmt.execute();

conn.commit();

} catch (SQLException e)

{

// TODO Auto-generated catch block

e.printStackTrace();

try

{

conn.rollback();

} catch (SQLException e1)

{

// TODO Auto-generated catch block

e1.printStackTrace();

}

}

finally

{

try

{

if(conn != null)

conn.close();

if(stmt != null)

stmt.close();

if(rs != null)

rs.close();

}

catch(Exception e)

{

//ignore all exceptions when closing...

}

}

return retVal;

}

}

事务断点(Savepoint):

某些时候,我们对一个事物操作失败,我们并不像回滚到最初状态,而是回滚到事务开始后的某一个地方,这时我们可以使用断点的方式让事物回滚到指定的断点(Savepoint)上.

示例代码:

下面的代码演示了如果cjk的100元转账到ly失败的话,我们将这100元转到cyx的账户上。(其中用手动跑出异常的方式模拟cjk到ly的转账失败)

package org.lyk.main;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.sql.Savepoint;

import org.apache.commons.dbcp2.BasicDataSource;

public class Main

{

public static String DBDRIVER = "com.mysql.jdbc.Driver";

public static String DB_URL = "jdbc:mysql://localhost:3306/mldn";

public static String USERNAME = "root";

public static String PASSWORD = "admin";

public static BasicDataSource bds = null;

public static void main(String[] args)

{

dbPoolInit();

transferAmount();

System.out.println("///Done~~~");

}

public static void dbPoolInit()

{

bds = new BasicDataSource();

bds.setDriverClassName(DBDRIVER);

bds.setUrl(DB_URL);

bds.setUsername(USERNAME);

bds.setPassword(PASSWORD);

}

public static boolean transferAmount()

{

boolean retVal = true;

String sql = "UPDATE user SET amount=? WHERE userid=?";

Connection conn = null;

PreparedStatement stmt = null;

ResultSet rs = null;

Savepoint sp = null;

try

{

conn = bds.getConnection();

conn.setAutoCommit(false);

stmt = conn.prepareStatement(sql);

stmt.setInt(1, 0);

stmt.setString(2, "cjk");

stmt.execute();

sp = conn.setSavepoint();

stmt.setInt(1, 100);

stmt.setString(2, "ly");

stmt.execute();

throw new Exception();

}

catch (Exception e)

{

e.printStackTrace();

try

{

conn.rollback(sp);

stmt.setInt(1, 100);

stmt.setString(2, "cyx");

stmt.execute();

conn.commit();

} catch (SQLException e1)

{

// TODO Auto-generated catch block

e1.printStackTrace();

}

}

finally

{

try

{

if(conn != null)

conn.close();

if(stmt != null)

stmt.close();

if(rs != null)

rs.close();

}

catch(Exception e)

{

//ignore all exceptions when closing...

}

}

return retVal;

}

}