JDBC学习(六、事务处理操作)

案例:银行转账:从张无忌账户上给赵敏转1000块。
准备:account(账户表):
---------------------------------------------------------------
id            name(账号,唯一)           balance(余额)
1             张无忌                             20000
2             赵敏                                  0
---------------------------------------------------------------
操作步骤:
           1):检查张无忌的账户余额是否大于等于1000.
           SELECT * FROM account WHERE  name = '张无忌' AND balance >= 1000;
           2):从张无忌的账户余额中减少1000.
           UPDATE account SET balance = balance - 1000 WHERE name = '张无忌';
           3):再在赵敏的账户余额中增加1000.
           UPDATE account SET balance = balance + 1000 WHERE name = ' 赵敏';
如果:在第二步和第三步之间如果程序中断,怎么办? (通过异常来模拟)

代码演示:

public void test1(){
		String sql = "select * from account where name=? AND balance>?";
		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","rootroot");
			System.out.println(conn);
			//1.查询张无忌账户余额是否大于1000
			PreparedStatement ps = conn.prepareStatement(sql);
			ps.setString(1, "张无忌");
			ps.setDouble(2, 1000.0);
			ResultSet rs = ps.executeQuery();
			if(!rs.next()){
				throw new RuntimeException("账户余额不足");
			}
			//2.从张无忌账户中转出1000
			sql = "update account set balance=balance-? where name=?";
			ps = conn.prepareStatement(sql);
			ps.setDouble(1, 1000.0);
			ps.setString(2, "张无忌");
			ps.executeUpdate();
			//---------模拟停电了--------------
			//int a = 1/0;
			//--------------------------
			//3.从赵敏账户中增加1000
			sql = "update account set balance=balance+? where name=?";
			ps = conn.prepareStatement(sql);
			ps.setDouble(1, 1000.0);
			ps.setString(2, "赵敏");
			ps.executeUpdate();
		} catch (ClassNotFoundException |SQLException |RuntimeException ex) {
			ex.printStackTrace();
		}
	}
事务(Transaction,简写为tx):
     在数据库中,所谓事务是指一组逻辑操作单元,使数据从一种状态变换到另一种状态。
     我们把多个密不可分的操作看做是一个整体,那么该整体就称之为一个事务.
--------------------------------------------------
事务的ACID属性:
1. 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2. 一致性(Consistency)事务必须使数据库从一个一致性状态变换到另外一个一致性状态,但是不最终数据不能被破坏,两个账户的总余额是不能改变的.
3. 隔离性(Isolation):MySQL再讲
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
4. 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响
--------------------------------------------------
事务:指构成单个逻辑工作单元的操作集合
事务处理:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时, 要么所有的事务都被提交(commit),要么整个事务回滚(rollback)到最初状态
处理事务的两个动作:
       提交:commit:   当整个事务中,所有的逻辑单元都正常执行成功.  ---->提交事务.---数据已经提交,不能更改.
       回滚:rollback:  当整个事务中,有一个逻辑单元执行失败,              ---->回滚事务.  
                      撤销该事务中的所有操作,释放锁--->恢复到最初的状态.


    1):默认情况下,在JDBC中执行DML操作就会自动提交事务,此时我们得设置事务的手动提交机制(取消事务的自动提交).
    2):查询操作,不涉及数据的更改,所以不需要事务.
    3):MySQL中InnoDB存储引擎支持事务,MyISAM不支持.
     alter table account engine = 'MyISAM';   ---> "InnoDB"
意识:如果是DML操作时,没有异常,代码也正确,但是数据改变不了,首先去想到事务没有提交。

操作事务的模板:

try{
   //取消事务自动提交:
   connection对象.setAutoCommit(false);
   操作1
   操作2
   操作3     
   //提交事务
   Connection对象.commit();
}catch(Exception e){
     //处理异常
     //回滚事务
    Connection对象.rollback();
}finally{
    释放资源
}

上述例子修改后代码演示:

@Test
	public void test2() throws ArithmeticException{
		String sql = "select * from account where name=? AND balance>?";
		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","rootroot");
			//取消事务自动提交
			conn.setAutoCommit(false);
			System.out.println(conn);
			//1.查询张无忌账户余额是否大于1000
			PreparedStatement ps = conn.prepareStatement(sql);
			ps.setString(1, "张无忌");
			ps.setDouble(2, 1000.0);
			ResultSet rs = ps.executeQuery();
			if(!rs.next()){
				throw new RuntimeException("账户余额不足");
			}
			//2.从张无忌账户中转出1000
			sql = "update account set balance=balance-? where name=?";
			ps = conn.prepareStatement(sql);
			ps.setDouble(1, 1000.0);
			ps.setString(2, "张无忌");
			ps.executeUpdate();
			//---------模拟停电了--------------
			int a = 1/0;
			//--------------------------
			//3.从赵敏账户中增加1000
			sql = "update account set balance=balance+? where name=?";
			ps = conn.prepareStatement(sql);
			ps.setDouble(1, 1000.0);
			ps.setString(2, "赵敏");
			ps.executeUpdate();
			conn.commit();
		} catch ( Exception ex) {
			ex.printStackTrace();
			try {
				conn.rollback();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

猜你喜欢

转载自blog.csdn.net/qq_38741971/article/details/80619337