说明:这里列出了数据库操作的重要内容---事务,假设银行为了转账而对数据库操作,执行减钱成功了,但是加钱的时候出问题了,这就坏了。事务就是可以让多个动作都成功之后再生效,否则都不生效。
package cn.itcast.jdbc;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.junit.Test;
import cn.itcast.util.JdbcUtil;
/*
create table account(
id int primary key auto_increment,
name varchar(40),
money float
);
insert into account(name,money) values('aaa',1000);
insert into account(name,money) values('bbb',1000);
insert into account(name,money) values('ccc',1000);
*/
public class TransactionDemo1 {
@Test
public void test(){
Connection conn = null;
PreparedStatement stmt = null;
try{//事务本来是默认开启的,执行依据关闭
conn = JdbcUtil.getConnection();
//手工开启事务
conn.setAutoCommit(false);//相当于start transaction;
stmt = conn.prepareStatement("update account set money=money-100 where name='bbb'");
stmt.executeUpdate();
//int i = 1/0;//这里是异常,用于测试
stmt = conn.prepareStatement("update account set money=money+100 where name='aaa'");
stmt.executeUpdate();
conn.commit();//事务提交
}catch(Exception e){
e.printStackTrace();//如果中间出现
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally{
JdbcUtil.release(null, stmt, conn);
}
}
}
下面是事务的隔离级别:
事务的特性(隔离级别)
A:原子性。说明事务是一个不可分割的单位。
C:一致性.事务必须使数据库从一个一致性状态变换到另外一个一致性状态.(比如转账)
*I:隔离性。一个事务不能被其他事务打扰。
D:持久性。事务一旦提交,就应该被永久保存起来。
如果不考虑事务的隔离级别,会出现以下“不正确”的情况:
脏读:指一个事务读到了另一个事务中未提交的数据。
不可重复读:针对一条记录的,同一条记录前后不一样
虚读(幻读):针对一张表,前后读到的记录条数不一样。
MySQL中控制事务隔离级别的语句:
select @@tx_isolation; //查看当前的事务隔离级别
set transaction isolation level 你的级别(四种之一);//设置隔离级别
隔离级别的分类:
READ UNCOMMITTED:脏读、不可重复读、虚读都有可能发生。
READ COMMITTED:能避免脏读,不可重复读、虚读都有可能发生。
REPEATABLE READ:能避免脏读、不可重复度,虚读都有可能发生。
SERIALIZABLE:能避免脏读、不可重复度、虚读。
package cn.itcast.jdbc;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.junit.Test;
import cn.itcast.util.JdbcUtil;
//演示控制事务的隔离级别
//隔离级别必须用在事务之中
public class TransactionIsolationDemo {
@Test
public void test(){
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try{
conn = JdbcUtil.getConnection();
conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);//一定要在开启事务前设置隔离级别,否则无效
conn.setAutoCommit(false);
//先查询aaa的余额
stmt = conn.prepareStatement("select * from account where name='aaa'");
rs = stmt.executeQuery();
if(rs.next())
System.out.println("开始时的余额:"+rs.getString("money"));
Thread.sleep(10*1000);
stmt = conn.prepareStatement("select * from account where name='aaa'");
rs = stmt.executeQuery();
if(rs.next())
System.out.println("别人未提交事务时的余额:"+rs.getString("money"));
}catch(Exception e){
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally{
try {
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
}