在具体的工作中,有的事情需要被保持,不需要回滚,有的工作需要回滚,而这些逻辑,可以通过手动设置事务的回滚点。
1、用JAVA处理数据库事务的事务回滚点的准备
要有一个能够访问数据库的应用。下面的示例都基于ORACLE进行。
create table ffm_account(
id int primary key ,
name varchar(32),
money int
);
测试数据:
insert into ffm_account(id,name,money)values(1,‘A‘,1000);
insert into ffm_account(id,name,money)values(2,‘B‘,1000);
2、JDBC中使用回滚点进行事务处理
在JDBC中使用如下的语句设置事务回滚点:
Savepoint sp = conn.setSavepoint();
Conn.rollback(sp);
Conn.commit();//回滚后提交事务
3、JDBC使用事务范例之脏数据 以及读取脏数据的源代码
在JDBC代码中演示银行转帐案例,有两个银行账户,A和B,各自有1000块钱;A在银行购买了一个VIP服务,花费10元钱;然后 A往B账户转账100块。
在本样例中,购买VIP服务不需要回滚,A往B账户转账,如果转账失败,需要回滚。
JAVA源代码:
package com.transaction;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;
import com.db.EasyC3p0;
/**
*有两个银行账户,A和B,各自有1000块钱;A在银行购买了一个VIP服务,花费10元钱;然后 A往B账户转账100块。
*在本样例中,购买VIP服务不需要回滚,A往B账户转账,如果转账失败,需要回滚。
*
*@author 范芳铭
*/
public class EasySavepoint {
publicstatic void main(String[] args) throwsSQLException{
EasySavepointpoint = new EasySavepoint();
//首先对账户进行操作
point.OperAccount();
//查看账户执行情况
point.afterRunResult();
}
publicvoid OperAccount() throws SQLException{
Connectionconn = null;
PreparedStatementstmt = null;
ResultSetrs = null;
Savepointsp = null;
try{
conn= EasyC3p0.getConnection();
//通知数据库开启事务(start transaction)
//=================================
conn.setAutoCommit(false);
StringsqlAllMoney = " select sum(money) as money from ffm_account ";
StringsqlA_money = " select money from ffm_account ";
stmt= conn.prepareStatement(sqlAllMoney);
rs = stmt.executeQuery();
if(rs.next()) {
System.out.println("转账执行前,系统中全部金额为:" +rs.getInt("money"));
}
stmt= conn.prepareStatement(sqlA_money);
rs= stmt.executeQuery();
if(rs.next()) {
System.out.println("转账执行前,A的金额为:"+ rs.getInt("money"));
}
//=================================
//A账户购买VIP服务,花费10元
StringsqlA = "update ffm_account set money=money-100 where name=‘A‘";
stmt= conn.prepareStatement(sqlA);
stmt.executeUpdate();
//设置事务回滚点
sp= conn.setSavepoint();
//简单模拟A往B账户转账:
sqlA= "update ffm_account set money=money-100 where name=‘A‘";
stmt= conn.prepareStatement(sqlA);
stmt.executeUpdate();
//系统中有B账户,但是发生了异常
//简单粗暴的让任务出现异常中断
intx = 1/0;
Stringsqlc = "update ffm_account set money=money+100 where name=‘C‘";
stmt= conn.prepareStatement(sqlc);
stmt.executeUpdate();
conn.commit();
//简单模拟A往B账户 结束
//=================================
}catch (Exception e) {
//回滚到设置的事务回滚点
conn.rollback(sp);
//回滚后要提交事务
conn.commit();
e.printStackTrace();
}finally {
EasyC3p0.close(conn,stmt, rs);
}
}
publicvoid afterRunResult(){
Connectionconn = null;
PreparedStatementstmt = null;
ResultSetrs = null;
try{
conn = EasyC3p0.getConnection();
//通知数据库开启事务(starttransaction)
//=================================
conn.setAutoCommit(false);
StringsqlAllMoney = " select sum(money) as money from ffm_account ";
StringsqlA_money = " select money from ffm_account ";
//转账结束后,看账户情况
stmt= conn.prepareStatement(sqlAllMoney);
rs= stmt.executeQuery();
if(rs.next()) {
System.out.println("转账执行后,系统中全部金额为:" +rs.getInt("money"));
}
stmt= conn.prepareStatement(sqlA_money);
rs= stmt.executeQuery();
if(rs.next()) {
System.out.println("转账执行后,A的金额为:"+ rs.getInt("money"));
}
}catch (Exception e) {
e.printStackTrace();
}finally {
EasyC3p0.close(conn,stmt, rs);
}
}
}
4、运行结果
转账执行前,系统中全部金额为:2000
转账执行前,A的金额为:1000
java.lang.ArithmeticException: / by zero
atcom.transaction.EasySavepoint.OperAccount(EasySavepoint.java:64)
atcom.transaction.EasySavepoint.main(EasySavepoint.java:21)
转账执行后,系统中全部金额为:1900
转账执行后,A的金额为:900
系统虽然在运行中出现了异常,但是达到了预期的效果。