JDBC事务

本文通过转账案例介绍如何利用数据库事务确保数据操作的一致性和完整性。事务具备原子性、一致性、隔离性和持久性四大特性,能有效避免部分执行导致的数据错误。

有时我们使用JDBC操作数据库时,会出现同时执行两条Insert或update或delete之类的语句。


例如:有两个人Martin和John,Martin有1000元,John有700元。假设某天Martin要转100元给John,那么数据库应该会这样执行:

Update Martin set monry = money -100 ;

Update John set money = money +100 ;

当两个语句都执行了,才可以算完成一个转账。否则其中一条语句没执行,将会出现严重后果。而事物就是在这种背景下使用。


事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性

原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。

一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

下面就模仿事物中的原子性:SQL语句要么全部执行,要么全部都不执行。


下面模拟:

1,以上面的例子建立数据库:

create table bank(
   id int primary key auto_increment ,
   name varchar(20) not null ,
   money double not null default 0.00
) ;

insert into bank (name ,money) values("Martin" , 1000) ;
insert into bank (name ,money) values("John" , 700) ;

(图1)

2,我们模拟在update语句执行的过程中遇到了异常,这个异常可能是断电,数据库出现异常或自然灾害等。我们用1/0这个异常来代替

public class JDBC {
    public static void main(String[] args) {
    	Connection conn = null ;
    	Statement stat = null ;
	    try {
			Class.forName("com.mysql.jdbc.Driver") ;
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc" , "root","jian") ;
			
			String sql1 = "update bank set money=money-100 where name='Martin'" ;
			String sql2 = "update bank set money=money-100 where name='John'" ;
			
			stat = conn.createStatement() ;
			stat.executeUpdate(sql1) ;
			
			//模拟异常出现
			int x = 1/0 ;
			
			
			stat.executeUpdate(sql2) ;
			
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			if(null!=conn){
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				conn = null ;
			}
			if(null!=stat){
				try {
					stat.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				stat = null ;
			}
		}
	}
    
    
}


没有事物,相对于图1发生了更新的异常

(图2)

3,使用了事务

public class JDBC {
    public static void main(String[] args) {
    	Connection conn = null ;
    	Statement stat = null ;
	    try {
			Class.forName("com.mysql.jdbc.Driver") ;
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc" , "root","jian") ;
			
			String sql1 = "update bank set money=money-100 where name='Martin'" ;
			String sql2 = "update bank set money=money-100 where name='John'" ;
			//设置不主动提交事务
			conn.setAutoCommit(false);
			stat = conn.createStatement() ;
			
			stat.executeUpdate(sql1) ;
			//模拟异常出现
			int x = 1/0 ;
			stat.executeUpdate(sql2) ;
			
			//当两个update都完成了,在提交事务
			conn.commit();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} catch(ArithmeticException e){
			//出现异常则回滚事务
			try {
				conn.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		}
	    finally{
			if(null!=conn){
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				conn = null ;
			}
			if(null!=stat){
				try {
					stat.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				stat = null ;
			}
		}
	}
    
    
}

(图3)


当使用了事务后,结果如图3所示,相对于图2没有发生任何更新,在出现异常后回滚事务。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值