Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Java_Промышленное программирование1.doc
Скачиваний:
175
Добавлен:
13.04.2015
Размер:
5.58 Mб
Скачать

Метаданные

Существует целый ряд методов интерфейсов ResultSetMetaData и DatabaseMetaData для интроспекции объектов. С помощью этих методов можно получить список таблиц, определить типы, свойства и количество столбцов БД. Для строк подобных методов нет.

Получить объект ResultSetMetaData можно следующим образом:

ResultSetMetaData rsMetaData = rs.getMetaData();

Некоторые методы интерфейса ResultSetMetaData:

int getColumnCount() – возвращает число столбцов набора результатов объекта ResultSet;

String getColumnName(int column) – возвращает имя указанного столбца объекта ResultSet;

int getColumnType(int column) – возвращает тип данных указанного столбца объекта ResultSet и т.д.

Получить объект DatabaseMetaData можно следующим образом:

DatabaseMetaData dbMetaData = cn.getMetaData();

Некоторые методы весьма обширного интерфейса DatabaseMetaData:

String getDatabaseProductName() – возвращает название СУБД;

String getDatabaseProductVersion() – возвращает номер версии СУБД;

String getDriverName() – возвращает имя драйвера JDBC;

String getUserName() – возвращает имя пользователя БД;

String getURL() – возвращает местонахождение источника данных;

ResultSet getTables() – возвращает набор типов таблиц, доступных для данной БД, и т.д.

Подготовленные запросы и хранимые процедуры

Для представления запросов существуют еще два типа объектов PreparedStatement и CallableStatement. Объекты первого типа используются при выполнении часто повторяющихся запросов SQL. Такой оператор предварительно готовится и хранится в объекте, что ускоряет обмен информацией с базой данных. Второй интерфейс используется для выполнения хранимых процедур, созданных средствами самой СУБД.

Для подготовки SQL-запроса, в котором отсутствуют конкретные параметры, используется метод prepareStatement(String sql) интерфейса Connection, возвращающий объект PreparedStatement. Установка входных значений конкретных параметров этого объекта производится с помощью методов setString(), setInt() и подобных им, после чего и осуществляется непосредственное выполнение запроса методами executeUpdate(), executeQuery(). Так как данный оператор предварительно подготовлен, то он выполняется быстрее обычных операторов, ему соответствующих. Оценить пре- имущества во времени можно, выполнив большое число повторяемых запросов с предварительной подготовкой запроса и без нее.

/* пример # 2 : создание и выполнение подготовленного запроса :

PreparedStatementServlet.java */

package chapt20;

import java.io.*;

