• 批处理、事务、批处理与事务结合


    批处理(batch)------------>好比快递员【不能一件一件的送快递】
    - 批处理指的是一次操作中执行多条SQL语句
    - 批处理相比于一次一次执行效率会提高很多
             
    - 批处理主要是分两步:
    1.将要执行的SQL语句保存
    2.执行SQL语句
                  
    - Statement和PreparedStatement都支持批处理操作,这里我们只需要掌握PreparedStatement的批处理方式:
    - 方法:
       void addBatch()
         - 将要执行的SQL先保存起来,先不执行
         - 这个方法在设置完所有的占位符之后调用
       int[] executeBatch()
         - 这个方法用来执行SQL语句,这个方法会将批处理中所有SQL语句执行      
                      
    - mysql默认批处理是关闭的,所以我们还需要去打开mysql的批处理: rewriteBatchedStatements=true

    url="jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true"

    我们需要将以上的参数添加到mysql的url地址中
             
    - 注意:低版本的mysql-jdbc驱动也不支持批处理,一般都是在修改的时候使用批处理,查询的时候不使用!
     
     
    案例演示:
     
    1.创建一张新的数据表
             
    2.反复打开数据库客户端,插入语句【相当于每次获取一个connection连接,执行executeUpdate语句】效率不高
         
    3.引出批处理--->执行效率高,资源利用率好!
     
    public class TestBatch {
    
          @Test
          public void test() {
                Connection conn = null;
                PreparedStatement ps = null;
                String sql ="insert into test (name) values(?)";
                //Time:368236
                //Time:1393
                try {
                      //获取连接
                      conn = JDBCUtil.getConnection();
                      ps = conn.prepareStatement(sql);
                      //设置参数
                      for(int i = 0; i < 5000 ;i++){
                            //填充占位符
                            ps.setString(1,"emp_"+i);
                            //添加到批处理方法中,调用无参的,有参的是Statement来调用的!
                            ps.addBatch();
                      }
                      long start = System.currentTimeMillis();
                      //执行批处理
                      ps.executeBatch();
                      long end = System.currentTimeMillis();
                      System.out.println("Time:"+(end-start));
                } catch (SQLException e) {
                      // TODO Auto-generated catch block
                      e.printStackTrace();
                }finally{
                      JDBCUtil.close(conn);
                }
          }
    }
    

    事务:
     
    演示银行转账的功能:
    1.创建一张表示账号的表
                 
    2.向表中插入几个用户
             
    3.在数据库执行sql语句,实现转账 
                  
    4.从java代码中演示上面的案例:
    (1)创建Dao类
    public class AccountDao {
          public void update(Integer id,Integer count){
                Connection conn = null;
                PreparedStatement ps = null;
                try {
                      String sql="UPDATE t_account SET balance = balance + ? WHERE id = ?";
                      conn = JDBCUtil.getConnection();
                      ps = conn.prepareStatement(sql);
                      ps.setInt(1, count);
                      ps.setInt(2, id);
    
                      ps.executeUpdate();
                } catch (SQLException e) {
                      // TODO Auto-generated catch block
                      e.printStackTrace();
                }finally {
                      JDBCUtil.close(conn);
                }
          }
    }
    

    (2).测试该DAO

    @Test
    public void test() {
         //孙悟空向猪八戒转账100元
         dao.update(1, -100);
         dao.update(2, 100);
    }
    
    上面是可以正常执行的
     
    但是如果上面的程序在suwukong减去100元之后,shaheshang加钱之前,出现了异常
    第二个 update() 就不会执行,导致数据不一致,一个减少了一个没增加
    @Test
    public void test() {
         //孙悟空向猪八戒转账100元
          dao.update(1, -100);
          int a = 10/0;//异常
          dao.update(2, 100);
    }
    

    这时候就需要用到 事务!

    事务的特性(ACID):
     
    - 原子性(atomicity)
         一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
                       
    - 一致性(consistency)
         事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
     
    - 隔离性(isolation)
         一个事务的执行不能被其他事务干扰。
         即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
                            
    - 持久性(durability)
         持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。
         接下来的其他操作或故障不应该对其有任何影响。
                            
    操作事务的基本步骤:
         1.开启事务
              - 开启事务以后,我们只后的所有操作将都会在同一个事务当中
         2.操作数据库
              - 开启事务以后再去操作数据库,所有操作将不会直接提交到数据库中
         3.提交事务
              - 将修改应用到数据库
         4.回滚事务
              - 数据库操作过程中出现异常了,回滚事务,回滚事务以后,数据库变成开启事务之前的状态
      
              提交事务与回滚事务只能执行其中一条
     
    mysql中的事务控制
         #开启事务
              START TRANSACTION
         #回滚事务
              ROLLBACK              
         #提交事务
              COMMIT
                 
          ROLLBACK  要与 START TRANSACTION 连用,单独使用没用
     
    JDBC中的事务主要通过Connection对象来控制的
    1.开启事务
         void setAutoCommit(boolean autoCommit) throws SQLException;
              - 设置事务是否自动提交,默认是自动提交
              - 设置事务手动提交
                 conn.setAutoCommit(false);
                       
    2.提交事务
    public class TestAccount {
    
          private AccountDao dao = new AccountDao();
          @Test
          public void test() {
                Connection conn = null;
                PreparedStatement ps = null;
                conn = JDBCUtil.getConnection();
                //默认true自动提交,false手动提交
                try {
                //开启事务需要手动提交
                      conn.setAutoCommit(false);
                      //孙悟空向猪八戒转账100元
                      dao.update(conn,1, -100);
                      int a = 10/0;//异常
                      dao.update(conn,2, 100);
                      //提交事务
                      conn.commit();
                } catch (SQLException e) {
                      // TODO Auto-generated catch block
                      try {
                            //出现异常就回滚,保持数据一致性
                            conn.rollback();
                      } catch (SQLException e1) {
                            e1.printStackTrace();
                      }
                }finally {
                      try {
                            conn.close();
                      } catch (SQLException e) {
                            e.printStackTrace();
                      }
                }
          }
    }
    
    但是结果依旧是一个减少一个没增加
    因为两次update调用了两个Connection,本身还有个Connection,一共三个Connection
    注意:我们在同一个事务中使用的数据库连接(Connection)必须是同一个,否则事务还是不作用!    
            所以将conn 传给 update()
    此时原来的AccountDAO中的update方法要改为如下所示:
     
    public class AccountDao {
          public void update(Connection conn,Integer id,Integer count){
    
                PreparedStatement ps = null;
                try {
                      String sql="UPDATE t_account SET balance = balance + ? WHERE id = ?";
    
                      ps = conn.prepareStatement(sql);
                      ps.setInt(1, count);
                      ps.setInt(2, id);
    
                      ps.executeUpdate();
                } catch (SQLException e) {
                      e.printStackTrace();
                }finally {
                      //此时也不能在这关闭数据库,要在外边统一关闭
                      JDBCUtil.close(null);
                }
          }
    }
    

    事务与批处理结合
     
    一般是将事务与批处理结合起来写,更快
    public class TestAccount {
    
          private AccountDao dao = new AccountDao();
          @Test
          public void test() {
                Connection conn = null;
                PreparedStatement ps = null;
                conn = JDBCUtil.getConnection();
                try {
                      //默认true自动提交,false手动提交
                      //开启事务需要手动提交
                      conn.setAutoCommit(false);
    
                      //批处理
                      String sql ="insert into test (name) values(?)";
                      ps = conn.prepareStatement(sql);
                      //设置参数
                      for(int i = 0; i < 5000 ;i++){
                            //填充占位符
                            ps.setString(1,"emp_"+i);
                            //添加到批处理方法中,调用无参的,有参的是Statement来调用的!
                            ps.addBatch();
                      }
                      long start = System.currentTimeMillis();
                      //执行批处理
                      ps.executeBatch();
                      long end = System.currentTimeMillis();
                      System.out.println("Time:"+(end-start));
    
                      //提交事务
                      conn.commit();
                } catch (SQLException e) {
                      try {
                            conn.rollback();
                      } catch (SQLException e1) {
                            e1.printStackTrace();
                      }
                }finally {
                      try {
                            conn.close();
                      } catch (SQLException e) {
                            e.printStackTrace();
                      }
                }
          }
    }
    
     
  • 相关阅读:
    linux 删除某种规则命名的文件
    adb shell 出现 error :
    android 开发,多个线程共用一个handler
    android 开发上传图片遇到返回 FileNotFoundException
    mysql 的存储过程调试软件
    输入adb shell 时 提示error: more than one device and emulator
    高德开发 android 出现 key 鉴权失败
    android 中设置HttpURLConnection 超时并判断是否超时
    LINQ to SQL语句(3)之Count/Sum/Min/Max/Avg
    C# 如何判断数据是否为 NaN
  • 原文地址:https://www.cnblogs.com/lwj-0923/p/7454921.html
Copyright © 2020-2023  润新知