воскресенье, 17 февраля 2013 г.

JDBC Statement & ResulSet


И так, чтобы начать получать данные из  базы или сохранять/изменять их в ней, нам нужно создать выражение, и выполнить его, результатом выполнения выражения является ResultSet.

ResultSet бывают нескольких типов, которые определяют методы работы с ним:
TYPE_FORWARD_ONLY - курсор такого резалтсета может двигаться только вперед, при этом данные в этом резалтсете храняться на момент выполнения выражения, не отображая изменения в базе на поточный момент работы в ним через курсор.
TYPE_SCROLL_INSENSITIVE - такой резалтсет позволяет курсору двигаться в любом направлении и в абсолютные позиции, но при этом в нем хранятся данные на момент выполнения выражения.
TYPE_SCROLL_SENSITIVE - курсор такого сета тоже подвижен в любом направлении, но при этом изменения в базе тут же отображаются в резалтсете.


Еще одна характеристика резалтсета это конкурентность(ResultSet Concurrency). Она определяет можно ли изменять содержимое базы данных через резалтсет. Есть два типа:
CONCUR_READ_ONLY - не можно.
CONCUR_UPDATABLE - можно изменять изменять содержимое базы.

public void modifyPrices(float percentage) throws SQLException {
    Statement stmt = null;
    try {
      stmt =
          con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
      ResultSet uprs = stmt.executeQuery("SELECT * FROM COFFEES");

      while (uprs.next()) {
        float f = uprs.getFloat("PRICE");
        uprs.updateFloat("PRICE", f * percentage);
        uprs.updateRow();
      }

    } catch (SQLException e) {
      JDBCTutorialUtilities.printSQLException(e);
    } finally {
      if (stmt != null) { stmt.close(); }
    }
  }

И так, как уже стало понятно, чтобы база начала выполнять какие-то операции мы должна работать с выражением, а вернее выполнять через него некие запросы.
Делать мы это можем через следующие методы:

boolean execute(String sql) - выполнить скуель указанный в строке; возращается тру, если мы можем получить резалтсет через .getResultSet() в случае если у нас запрос типа выборка, или же мы можем получить количество обработанных/вставленных строк запросом int getUpdateCount(), если же у нас запросом сформирован резалтсет(была выборка), то этот методв вернет -1, -1 он вернет также если не обработано ни одной строки.
ResultSet executeQuery(String sql) - этот метод у нас для того, чтобы выполнять только запросы выборки.
int executeUpdate(String sql) - а этот метод для того, чтобы выполнять запросы INSERT, UPDATE, или DELETE, или SQL DDL, которые не возвращают никаких результатов.
int[] executeBatch()  - этот метод выполняет пакет запросов, которые мы до этого вставили в наше выражение, возвращает он массив с количеством результатов, которые возвратил каждый запрос пакета.

Впринципе мы можем работать только с екзекьютом, при этом не сразу обрабатывать резалтсеты в служае выборок, мы можем потом подключить использование методов, которые получают результаты пердыдущих запросов:
boolean getMoreResults() - тру если мы можем получить следующий результат методом .getResultSet(), у нас не может быть вызовов .getResultSet() больше чем выло выполнено екзекьютов на этом выражении, если мы вызываем .getResultSet() большее количество раз чем было екзекьютов( если  getMoreResults() == фолс), то у нас будет ексепшин.
boolean getMoreResults(int current) - подвинет курсор резалтсетов на указанную позицию, если вернется тру, то мы можем .getResultSet() получить результат выполненного по счету current запроса.

Курсоры резалтсета:

Они содрежат следующие методы:

next:
previous:
first:
last:
beforeFirst:
afterLast:
relative(int rows):
absolute(int row):


Пакетные запросы.

