Spring框架——批處理(batch)和事務(Transaction)

批處理(batch)

批處理(batch)------------>比如快遞員【不能一件一件的送快遞】
- 批處理指的是一次操做中執行多條SQL語句
- 批處理相比於一次一次執行效率會提升不少java

- 批處理主要是分兩步:
  1.將要執行的SQL語句保存
  2.執行SQL語句

- Statement和PreparedStatement都支持批處理操做,這裏咱們只須要掌握PreparedStatement的批處理方式:
- 方法:
  void addBatch()
- 將要執行的SQL先保存起來,先不執行
- 這個方法在設置完全部的佔位符以後調用
  int[] executeBatch()
- 這個方法用來執行SQL語句,這個方法會將批處理中全部SQL語句執行

- mysql默認批處理是關閉的,因此咱們還須要去打開mysql的批處理:
  rewriteBatchedStatements=true
咱們須要將以上的參數添加到mysql的url地址中

- 注意:低版本的mysql-jdbc驅動也不支持批處理,通常都是在修改的時候使用批處理,查詢的時候不使用!mysql


案例演示:
1.建立一張新的數據表sql

CREATE TABLE t_emp(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(50)
)

  

2.反覆打開數據庫客戶端,插入語句【至關於每次獲取一個connection鏈接,執行executeUpdate語句】數據庫

INSERT INTO t_emp(NAME) VALUES('張三');
SELECT * FROM t_emp;


3.引出批處理--->執行效率高,資源利用率好!併發

@Test//測試批處理
public void testBatch(){
//向t_emp表中插入10000條數據

  //準備兩個變量
  Connection connection = null;
  PreparedStatement ps = null;

  try {
    //獲取數據庫鏈接
    connection=JDBCUtil.getConnection();
    //準備SQL模板
    String sql = "INSERT INTO t_emp(NAME) VALUES(?)";
    //獲取PrepareStatement
    ps = connection.prepareStatement(sql);
    //建立一個for循環,來設置佔位符
    for(int i = 0; i < 10000 ;i++){
      //填充佔位符
      ps.setString(1,"emp"+i);
      //添加到批處理方法中,調用無參的,有參的是Statement來調用的!
      ps.addBatch();
    } 
    //獲取一個時間戳
    long start = System.currentTimeMillis();
    //執行批處理
    ps.executeBatch();
    //獲取一個時間戳
    long end = System.currentTimeMillis();
    System.out.println("共花費了:"+(end-start));
  } catch (SQLException e) {
    e.printStackTrace();
  }
}

  

事務(Transaction)

演示銀行轉帳的功能:
1.建立一張表示帳號的表測試

CREATE TABLE t_account(
id INT PRIMARY KEY AUTO_INCREMENT,
a_name VARCHAR(50),
balance DECIMAL(11,2)
)

 


2.向表中插入幾個用戶atom

INSERT INTO t_account(id,a_name,balance) VALUES(NULL,'sunwukong',1000);
INSERT INTO t_account(id,a_name,balance) VALUES(NULL,'zhubajie',1000);
INSERT INTO t_account(id,a_name,balance) VALUES(NULL,'shaheshang',1000);
SELECT * FROM t_account;

 


3.sunwukong向shaheshang轉帳100元
從sunwukong的帳號減去100元url

UPDATE t_account SET balance = balance - 100 WHERE a_name='sunwukong';

給shaheshang的帳號加上100元對象

UPDATE t_account SET balance = balance +100 WHERE a_name = 'shaheshang';

 


從新設置爲1000元:blog

UPDATE t_account SET balance =1000;

 


4.從java代碼中演示上面的案例:
1.建立Dao類

public class AcountDao {	
  public void update(String name,double money){
    //準備兩個變量
    Connection conn = null;
    PreparedStatement ps = null;
    //準備SQL模板
    String sql = "UPDATE t_account SET balance = balance + ? WHERE a_name = ?";

    try {
      conn = JDBCUtil.getConnection();
      //獲取PreparedStatement
      ps = conn.prepareStatement(sql);
      //填充佔位符
      ps.setDouble(1, money);
      ps.setString(2, name);

      //執行SQL語句
      ps.executeUpdate();

    } catch (SQLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }finally{
      JDBCUtil.close(conn, ps, null);
    }
  }
}

  


