根据实际需求,通过设置数据库的事务隔离级别可以解决多个事务并发情况下出现的脏读、不可重复读和幻读问题,数据库事务隔离级别由低到高依次为Read uncommitted、Read committed、Repeatable read和Serializable等四种。数据库不同,其支持的事务隔离级别亦不相同:MySQL数据库支持上面四种事务隔离级别,默认为Repeatable read;Oracle 数据库支持Read committed和Serializable两种事务隔离级别,默认为Read committed。
Read committed(读提交):可以避免脏读,但可能出现不可重复读和幻读。
大多数数据库默认级别就是Read committed,比如Sql Server数据库和Oracle数据库。
注意:该隔离级别在写数据时只会锁住相应的行。
数据库事务隔离级别设置为READ-COMMITTED(读已提交):在并重启MySQL服务。
脏读
已知有两个事务A和B, A读取了已经被B更新但还没有被提交的数据,之后,B回滚事务,A读取的数据就是脏数据。
场景:公司发工资了,领导把5000元打到Tom的账号上,但是该事务并未提交,而Tom正好去查看账户,发现工资已经到账,账户多了5000元,非常高兴,可是不幸的是,领导发现发给Tom的工资金额不对,是2000元,于是迅速回滚了事务,修改金额后,将事务提交,Tom再次查看账户时发现账户只多了2000元,Tom空欢喜一场,从此郁郁寡欢,走上了不归路…...
分析:上述情况即为脏读,两个并发的事务:“事务B:领导给Tom发工资”、“事务A:Tom查询工资账户”
create table account( id int(36) primary key comment '主键', card_id varchar(16) unique comment '卡号', name varchar(8) not null comment '姓名', balance float(10,2) default 0 comment '余额' )engine=innodb; insert into account (id,card_id,name,balance) values (1,'6226090219290000','Tom',1000);
数据库中数据显示:
代码如下:
public class Boss { public static void main(String[] args) { Connection connection = null; Statement statement = null; try { Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://127.0.0.1:3306/test"; connection = DriverManager.getConnection(url, "root", "root"); connection.setAutoCommit(false); statement = connection.createStatement(); String sql = "update account set balance=balance+5000 where card_id='6226090219290000'"; statement.executeUpdate(sql); Thr