public void batchUpdate() throws SQLException {

    Statement stmt = null;
    try {
        this.con.setAutoCommit(false);
        stmt = this.con.createStatement();

        stmt.addBatch(
            "INSERT INTO COFFEES " +
            "VALUES('Amaretto', 49, 9.99, 0, 0)");

        stmt.addBatch(
            "INSERT INTO COFFEES " +
            "VALUES('Hazelnut', 49, 9.99, 0, 0)");

        stmt.addBatch(
            "INSERT INTO COFFEES " +
            "VALUES('Amaretto_decaf', 49, " +
            "10.99, 0, 0)");

        stmt.addBatch(
            "INSERT INTO COFFEES " +
            "VALUES('Hazelnut_decaf', 49, " +
            "10.99, 0, 0)");

        int [] updateCounts = stmt.executeBatch();
        this.con.commit();

    } catch(BatchUpdateException b) {
        JDBCTutorialUtilities.printBatchUpdateException(b);
    } catch(SQLException ex) {
        JDBCTutorialUtilities.printSQLException(ex);
    } finally {
        if (stmt != null) { stmt.close(); }
        this.con.setAutoCommit(true);
    }
}
Также в пакете можно работать с подготовленными выражениями:

con.setAutoCommit(false);
PreparedStatement pstmt = con.prepareStatement(
                              "INSERT INTO COFFEES VALUES( " +
                              "?, ?, ?, ?, ?)");
pstmt.setString(1, "Amaretto");
pstmt.setInt(2, 49);
pstmt.setFloat(3, 9.99);
pstmt.setInt(4, 0);
pstmt.setInt(5, 0);
pstmt.addBatch();

pstmt.setString(1, "Hazelnut");
pstmt.setInt(2, 49);
pstmt.setFloat(3, 9.99);
pstmt.setInt(4, 0);
pstmt.setInt(5, 0);
pstmt.addBatch();

// ... and so on for each new
// type of coffee

int [] updateCounts = pstmt.executeBatch();
con.commit();
con.setAutoCommit(true);

Вставка строк через резалтсет

Как известно инсерты делаются execute, executeUpdate. Но некоторые реляционные базы позволяют делать вставки также через резалтсет:
public void insertRow(String coffeeName, int supplierID,
                      float price, int sales, int total)
    throws SQLException {

    Statement stmt = null;
    try {
        stmt = con.createStatement(
            ResultSet.TYPE_SCROLL_SENSITIVE
            ResultSet.CONCUR_UPDATABLE);

        ResultSet uprs = stmt.executeQuery(
            "SELECT * FROM " + dbName +
            ".COFFEES");

        uprs.moveToInsertRow();
        uprs.updateString("COF_NAME", coffeeName);
        uprs.updateInt("SUP_ID", supplierID);
        uprs.updateFloat("PRICE", price);
        uprs.updateInt("SALES", sales);
        uprs.updateInt("TOTAL", total);

        uprs.insertRow();
        uprs.beforeFirst();
    } catch (SQLException e ) {
        JDBCTutorialUtilities.printSQLException(e);
    } finally {
        if (stmt != null) { stmt.close(); }
    }
}

Подготовленные выражения

public void updateCoffeeSales(HashMap salesForWeek)
    throws SQLException {

    PreparedStatement updateSales = null;
    PreparedStatement updateTotal = null;

    String updateString =
        "update " + dbName + ".COFFEES " +
        "set SALES = ? where COF_NAME = ?";

    String updateStatement =
        "update " + dbName + ".COFFEES " +
        "set TOTAL = TOTAL + ? " +
        "where COF_NAME = ?";

    try {
        con.setAutoCommit(false);
        updateSales = con.prepareStatement(updateString);
        updateTotal = con.prepareStatement(updateStatement);

        for (Map.Entry e : salesForWeek.entrySet()) {
            updateSales.setInt(1, e.getValue().intValue());
            updateSales.setString(2, e.getKey());
            updateSales.executeUpdate();
            updateTotal.setInt(1, e.getValue().intValue());
            updateTotal.setString(2, e.getKey());
            updateTotal.executeUpdate();
            con.commit();
        }
    } catch (SQLException e ) {
        JDBCTutorialUtilities.printSQLException(e);
        if (con != null) {
            try {
                System.err.print("Transaction is being rolled back");
                con.rollback();
            } catch(SQLException excep) {
                JDBCTutorialUtilities.printSQLException(excep);
            }
        }
    } finally {
        if (updateSales != null) {
            updateSales.close();
        }
        if (updateTotal != null) {
            updateTotal.close();
        }
        con.setAutoCommit(true);
    }
}

Комментариев нет:

Отправить комментарий