import java.sql.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class PreparedStatementServlet extends HttpServlet {

protected void doGet(HttpServletRequest req,

HttpServletResponse resp)

throws ServletException, IOException {

performTask(req, resp);

}

protected void doPost(HttpServletRequest req,

HttpServletResponse resp)

throws ServletException, IOException {

performTask(req, resp);

}

protected void performTask(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {

resp.setContentType("text/html");

PrintWriter out = resp.getWriter();

try {

Class.forName("org.gjt.mm.mysql.Driver");

Connection cn = null;

try {

cn = DriverManager.getConnection( "jdbc:mysql://localhost/db3","root","");

PreparedStatement ps = null;

String sql =

"INSERT INTO emp(id,name,surname,salary) VALUES(?,?,?,?)";

//компиляция (подготовка) запроса

ps = cn.prepareStatement(sql);

Rec.insert(ps, 2203, "Иван", "Петров", 230);

Rec.insert(ps, 2308, "John", "Black", 450);

Rec.insert(ps, 2505, "Mike", "Call", 620);

out.println("COMPLETE");

} finally {

if (cn != null) cn.close();

}

} catch (Exception e) {

e.printStackTrace();

}

out.close();

}

}

class Rec {

static void insert(PreparedStatement ps, int id, String name, String surname, int salary)

throws SQLException {

//установка входных параметров

ps.setInt(1, id);

ps.setString(2, name);

ps.setString(3, surname);

ps.setInt(4, salary);

//выполнение подготовленного запроса

ps.executeUpdate();

}

}

Результатом выполнения данной программы будет добавление в базу данных db3 трех записей и вывод в окно браузера слова COMPLETE.

Интерфейс CallableStatement расширяет возможности интерфейса PreparedStatement и обеспечивает выполнение хранимых процедур.

Хранимая процедура – это в общем случае именованная последовательность команд SQL, рассматриваемых как единое целое, и выполняющаяся в адресном пространстве процессов СУБД, который можно вызвать извне (в зависимости от политики доступа используемой СУБД). В данном случае хранимая процедура будет рассматриваться в более узком смысле как последовательность команд SQL, хранимых в БД и доступных любому пользователю этой СУБД. Механизм создания и настройки хранимых процедур зависит от конкретной базы данных. Для создания объекта CallableStatement вызывается метод prepareCall() объекта Connection.

Интерфейс CallableStatement позволяет исполнять хранимые проце­дуры, которые находятся непосредственно в БД. Одна из особенностей этого процесса в том, что CallableStatement способен обрабатывать не только входные (IN) параметры, но и выходящие (OUT) и смешанные (INOUT) параметры. Тип выходного параметра должен быть зарегистрирован методом registerOutParameter(). После установки входных и выходных параметров вызываются методы execute(), executeQuery() или executeUpdate().

Пусть в БД существует хранимая процедура getempname, которая по уникальному для каждой записи в таблице employee числу SSN будет возвращать соответствующее ему имя:

CREATE PROCEDURE getempname

(emp_ssn IN INT, emp_name OUT VARCHAR) AS

BEGIN

SELECT name

INTO emp_name

FROM employee

WHERE SSN = EMP_SSN;

END

Тогда для получения имени служащего employee через вызов данной процедуры необходимо исполнить java-код вида:

String SQL = "{call getempname (?,?)}";

CallableStatement cs = conn.prepareCall(SQL);

cs.setInt(1,822301);

//регистрация выходящего параметра

cs.registerOutParameter(2,java.sql.Types.VARCHAR);

cs.execute();

String empName = cs.getString(2);

System.out.println("Employee with SSN:" + ssn

+ " is " + empName);

В результате будет выведено:

Employee with SSN:822301 is Spiridonov

В JDBC также существует механизм batch-команд, который позволяет запускать на исполнение в БД массив запросов SQL вместе, как одну единицу.

// turn off autocommit

con.setAutoCommit(false);

Statement stmt = con.createStatement();

stmt.addBatch("INSERT INTO employee VALUES

(10, 'Joe ')");

stmt.addBatch("INSERT INTO location VALUES

(260, 'Minsk')");

stmt.addBatch("INSERT INTO emp_dept VALUES

(1000, 260)");

// submit a batch of update commands for execution

int[] updateCounts = stmt.executeBatch();

Если используется объект PreparedStatement, batch-команда состоит из параметризованного SQL-запроса и ассоциируемого с ним множества параметров.

Метод PreparedStatement.executeBatch() возвращает массив чисел, причем каждое характеризует число строк, которые были изменены конкретным запросом из batch-команды.

Пусть существует массив объектов типа Employee со стандартным набором методов getТип()/setТип() для каждого из его полей, и необходимо внести их значения в БД. Многократное выполнение методов execute() или executeUpdate() становится неэффективным, и в данном случае лучше использовать схему batch-команд:

try {

Employee[] employees = new Employee[10];

PreparedStatement statement =

con.prepareStatement("INSERT INTO employee VALUES

(?,?,?,?,?)");

for (int i = 0; i < employees.length; i++) {

Employee currEmployee = employees[i];

statement.setInt(1, currEmployee.getSSN());

statement.setString(2, currEmployee.getName());

statement.setDouble(3, currEmployee.getSalary());

statement.setString(4,currEmployee.getHireDate());

statement.setInt(5, currEmployee.getLoc_Id());

statement.addBatch();

}

updateCounts = statement.executeBatch();

} catch (BatchUpdateException e) {

e.printStackTrace();

}