为了作这个实验,设计个场景,要把用户2 上帐户的22块钱打一块钱到帐户1的帐上去。要么全成功,全失败,也就是帐要作平。 java
代码以下: mysql
其中最关键的是: spring
updateMoneyByUserId(1, getMoneyByUserId(1) + 1,false); //这条语句是否回滚
updateMoneyByUserId(2, getMoneyByUserId(2) - 1,true); //设置抛出异常, sql
当用户2在打钱时抛出异常,没成功时,用户1的更新要回滚回来。在mysql connection中默认是自动提交的,须要设置为手动提交,而后才可用rollback方法进行回滚。 数据库
package com.test.transaction;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
CREATE TABLE `usermoney` (
`user_id` int(11) NOT NULL DEFAULT '0',
`moneyNum` int(11) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='user for money';
INSERT INTO `usermoney` VALUES (1,11),(2,22),(3,33),(4,44),(5,55);
* */
public class TranTest {
static Connection connection;
static {
try {
// 加载驱动程序
Class.forName("com.mysql.jdbc.Driver");
// 连续数据库
connection = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/banker", "root", "123456");
if (!connection.isClosed()) {
System.out.println("created connetion...:" + connection);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
try {
//手工设置数据库为一个初始状态,并提交
connection.setAutoCommit(false);//默认为自动提交
updateMoneyByUserId(1, 11,false);
updateMoneyByUserId(2, 22,false);
connection.commit();
//查询是不是设置正确1 --11 ; 2 --22
System.out.println("userID=1 & moneyNum=" + getMoneyByUserId(1));
System.out.println("userID=2 & moneyNum=" + getMoneyByUserId(2));
//若是更新是抛异常,须要注意回滚
connection.setAutoCommit(false);
updateMoneyByUserId(1, getMoneyByUserId(1) + 1,false); //这条语句是否回滚
updateMoneyByUserId(2, getMoneyByUserId(2) - 1,true); //设置抛出异常,
//若是抛异常,下面语句再也不执行
System.out.println("userID=1 & moneyNum=" + getMoneyByUserId(1));
System.out.println("userID=2 & moneyNum=" + getMoneyByUserId(2));
//若是不抛异常,不提交会怎样?(结束时仍是会作一次提交)
connection.commit();
} catch (SQLException e) {
try {
e.printStackTrace();
//开始回滚
connection.rollback();
//数据库是否仍是正确的呢?1==11 ; 2==22
System.out.println("check if userId=1 and moneyNum==11-->userID=1 & moneyNum=" + getMoneyByUserId(1));
System.out.println("check if userId=2 and moneyNum==22-->userID=2 & moneyNum=" + getMoneyByUserId(2));
} catch (SQLException e1) {
e.printStackTrace();
}
}
Thread.sleep(10000L);
}
/**
* 经过UserId获取Money number
* */
public static int getMoneyByUserId(int userId) throws SQLException {
// 执行SQL语句
Statement statement = connection.createStatement();
// 要执行的SQL语句
String sql = "select user_id,moneyNum from usermoney where user_id="
+ userId;
statement.execute(sql);
ResultSet rs = statement.executeQuery(sql);
rs.next();
return new Integer(rs.getString("moneyNum"));
}
/**
* 更新用户金额
* */
public static void updateMoneyByUserId(int userId, int moneyNum,boolean showThrow)
throws SQLException {
// 执行SQL语句
if (showThrow) {
throw new SQLException("不让你存");
}
Statement statement = connection.createStatement();
// 要执行的SQL语句
String sql = "update usermoney set moneyNum=" + moneyNum
+ " where user_id=" + userId;
System.out.println(sql);
statement.executeUpdate(sql);
}
}
经过以上代码实验,咱们还能够得出一个经验。 spa
在一个方法中同时操做本地数据库和调用远程接口时,要先把本地数据库事务操做完成后,再调用远程接口。 设计
由于若是先调用接口,再操做本地数据库事务是抛出异常,再回滚时,本地数据库就和远程接口数据不一致了。 接口
若是先操做本地数据库,抛出异常还能够本身决定一次是否要调用远程接口。 事务
如今比较大的项目,经常使用spring来作事务管理,接下来作更多的这方面研究。 get