public class TxTest {
public static void main(String[] args) throws SQLException {
test();
}
static void test() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
conn.setAutoCommit(false);
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
/*
先解釋一下:
事務指定一個隔離級別,該隔離級別定義一個事務必須與由其他事務進行的資源或資料更改相隔離的程度。隔離級別從允許的併發副作用(例如,髒讀或虛擬讀取)的角度進行描述。
a:髒讀取:一個事務讀取了另外一個並行事務未提交的資料
b:不可重複讀取:一個事務再次讀取之前讀過的資料時得到的資料不一致,被另外一個事務修改。
把甲的安全級別設成是是允許自己可重複讀的。那麼甲事務在執行中讀了一次ID是10的資料的資金是1000,在執行過程中第二次它再去讀這個ID10的資金有可能就不是1000了,因為乙在甲執行第二次查詢之前第一次查詢之後將這條資料的資金修改並提交了。
c:虛讀:一個事務重新執行一個查詢,返回的記錄包含了其他事務提交的新記錄
設定事務的隔離級別:con.setTransactionIsolation(Connection.isolationLevel);
四種隔離級別:
con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);//最底級別:只保證不會讀到非法資料,上述3個問題有可能發生
con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); //預設級別:可以防止髒讀
con.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);//可以防止髒讀和不可重複讀取
con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); //最高階別:防止上述3種情況,事務序列執行,慎用
表:
允許自己,但是不一定會:V 不允許自己,絕對不會:x
隔離級別 |
髒讀 |
不可重複讀 |
幻讀 |
讀未提交(Read uncommitted) |
V |
V |
V |
讀已提交(Read committed) |
x |
V |
V |
可重複讀(Repeatable read) |
x |
x |
V |
可序列化(Serializable ) |
x |
x |
x |
*/
st = conn.createStatement();
String sql = "update user set money=money-10 where id=1";
st.executeUpdate(sql);
sql = "select money from user where id=2";
rs = st.executeQuery(sql);
float money = 0.0f;
if (rs.next()) {
money = rs.getFloat("money");
}
if (money > 400)
throw new RuntimeException("已經超過最大值!");
sql = "update user set money=money+10 where id=2";
st.executeUpdate(sql);
conn.commit();
} catch (SQLException e) {
if (conn != null)
conn.rollback();
throw e;
} finally {
JdbcUtils.free(rs, st, conn);
}
}
}
分成兩階段提交。
javax.transaction.UserTransaction tx = (UserTransaction)ctx.lookup(“jndiName");
tx.begin();
//connection1 connection2 (可能來自不同的資料庫)…
tx.commit();//tx.rollback();