第一章事务操作
1.1Mysql事务操作
略,详情见mysql笔记中
1.2JDBC事务操作
Connection对象的方法名 | 描述 |
conn.setAutoCommit(false); | 开启事务 |
conn.commit(); | 提交事务 |
conn.rollback(); | 回滚事务 |
示例代码:
package Transaction;
import jdbc.JdbcUtils;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;public class Demo01 {
public static void main(String[] args) throws SQLException {
//模拟转账
//1.获取连接
Connection connection = null;
Statement statement = null;
try {
connection = JdbcUtils.getConnection();
//1.开启事务
connection.setAutoCommit(false);
String sql1 = "update account set cash= cash-100 where `name` ='zhangsan'";
String sql2 = "update account set cash= cash+100 where `name` ='lisi'";
//2.加钱,减钱
statement = connection.createStatement();
statement.executeUpdate(sql1);
int i = 1 / 0; //模拟收款人加钱时出错。
statement.executeUpdate(sql2);
//2.提交事务
connection.commit();
} catch (Exception e) {
connection.rollback(); //3.回滚事务
} finally {
//3.关闭资源
JdbcUtils.closeResource(connection, statement, null);
}
}
}
1.3DBUtils
Connection对象的方法名 | 描述 |
conn.setAutoCommit(false); | 开启事务 |
DbUtils.commitAndCloseQuietly(conn); | 提交事务并且关闭连接 |
DbUtils.rollbackAndCloseQuietly(conn); | 回滚事务 并且关闭连接 |
new QueryRunner() | 创建核心类 |
query(conn,sql,handler,params)或者 | 执行sql语句 |
update(conn,sql,params) | 执行sql语句 |
package Transaction;
import jdbc.JdbcUtils;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import java.sql.Connection;
public class Demo02 {
public static void main(String[] args) {
Connection connection = null;
try {
//1.开启事务
connection = JdbcUtils.getConnection();
connection.setAutoCommit(false);
String sql1 = "update account set cash=cash-100 where `name`='zhangsan'";
String sql2 = "update account set cash=cash+100 where `name`='lisi'";
QueryRunner queryRunner = new QueryRunner();
queryRunner.update(connection, sql1);
int i =1/0;
queryRunner.update(connection, sql2);
//2.提交事务
DbUtils.commitAndCloseQuietly(connection);
} catch (Exception e) {
//3.回滚事务
DbUtils.rollbackAndCloseQuietly(connection);
}
}
}
第二章 事务总结
2.1ACID回顾:
原子性:原子性是指事务是不可分割的,要么都发生,要么都不发生。
一致性:事务前后的数据必须保持一致。
隔离性:事务的隔离性就是一个事务不能呗其他事务干扰。
持久性:事务一旦提交,对数据的改变就是永久的。
2.2事务并发问题
脏读:一个事务读到了另外一个事务没有提交的数据
1.在事务A执行的过程中,事务A对数据进行了修改,事务B读取到了事务A修改后的数据
2.由于某些原因,事务A并没有完成提交,发生了回滚操作,所以B读到了不该读到的脏数据。
这种读取到另外一个事务没有提交的数据的现象就是脏读(Dirty Read)。
不可重复读:事务B读取了两次数据资源,在这两次数据资源读取的过程中,事务A修改了数据,导致事务B在两次读取中的数据不一致,在这种同一个事务中,两次读取数据不一致的现象出现 ,就是不可重复读。
幻读/虚读:事务B前后两次读取同一个范围数据,在事务B进行中,事务A新增了数据,导致事务B后面读的和前面一次查询的不一致。
2.3隔离级别:解决问题
数据库规范了4种隔离级别,分别用于解决事务并发产生的所有情况,事务隔离级别从低到高分别是:读未提交,读已提交,可重复读,串行化。
级别越高,越能保证数据的一致性和完整性,但是执行效率也就越低,所以设置数据库的隔离级别需要做以下权衡。
Mysql默认的是可重复读的级别。
读未提交:是最低的隔离级别,所有的事务都能看到其他未提交的事务的执行结果,不能解决脏读,幻读,可重复读,所以很少应用于实际开发中。
读已提交:在这个隔离级别下,一个事务的更新操作结果只有在该事务提交之后,另一个事务才能读取到同一笔数据的更新结果。可以防止脏读出现,但是不能解决可重复读和幻读的问题。
可重复读:Mysql默认的隔离级别。在这个隔离级别下,一个事务多次读同一个数据,如果这个事务还没有结束,其他事务不能访问该数据(包括读写)。这样就能保证两次读到的数据是一样的。可以预防脏读,不可重复读,但是还是会出现幻读。
串行化:这是最高的隔离级别,要求事务序列化的执行,事务只能排队一个接着一个的执行。强制要求事务不能并发执行。可以解决上面的所有问题,但是会导致大量的超时出现,通常情况下不使用该隔离级别。