各种并发的问题
- 脏读:对于两个事务 T1,T2,T1 读取了已经被 T2 更新但还没有被提交的字段之后,若 T2 回滚,T1 读取的内容就是临时且无效的。
- 不可重复读:对于两个事物 T1 T2 ,T1 读取了一个字段,然后 T2 更新了该字段之后,T1 再次读取同一个字段,值就不同了。
- 幻读:对于两个事物 T1 T2,T1 从一个表中读取了一个字段,然后 T2 在该表中插入了一些新的行之后,如果 T1 再次读取同一个表,就会多出几行。
事务的隔离级别
设置隔离级别的两种方式
- 在Java程序中:
查看:System.out.println(connection.getTransactionIsolation());
设置:connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); - 在 MySQL中
查看:SELECT @@tx_isolation
设置当前MySQL连接的隔离级别 set transaction isolation level read committed;
设置数据库系统的全局的隔离级别 set global transaction isolation lenel rad committed;
Java测试设置隔离级别未提交
//返回某条记录的某一个字段的值或一个统计的值
public <E> E getForValue(String sql,Object ...args){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JDBCTools.getConnection();
//设置隔离级别--读未提交/读已提交
connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
//connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
preparedStatement = connection.prepareStatement(sql);
for(int i = 0;i < args.length;i++){
preparedStatement.setObject(i+1, args[i]);
}
resultSet = preparedStatement.executeQuery();
if(resultSet.next()){
return (E) resultSet.getObject(1);
}
} catch (Exception e) {
e.printStackTrace();
} finally{
JDBCTools.release(resultSet, preparedStatement, connection);
}
return null;
}
/**
* 测试事务的隔离级别在 JDBC 程序中可以通过 Connection 的 setTransactionIsolation
* 来设置事务的隔离级别
*/
@Test
public void testTransactionIsolationUpdate(){
Connection connection = null;
try {
connection = JDBCTools.getConnection();
connection.setAutoCommit(false);
String sql = "UPDATE users SET balance = balance-500 WHERE id = ?";
update(connection, sql,1);
connection.commit();//该行进行断点调试
} catch (Exception e) {
e.printStackTrace();
}finally{
JDBCTools.release(null, null, connection);
}
}
@Test
public void testTransactionIsolationRead(){
String sql = "SELECT balance FROM users WHERE id = 1";
Integer balance = getForValue(sql);
System.out.println(balance);
}
数据库:
设置隔离级别读未提交时:(数据库 balance == 1000 发生脏读、幻读、不可重复读)
设置隔离级别读已提交时:(数据库 balance == 1000 发生不可重复读和幻读,可避免脏读)