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

论坛 期权论坛 脚本     
匿名技术用户   2020-12-31 00:42   754   0
案例:银行转账:从张无忌账户上给赵敏转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();
   }
  }
 }
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP