Задание на первое занятие по курсу “Корпоративные информационные системы”
  1. Изучить шаги создания простого приложения FirstQuery на примерах следующих запросов к базе данных “Учебный процесс” (Инфологическую модель БД и полный перечень запросов можно посмотреть в методических материалах по дисциплине “Базы данных”, 3-й курс):
         Простая выборка.         Исключение дубликатов.
  1. Изучить различные варианты регистрации и выбора драйвера.
  2. Изучить различные варианты создания соединения с базой данных.
  3. (контрольное) Написать свое приложение доступа к базе данных с вынесением шагов, рассмотренных в примере простого приложения FirstQuery, в отдельные методы. При реализации шагов регистрации драйвера и создания соединения реализовать перегруженные методы для всех возможных вариантов.


Пример создания простого приложения.

//Шаг первый: Импорт пакетов
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.Date;
import java.sql.SQLException;

public class FirstQuery {

    public static void main(String[] args) {

        Connection conn = null;

        try {

            //Шаг второй: Регистрация JDBC драйвера
            String driver = "oracle.jdbc.OracleDriver";
            Class.forName(driver);

            //Шаг третий: Создание соединения
            System.out.println("Connecting to database ...");
            String jdbcUrl = "jdbc:oracle:thin:@localhost:1521:orbis";
            String user = "stud";
            String pass = "stud";
            conn = DriverManager.getConnection(jdbcUrl, user, pass);

            //Шаг четвертый: Выполнение запроса
            Statement st = conn.createStatement();
            String sql;
            sql = "SELECT COUNT(*) FROM all_tables";
            ResultSet rs = st.executeQuery(sql);

            //Шаг пятый: Извлечение данных из "Результата запроса"
            while(rs.next()) {
                //
                int count = rs.getInt(1);
                System.out.println("Result set is: "+count);
            }

            //Шаг шестой: Освобождение ресурсов
            rs.close();
            st.close();
            conn.close();

         //Шаг седьмой: Обработка исключений
         }catch(SQLException se) {
             //Обработка ошибок для JDBC
              se.printStackTrace();
         }catch(Exception e) {
             //Обработка ошибок для Class.forName
             e.printStackTrace();
         }finally {
             //finally block used to close resourses
             try{
                 if (conn!=null)
                     conn.close();
             }catch(SQLException se) {
                 se.printStackTrace();
            }//end finally try
        }//end try

        System.out.println("GoodBye!");
    }//end main
}//end FirstQuery


Шаг 1: Импортирование классов и интерфейсов.

    Как и во всех Java-приложениях необходимо импортировать пакеты, которые содержат необходимые для работы программы классы. Все JDBC интерфейсы и классы находятся в пакетах java.sql и javax.sql. Пакет java.sql содержит основные интерфейсы и классы, которые используются в любых JDBC-приложениях. Пакет javax.sql содержит классы и интерфейсы, необходимые для написания приложений корпоративного уровня. Он является стандартным расширением и применяется при создании и использовании "пула соединений", работы с "наборами строк", распределенными транзакциями и т.д.

В приведенном выше примере импортированы следующие классы и интерфейсы:
Шаг 2: Регистрация JDBC драйвера.

    Драйвер JDBC является зависимой от конкретной СУБД частью программного интерфейса между Java-приложением и базой данных. Процедура добавления его к общим java.sql-классам называется регистрацией, которая может быть выполнена следующими методами соответствующий классов:     Метод DriverManager.registerDriver() требует указания параметра типа Driver. Регистрация драйвера этим методом производится на этапе компиляции программы и в случае проблемы с регистрацией возникает исключение типа SQLException. Ниже приведен пример программного кода, создающего с помощью конструктора oracle.jdbc.OracleDriver() новый объект типа oracle.jdbc.OracleDriver и передающего его в качестве параметра методу DriverManager.registerDriver():

try {
    DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
} catch (SQLException se) {
    se.printStackTrace();
}

    Метод Class.forName() является более гибким методом регистрации драйвера, т.к. получает его имя в виде параметра типа String. Это позволяет задавать имя драйвера в командной стоке запуска Java-приложения на выполнение или в файле свойств, читаемым Java-приложением в момент исполнения программы. В приведенном выше примере переменной driver типа String присваивается полное имя класса JDBC драйвера. Данный метод выдает исключение ClassNotFoundException если указанный в качестве параметра драйвер не был найден в момент выполнения программы.
    Использование Class.forName(String “имя класса драйвера”).newInstance() является наиболее распространенным способом регистрации драйвера. Созданный таким образом новый объект драйвера саморегистрируется с помощью статического инициализатора, который вызывает метод DriverManager.registerDriver(). Этот механизм позволяет динамически регистрировать драйвера в процессе выполнения программы. В случае регистрации ORACLE драйвера программный код может выглядеть следующим образом:

try {
    String driver = “oracle.jdbc.OracleDriver”;
    Class.forName(driver).newInstance();
} catch (ClassNotFoundException e) {
    //Возникает, если класс драйвера не найден в CLASSPATH
    e.print.StackTrace();
}

  Для указания имени класса драйвера в качестве системного свойства в командной строке запуска программы на выполнение используется ключ -D. В этом случае JVM будет пытаться загрузить драйвер как часть процесса инициализации. По завершению инициализации будет запущено на выполнение само приложение. При этом регистрации драйвера в самом приложении уже не требуется. Ниже приведен пример командной строки:

java -Djdbc.drivers=oracle.jdbc.OracleDriver FirstQuery

    В случае чтения имени класса драйвера из файла свойств, последний должен содержать строчку следующего вида:


jdbc.drivers=oracle.jdbc.OracleDriver

   Ниже приведен пример программного кода, читающего имя класса драйвера из файла свойств по имени database.properties:

Properties props = new Properties();
FileInputStream in = new FileInputStream("database.properties");
props.load(in);
in.close();
String drivers = props.getProperty("jdbc.drivers");
System.setProperty("jdbc.drivers", drivers);

    Драйверов может быть зарегистрировано несколько. Например, такая необходимость возникает при разработке приложений, обращающихся сразу к нескольким СУБД. В процессе выполнения приложения выбор нужного драйвера можно осуществить следующими методами:      Первый метод возвращает соответствующий объект драйвера. Второй метод возвращает объект типа Enumeration, содержащий список зарегистрированных драйверов. Ниже приведен пример программного кода, демонстрирующий использование второго метода:

Enumeration drEnum = DriverManager.getDrivers();
while(drEnum.hasMoreElements()) {
    Driver dr = (Driver)drEnum.nextElement();
    String str = "Driver class name is: "+dr.getClass().getName();
    System.out.println(str);
}
   
    Если по какой либо причине возникла необходимость исключить возможность обращения к той или иной или базе данных, то можно воспользоваться методом DriverManager.deregisterDriver(), которому в качестве параметра указывается объект ранее зарегистрированного драйвера, например:

DriverManager.deregisterDriver(dr)



Шаг 3: Создание соединения с СУБД.

    Для того чтобы открыть соединение с базой данных можно использовать один из трех перегруженных методов DriverManager.getConnection():

    DriverManager.getConnection(String url)
    DriverManager.getConnection(String url, Properties prop)
    DriverManager.getConnection(String url, String username, String password)

    Перед вызовом метода необходимо установить необходимые для создания соединения параметры:     В примере FirstQuery первая часть строки URL (jdbc:oracle:thin) указывает на тип драйвера, а вторая часть(@localhost:1521:orbis) указывает на местоположение базы, порт и ее название, под которым она известна СУБД. В случае использования метода с одним параметром во второй части строки URL может быть указано имя пользователя и его пароль (stud/stud@localhost:1521:orbis). Ниже приведен пример программного кода с использованием в качестве параметра объект типа Properties и файла свойств по имени database.properties:

//Usage: java DBConnProp.
//Contents of file database.properties is:
//jdbc.drivers=oracle.jdbc.OracleDriver
//jdbc.url=jdbc:oracle:thin:@localhost:1521:orbis
//user=stud
//password=stud
//
import java.io.*;
import java.sql.*;
import java.util.*;
//
public class DBConnProp {
    public static void main(String[] args) throws Exception {

        Connection db = getConnection();
        Statement st = db.createStatement();
        ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM all_tables");
        while (rs.next()) {
            System.out.println(rs.getInt(1));
        }
        rs.close();
        st.close();
        db.close();
    }
    public static Connection getConnection() throws Exception {
        Properties props = new Properties();
        FileInputStream in = new FileInputStream("ad.database.properties");
        props.load(in);
        in.close();
        props.list(System.out);
        String drivers = props.getProperty("jdbc.drivers");
        if (drivers != null) {
            System.setProperty("jdbc.drivers", drivers);
            System.out.println("Property \"jdbc.drivers\" = " +
            System.getProperty("jdbc.drivers"));
        }
        String url = props.getProperty("jdbc.url");
        return DriverManager.getConnection(url, props);
    }
}

    Если попытка установки соединения окончится неудачей, то будет создан экземпляр исключения типа SQLException. В случае удачи, вновь созданный объект типа Connection будет представлять физическое соединение с базой данных.


Шаг. 4: Выполнение SQL запроса.

    Для выполнения запроса к базе данных необходимы два объекта. Первый объект необходим для применения интерфейсов Statement, PreparedStatement или CallableStatement. Эти три интерфейса имеют разное назначение. Интерфейс java.sql.Statement используется для выполнения статических запросов без параметров. Интерфейс java.sql.PreparedStatement используется для выполнения запросов с изменяемыми параметрами параметрами. И, наконец, java.sql.CallableStatement используется для выполнения хранимых в базе данных процедур.
    Второй необходимый для выполнения запроса объект имеет тип ResultSet. Этот объект содержит результат выполнения запроса и предусматривает ряд итераторов, с помощью которых данные результата можно построчно извлекать из объекта.
   В приведенном выше примере инициализируется объект типа Statement с помощью метода createStatement() объекта типа Connection. Далее переменной типа String присваивается SQL-предложение, которое используется в качестве параметра при выполнении метода executeQuery() объекта типа Statement. Данный метод возвращает объект типа ResultSet, содержащий результат выполнения запроса. В случае возникновения какой либо ошибки возникает исключение типа SQLException.


Шаг. 5: Просмотр результата запроса.

    Данные результата запроса сохраняются в объекте типа ResultSet в виде таблицы из строк и столбцов. Количество строк определяется критерием выборки, указанном во фразе WHERE SQL-предложения. Порядок следования столбцов результата запроса соответствует порядку их перечисления в SQL-предложении. Тип данных столбцов результата запроса соответствует типу данных столбцов таблицы базы данных.
    Для извлечения данных результата запроса из объекта типа ResultSet используются методы getXXX() этого объекта, где XXX соответствует извлекаемому типу данных (например: getInt(), getString(), getDate()), а в скобках указывается в качестве параметра номер (начиная с 1) или символьное имя столбца. Объект типа ResultSet использует курсор, указывающий на текущую строку результата запроса. Перемещение курсора по строкам результата запроса осуществляется с помощью метода next() объекта типа ResultSet, содержащего этот результат. При этом существует два специальных положения курсора, указывающие на положение перед первой строкой результата запроса и на положение после последней строки результата запроса. Эти положения ничего не содержат и попытка получить из них данные приведет к возникновению исключения типа SQLException. В первоначальный момент сразу после заполнения объекта данными результата запроса курсор установлен в крайнем верхнем положении – перед первой строкой данных. По этому перед выполнением метода getXXX() необходимо переместить курсор на первую строку результата запроса. Обычно это делается с помощью уже упомянутого метода next(), который возвращает значение TRUE, если курсор после его выполнения указывает на строку с данными результата запроса, и FALSE, если курсор указывает на пустое положение после последней строки данных результата запроса. Это позволяет использовать метод в качестве условия при организации цикла перемещения курсора по строкам данных результата запроса.


Шаг. 6: Освобождение ресурсов.

    Освобождение ресурсов осуществляется методом close() объекта, представляющего собой тот или иной ресурс, например: результат запроса, соединение с базой и т.д.