2.測試該DAO

public class TestTransaction {
  private AcountDao accountDao = new AcountDao();

  @Test
  public void test() {
    //從sunwukong帳戶向shaheshang帳戶轉帳100元!
    //1.從sunwukong帳戶扣除100元
    accountDao.update("sunwukong", -100);
    //2.向shaheshang帳戶添加100元
    accountDao.update("shaheshang", 100);
  }
}

  


顯然上面是能夠正常執行的!
可是若是上面的程序在suwukong減去100元以後,shaheshang加錢以前,出現了異常,以下所示:

//從sunwukong帳戶向shaheshang帳戶轉帳100元!
//1.從sunwukong帳戶扣除100元
accountDao.update("sunwukong", -100);
int i =10/0;//添加一個異常
//2.向shaheshang帳戶添加100元
accountDao.update("shaheshang", 100);

 



- 在開發中咱們的一個業務每每須要同時操做多個表,這些操做每每是不可分割,業務中的對數據庫的屢次操做,
要麼同時成功,要麼全都失敗。

- 事務的特性(ACID):
原子性(atomicity)
一個事務是一個不可分割的工做單位,事務中包括的諸操做要麼都作,要麼都不作。

一致性(consistency)
事務必須是使數據庫從一個一致性狀態變到另外一個一致性狀態。一致性與原子性是密切相關的。

隔離性(isolation)
一個事務的執行不能被其餘事務干擾。
即一個事務內部的操做及使用的數據對併發的其餘事務是隔離的,併發執行的各個事務之間不能互相干擾。

持久性(durability)
持久性也稱永久性(permanence),指一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的。
接下來的其餘操做或故障不該該對其有任何影響。


- 操做事務的基本步驟:
1.開啓事務
- 開啓事務之後,咱們只後的全部操做將都會在同一個事務當中
2.操做數據庫
- 開啓事務之後再去操做數據庫,全部操做將不會直接提交到數據庫中
3.提交事務
- 將修改應用到數據庫
4.回滾事務
- 數據庫操做過程當中出現異常了,回滾事務,回滾事務之後,數據庫變成開啓事務以前的狀態


- mysql中的事務控制
#開啓事務
START TRANSACTION
#回滾事務
ROLLBACK
#提交事務
COMMIT

- JDBC中的事務主要經過Connection對象來控制的
1.開啓事務
void setAutoCommit(boolean autoCommit) throws SQLException;
- 設置事務是否自動提交,默認是自動提交
- 設置事務手動提交
conn.setAutoCommit(false);

2.提交事務
void commit() throws SQLException;
- 提交事務
conn.commit()

3.回滾事務
void rollback() throws SQLException;
- 回滾事務
conn.rollback()

- 事務控制的格式:

//建立一個Connection
Connection conn = null;

try{
  //獲取Connection
  conn = JDBCUtils.getConnection();
  //開啓事務
  conn.setAutoCommit(false);
  //對數據庫進行操做
  //操做成功,提交事務
  conn.commit();
}catch(Exception e){
  e.printStackTrace();
  //回滾事務
  try {
    conn.rollback();
  } catch (SQLException e1) {
    e1.printStackTrace();
  }
}finally{
  JDBCUtils.close(conn, null, null);
}

 



- 注意:咱們在同一個事務中使用的數據庫鏈接(Connection)必須是同一個,不然事務仍是不做用!
因此此時原來的AcountDAO中的update方法要改成以下所示:

public class AcountDao {	
  public void update(Connection conn,String name,double money){
    //準備兩個變量
    PreparedStatement ps = null;
    //準備SQL模板
    String sql = "UPDATE t_account SET balance = balance + ? WHERE a_name = ?";
    
    try {
      //獲取PreparedStatement
      ps = conn.prepareStatement(sql);
      //填充佔位符
      ps.setDouble(1, money);
      ps.setString(2, name);
    
      //執行SQL語句
      ps.executeUpdate();

    } catch (SQLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }finally{
      //此時也不能在這裏關閉數據庫鏈接了,而是在外邊統一關閉
      JDBCUtil.close(null, ps, null);
    }
  }
}
相關文章
相關標籤/搜索