事务
什么是事务?
转账:
1. 给wc账户减1000元
2. 给wcxf账户加1000元
当给wc账户减1000元后,抛出了异常!这会怎么样呢?我相信从此之后,wc再也不敢转账了。
使用事务就可以处理这一问题:把多个对数据库的操作绑定成一个事务,要么都成功,要么都失败!
---------------------------------------------------------------------------------------------------------------------------------------------
事物的特性:ACID
*原子性:事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。
* 一致性:事务执行后,数据库状态与其它业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账号余额之和应该是不变的。
* 隔离性:隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。
*持久性:一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。
---------------------------------------------------------------------------------------------------------------------------------------------
MySQL操作事务
1. 开始事务:start transaction
2. 结束事务:commit//提交事物rollback//事物回滚
(1)事物回滚
(2)事物提交
---------------------------------------------------------------------------------------------------------------------------------------------
JDBC事务
1. 开始事务:con.setAutoCommit(false);
2. 结束事务;con.commit()或con.rollback();
public classJdbc2 {public static voidmain(String[] args) {
Connection con=null;
PreparedStatement pst=null;try{
con=JDBCUtils.getConnection();//开启事物
con.setAutoCommit(false);//开启手动事物
pst=con.prepareStatement("UPDATE acction SET mun=mun-100 WHERE username=? ");
pst.setString(1, "zhangsan");
pst.executeUpdate();//人为创建异常
int index=1/0;
pst=con.prepareStatement("UPDATE acction SET mun=mun+100 WHERE username=? ");
pst.setString(1, "wangwu");
pst.executeUpdate();
con.commit();//提交事物
}catch(Exception e) {try{
con.rollback();
}catch(SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{//关闭
JDBCUtils.createClose(null, pst, con);
}
}
}
---------------------------------------------------------------------------------------------------------------------------------------------
保存点
保存点的是可以回滚到事务中的某个位置,而不是回滚整个事务。
回滚到保存点不会结束事务。
设置保存点:Savepoint sp = con.setSavepoint();
回滚到保存点:con.rollback(sp);
public classJdbc1 {public static voidmain(String[] args) {
Connection con=null;
PreparedStatement pst=null;
Savepoint sp=null;try{
con=JDBCUtils.getConnection();
con.setAutoCommit(false);//手动开启事物
sp=con.setSavepoint();
pst=con.prepareStatement("INSERT INTO acction(username,mun) VALUES(?,?)");for(int i=1;i<=2000;i++){if(i==1002){int index=i/0;
}
pst.setString(1, "lxp");
pst.setInt(2, i);
pst.executeUpdate();if(i%1000==0){
sp=con.setSavepoint();
}
}
con.commit();//事物提交
}catch(Exception e){try{
con.rollback(sp);
con.commit();
}catch(SQLException e1) {//TODO Auto-generated catch block
e1.printStackTrace();
}//回滚事物
e.printStackTrace();
}finally{
JDBCUtils.createClose(null, pst, con) ;
}
}
---------------------------------------------------------------------------------------------------------------------------------------------
事务隔离级别
* 脏读:读到未提交
* 不可重复读:两次读取不一致,读取到另一事务修改的记录
* 幻读:两次读取不一致,读取到另一事务插入的记录
---------------------------------------------------------------------------------------------------------------------------------------------
四大隔离级别
* SERIALIZABLE(串行化):对同一数据的访问是串行的,即非并发的,所以不会出现任何并发问题。易出现死锁,效率太低!不可用!
* REPEATABLE READ(可重复读):防止了脏读、不可重复读,但没有防止幻读
* READ COMMITTED(读已提交):防止了脏读,但没有防止不可重复读,以及幻读
* READ UNCOMMITTED(读未提交):可能出现所有并发问题,效率最高,但不可用!
MySQL默认事务隔离级别为:REPEATABLE READ
Oracle默认事务隔离级别为:READ COMMITTED
-------------------------------------------------------------------------------------------------------------------------------------------------
MySQL设置事务隔离级别
/*查看:*/select @@tx_isolation/*设置:*/set transaction isolation level 四选一
JDBC设置事务隔离级别
con.setTransactionIsolation(四选一)
------------------------------------------------------------------------------------------------------------------------------------------------------
代码JDBCUtils代码:
需要配置dbconfig.properties文件
public classJDBCUtils {static Properties props = null;//绑定线程
static private ThreadLocal t1=new ThreadLocal();static{//加载本地配置文件
try{
InputStream in= JDBCUtils.class.getResourceAsStream("dbconfig.properties");
props= newProperties();
props.load(in);
}catch(IOException e) {
e.printStackTrace();
}//加载驱动
try{
Class.forName(props.getProperty("driverClassName"));
}catch(ClassNotFoundException e) {
e.printStackTrace();
}
}/*** 获得Connection连接
*@return*@throwsException*/
public static Connection getConnection() throwsException {
Connection conn=t1.get();if(conn==null){//加载配合
conn= DriverManager.getConnection(props.getProperty("url"),
props.getProperty("username"), props.getProperty("password"));
t1.set(conn);
}returnconn;
}/*** 关闭所有连接
*@paramrs
*@paramstatement
*@paramconn*/
public static voidcreateClose(ResultSet rs, PreparedStatement statement,
Connection conn) {try{if (rs != null)
rs.close();if (rs != null)
statement.close();if (rs != null)
conn.close();
if(t1!=null){
t1.remove();
}
}catch(Exception e) {
e.printStackTrace();
}
}
}