MySql中的事务、JDBC事务、事务隔离级别
一、MySql事务
之前在Oracle中已经学习过事务了,这个东西就是这个东西,但是在MySql中用法还是有一点不同,正好再次回顾一下。
先看看MySql中的事务,默认情况下,每执行一条SQL语句,都是一个单独的事务。如果需要在一个事务中包含多条SQL语句,就需要开启和结束事务。
开始事务:start transaction
结束事务:commit或rollback
在执行SQL语句之前,先执行start transaction,这就开启了一个新的事务,然后就可以去执行多条SQL语句,最后要结束事务,commit表示提交,即事务中多条SQL语句造成的影响会持久化到数据库中。rollback表示回滚,一切恢复到事务的起点,事务开始之后所到的操作全当没有发生过。
在orcale中拿银行转账举过例子,现在在MySql中实现以下:
首先建了一个银行账户表
现在张三余额800,李四余额1200,下面李四向张三转账200.
在两句update语句之后数据库貌似是变了,这时候注意其他用户看到的还是没有变化的数据库,因为没有提交,这时候在本用户查看好像是转成功了,但是一个rollback,一切归于开始。
二、JDBC事务
JDBC操作事务,全部都是由Connection完成。Connection的三个方法与事务有关
setAutoCommit(boolean):设置是否自动提交事务,如果不自动提交,那这句就表示事务的开始。
commit():表示提交事务
rollback():表示回滚事务
JDBC操作事务的代码格式
try{
con.setAutoCommit(fasle);
....
....
con.commit();
}catch(){
con.rollback();
}
如果对事务的操作抛出异常,那么肯定就执行不来,所以回滚,要是没有出错,那就提交。
这里一定要注意的JDBC操作事务一定要使用一个Connection对象!!!!再拿银行转账来演示,首先建一个账户类。
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; /** * @author WangXinwei *使用自建工具类JdbcUntils返回Connection对象 */ public class Bank { public void account(String name,int blance) throws SQLException{ Connection conn=JdbcUntils.getConn(); String sql="update bank set blance=blance+? where name=?"; PreparedStatement ps=conn.prepareStatement(sql); ps.setInt(1, blance); ps.setString(2, name); ps.executeUpdate(); } }
使用JDBC操作事务
import java.sql.Connection; import java.sql.SQLException; /** * @author WangXinwei * 传入转账方,收账方,转账金额 * */ public class Demo3 { public void demo(String from, String to, int money) { Connection conn = JdbcUntils.getConn(); try { conn.setAutoCommit(false); Bank bank = new Bank(); bank.account(from, -money); bank.account(to, +money); conn.commit(); } catch (Exception e) { // TODO: handle exception try { conn.rollback(); conn.close(); } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } finally { try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
因为我使用的是单例模式返回的Connection对象,所以是一个对象,满足之前说的。
三、事务的隔离级别
事务的问题一般都是出现的并发操作的时候。
并发事务问题有五种,其中两种是更新问题,三种是读问题。重点看并发读问题,在这之前,先略微了解一下更新问题
1. 第一类丢失更新(lost update): 在完全未隔离事务的情况下,两个事务更新同一条数据资源,某一事务异常终止,回滚造成第一个完成的更新也同时丢失。
2. 第二类丢失更新(second lost updates):是不可重复读的特殊情况,如果两个事务都读取同一行,然后两个都进行写操作,并提交,第一个事务所做的改变就会丢失。
并发读问题:
1.脏读:读到未提交更新数据,就是读到另一个事务未提交数据,就是脏数据。
比如:
2.不可重复读:对同一记录两次读取不一致,因为另一事务对该记录做了修改
比如:
3.幻读:对同一张表的两次查询不一致,因为另一事务插入了一条数据
比如:
不可重复读和幻读有什么区别呢?
不可重复读是读到了另一个事务的更新
幻读是读到了另个一表的插入(MySql中无法测试幻读)
四大隔离级别:
四个等级的隔离级别,在除了隔离级别不同什么都相同的情况下处理结果是不同的,因为四种隔离级别对并发数据的处理能力是不同的。
1.SERIALIZABLE(串行化)
因为是串行化,所以不会出现任何问题,效率最差
2.REPEATABLE READ(可重复读)MySql默认
防止脏读和不可重复读,不能防止幻读
3.READ COMMITTED(读已提交数据)
防止脏读
4.READ UNCOMMITTED(读未提交数据)
可能出现任何问题,效率最好
查看MySql中隔离级别,使用select @@tx_isolation查看
也可以通过 set isolationlevel [4选1] 来设置隔离级别
JDBC设置隔离级别:
依旧通过Connection对象,使用方法setTransactionisolation[ int level]
参数可选为