Эта секция обеспечивает некоторые общие концепции JDBC.
DriverManager
Когда вы используете JDBC за пределами сервера приложений, класс
DriverManager
управляет связями.
Определите для DriverManager
, с какими
драйверами JDBC попытаться установить связи. Самый легкий способ сделать это:
использовать Class.forName()
в классе, который
осуществляет интерфейс java.sql.Driver
.
С MySQL Connector/J название этого класса
com.mysql.cj.jdbc.Driver
.
С этим методом вы могли использовать внешний конфигурационный файл, чтобы
поставлять имя класса драйвера и параметры, чтобы использовать,
соединяясь с базой данных.
Следующий раздел показывает код Java, как вы могли бы зарегистрировать
MySQL Connector/J из метода main()
вашего
приложения. Проверяя этот код, сначала прочитайте инсталляционную секцию в
главе 4, чтобы удостовериться, что установили
соединитель правильно и настроили CLASSPATH
.
Кроме того, гарантируйте, что MySQL формируется, чтобы принять внешние
связи TCP/IP.
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; // Notice, do not import com.mysql.cj.jdbc.* // or you will have problems! public class LoadDriver { public static void main(String[] args) { try { // The newInstance() call is a work around for some // broken Java implementations Class.forName("com.mysql.cj.jdbc.Driver").newInstance(); } catch (Exception ex) { // handle the error } } }
После того, как драйвер был зарегистрирован в
DriverManager
, можно получить экземпляр
Connection
, который связан с конкретной базой
данных, вызывая DriverManager.getConnection()
:
Пример 7.1. Connector/J: Получение связи от
DriverManager
Если вы еще не сделали этого, пожалуйста, просмотрите раздел 7.1 выше прежде, чем работать с примером ниже.
Этот пример показывает, как можно получить экзепляр
Connection
из
DriverManager
.
Есть несколько различных сигнатур для метода
getConnection()
.
Консультируйтесь с документацией API, которая идет с вашим JDK для более
определенной информации о том, как использовать их.
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; Connection conn = null; ... try { conn = DriverManager.getConnection("jdbc:mysql://localhost/test?" + "user=minty&password=greatsqldb"); // Do something with the Connection ... } catch (SQLException ex) { // handle any errors System.out.println("SQLException: " + ex.getMessage()); System.out.println("SQLState: " + ex.getSQLState()); System.out.println("VendorError: " + ex.getErrorCode()); }
После установки Connection
это может
использоваться, чтобы создать объекты
Statement
и
PreparedStatement
, а также получить
метаданные о базе данных. Это объяснено в следующих разделах.
Statement
,
чтобы выполнить SQLОбъекты Statement
позволяют вам выполнять
основные SQL-запросы и получать результаты через класс
ResultSet
, который описан позже.
Чтобы создать экземпляр Statement
,
вызовите метод createStatement()
на объекте
Connection
, который вы получили с использованием
одного из методов DriverManager.getConnection()
или DataSource.getConnection()
, описанных ранее.
Имея экземпляр Statement
, можно
выполнить запрос SELECT
вызовом метода
executeQuery(String)
с SQL, который вы хотите использовать.
Чтобы обновить данные в базе данных, используйте метод
executeUpdate(String SQL)
.
Этот метод возвращает количество строк, соответствовавших запросу
обновления, а не количество строк, которые были изменены.
Если вы не знаете заранее, будет ли SQL-оператор
be a SELECT
или
UPDATE
/
INSERT
, тогда можно использовать метод.
Он вернет true, если SQL-запрос был
SELECT
, или false, если SQL-запрос был
UPDATE
,
INSERT
или
DELETE
. Если это был
SELECT
, можно получить результаты, вызвав
метод getResultSet()
. Если это был
UPDATE
,
INSERT
или
DELETE
, можно узнать затронутое количество
строк вызовом getUpdateCount()
в экземпляре
Statement
.
Пример 7.2. Connector/J: применение java.sql.Statement для выполнения
SELECT
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import java.sql.ResultSet; // assume that conn is an already created JDBC connection (see previous examples) Statement stmt = null; ResultSet rs = null; try { stmt = conn.createStatement(); rs = stmt.executeQuery("SELECT foo FROM bar"); // or alternatively, if you don't know ahead of time that // the query will be a SELECT... if (stmt.execute("SELECT foo FROM bar")) { rs = stmt.getResultSet(); } // Now do something with the ResultSet .... } catch (SQLException ex) { // handle any errors System.out.println("SQLException: " + ex.getMessage()); System.out.println("SQLState: " + ex.getSQLState()); System.out.println("VendorError: " + ex.getErrorCode()); } finally { // it is a good idea to release resources in a finally{} block // in reverse-order of their creation // if they are no-longer needed if (rs != null) { try { rs.close(); } catch (SQLException sqlEx) { } // ignore rs = null; } if (stmt != null) { try { stmt.close(); } catch (SQLException sqlEx) { } // ignore stmt = null; } }
CallableStatements
для выполнения сохраненных процедурConnector/J полностью понимает интерфейс
java.sql.CallableStatement
.
Для получения дополнительной информации о хранимых процедурах MySQL, пожалуйста, обратитесь к Using Stored Routines.
Connector/J выставляет функциональность хранимой процедуры через интерфейс
JDBC CallableStatement
.
Следующий пример показывает хранимую процедуру, которая возвращает
значение inOutParam
+1 и последовательность,
переданную с использованием inputParam
, как
ResultSet
:
Пример 7.3. Connector/J: Запрос хранимых процедур
CREATE PROCEDURE demoSp(IN inputParam VARCHAR(255), INOUT inOutParam INT) BEGIN DECLARE z INT; SET z = inOutParam + 1; SET inOutParam = z; SELECT inputParam; SELECT CONCAT('zyxw', inputParam); END
Чтобы использовать процедуру demoSp
с
Connector/J, выполните эти шаги:
Подготовьте запрос при помощи
Connection.prepareCall()
.
Заметьте, что необходимо использовать синтаксис JDBC escape и что круглые скобки, окружающие заполнители параметра, не опциональны:
Пример 7.4. Connector/J: Применение
Connection.prepareCall()
import java.sql.CallableStatement; ... // Prepare a call to the stored procedure 'demoSp' // with two parameters // // Notice the use of JDBC-escape syntax ({call ...}) CallableStatement cStmt = conn.prepareCall("{call demoSp(?, ?)}"); cStmt.setString(1, "abcdefg");
Connection.prepareCall()
дорогой метод из-за
поиска метаданных, который драйвер выполняет, чтобы поддержать параметры
вывода. По исполнительным причинам минимизируйте ненужные запросы
Connection.prepareCall()
снова используя
экземпляр CallableStatement
.
Зарегистрируйте параметры вывода (если есть).
Чтобы получить значения параметров вывода (параметры, определенные как
OUT
или INOUT
,
когда вы создали хранимую процедуру), JDBC требует, чтобы они были определены
перед выполнением запроса, используя различные методы
registerOutputParameter()
в интерфейсе
the CallableStatement
:
Пример 7.5. Connector/J: Регистрация параметров вывода
import java.sql.Types; ... // Connector/J supports both named and indexed // output parameters. You can register output // parameters using either method, as well // as retrieve output parameters using either // method, regardless of what method was used to register them. // // The following examples show how to use // the various methods of registering // output parameters (you should of course // use only one registration per parameter). // Registers the second parameter as output, and // uses the type 'INTEGER' for values returned // from getObject() // cStmt.registerOutParameter(2, Types.INTEGER); // Registers the named parameter 'inOutParam', and // uses the type 'INTEGER' for values returned // from getObject() cStmt.registerOutParameter("inOutParam", Types.INTEGER); ...
Установите входные параметры (если есть).
Параметры ввода и in/out заданы как для объектов
PreparedStatement
, но
CallableStatement
также понимают
параметры по имени:
Пример 7.6. Connector/J: Установка входных параметров
CallableStatement
... // Set a parameter by index cStmt.setString(1, "abcdefg"); // Alternatively, set a parameter using the parameter name cStmt.setString("inputParam", "abcdefg"); // Set the 'in/out' parameter using an index cStmt.setInt(2, 1); // Alternatively, set the 'in/out' parameter by name cStmt.setInt("inOutParam", 1); ...
Выполните CallableStatement
и получите любые наборы результатов или выходные параметры.
Хотя CallableStatement
допускает вызов
любого из методов выполнения Statement
(executeUpdate()
,
executeQuery()
или
execute()
), самый гибкий метод, это вызвать
execute()
, поскольку вы не должны знать
заранее, что хранимая процедура возвращает наборы результатов:
Пример 7.7. Connector/J: Получение результатов и значений выходных параметров
... boolean hadResults = cStmt.execute(); // // Process all returned result sets // while (hadResults) { ResultSet rs = cStmt.getResultSet(); // process result set ... hadResults = cStmt.getMoreResults(); } // Retrieve output parameters // // Connector/J supports both index-based and // name-based retrieval int outputValue = cStmt.getInt(2); // index-based outputValue = cStmt.getInt("inOutParam"); // name-based ...
AUTO_INCREMENT
getGeneratedKeys()
это предпочтительный метод, если необходимо получить
AUTO_INCREMENT
через JDBC, это иллюстрировано в
первом примере ниже. Второй пример показывает, как можно получить то же самое
значение, используя стандартный запрос
SELECT LAST_INSERT_ID()
.
Заключительный пример показывает, как обновляемые наборы результатов могут
получить значение AUTO_INCREMENT
, используя
метод insertRow()
.
Пример 7.8. Connector/J: Получение значений столбца
AUTO_INCREMENT
через
Statement.getGeneratedKeys()
Statement stmt = null; ResultSet rs = null; try { // Create a Statement instance that we can use for // 'normal' result sets assuming you have a // Connection 'conn' to a MySQL database already available stmt = conn.createStatement(); // Issue the DDL queries for the table for this example stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial"); stmt.executeUpdate("CREATE TABLE autoIncTutorial (" + "priKey INT NOT NULL AUTO_INCREMENT, " + "dataField VARCHAR(64), PRIMARY KEY (priKey))"); // Insert one row that will generate an AUTO INCREMENT // key in the 'priKey' field stmt.executeUpdate("INSERT INTO autoIncTutorial (dataField) " + "values ('Can I Get the Auto Increment Field?')", Statement.RETURN_GENERATED_KEYS); // Example of using Statement.getGeneratedKeys() // to retrieve the value of an auto-increment value int autoIncKeyFromApi = -1; rs = stmt.getGeneratedKeys(); if (rs.next()) { autoIncKeyFromApi = rs.getInt(1); } else { // throw an exception from here } System.out.println("Key returned from getGeneratedKeys():" + autoIncKeyFromApi); } finally { if (rs != null) { try { rs.close(); } catch (SQLException ex) { // ignore } } if (stmt != null) { try { stmt.close(); } catch (SQLException ex) { // ignore } } }
Пример 7.9. Connector/J: Получение значений столбца
AUTO_INCREMENT
через
SELECT LAST_INSERT_ID()
Statement stmt = null; ResultSet rs = null; try { // Create a Statement instance that we can use for // 'normal' result sets. stmt = conn.createStatement(); // Issue the DDL queries for the table for this example stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial"); stmt.executeUpdate("CREATE TABLE autoIncTutorial (" + "priKey INT NOT NULL AUTO_INCREMENT, " + "dataField VARCHAR(64), PRIMARY KEY (priKey))"); // Insert one row that will generate an AUTO INCREMENT // key in the 'priKey' field stmt.executeUpdate("INSERT INTO autoIncTutorial (dataField) " + "values ('Can I Get the Auto Increment Field?')"); // Use the MySQL LAST_INSERT_ID() // function to do the same thing as getGeneratedKeys() int autoIncKeyFromFunc = -1; rs = stmt.executeQuery("SELECT LAST_INSERT_ID()"); if (rs.next()) { autoIncKeyFromFunc = rs.getInt(1); } else { // throw an exception from here } System.out.println("Key returned from " + "'SELECT LAST_INSERT_ID()': " + autoIncKeyFromFunc); } finally { if (rs != null) { try { rs.close(); } catch (SQLException ex) { // ignore } } if (stmt != null) { try { stmt.close(); } catch (SQLException ex) { // ignore } } }
Пример 7.10. Connector/J: Получение значений столбца
AUTO_INCREMENT
в
Updatable ResultSets
Statement stmt = null; ResultSet rs = null; try { // Create a Statement instance that we can use for // 'normal' result sets as well as an 'updatable' // one, assuming you have a Connection 'conn' to // a MySQL database already available stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_UPDATABLE); // Issue the DDL queries for the table for this example stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial"); stmt.executeUpdate("CREATE TABLE autoIncTutorial (" + "priKey INT NOT NULL AUTO_INCREMENT, " + "dataField VARCHAR(64), PRIMARY KEY (priKey))"); // Example of retrieving an AUTO INCREMENT key // from an updatable result set rs = stmt.executeQuery("SELECT priKey, dataField "+"FROM autoIncTutorial"); rs.moveToInsertRow(); rs.updateString("dataField", "AUTO INCREMENT here?"); rs.insertRow(); // the driver adds rows at the end rs.last(); // We should now be on the row we just inserted int autoIncKeyFromRS = rs.getInt("priKey"); System.out.println("Key returned for inserted row: " + autoIncKeyFromRS); } finally { if (rs != null) { try { rs.close(); } catch (SQLException ex) { // ignore } } if (stmt != null) { try { stmt.close(); } catch (SQLException ex) { // ignore } } }
Управление предыдущим примером кода должно произвести следующий вывод:
Key returned from getGeneratedKeys(): 1 Key returned from SELECT LAST_INSERT_ID(): 1 Key returned for inserted row: 1
Время от времени это может быть хитро, чтобы использовать запрос
SELECT LAST_INSERT_ID()
,
поскольку значение привязано к соединению. Так, если некоторый другой запрос
происходит на той же самой связи, значение переписано. С другой стороны,
метод getGeneratedKeys()
относится к экземпляру
Statement
, таким образом, это может
использоваться, даже если другие запросы происходят на той же самой связи, но
не на том же самом Statement
.