Эта секция обеспечивает некоторые общие концепции 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_INCREMENTgetGeneratedKeys()
это предпочтительный метод, если необходимо получить
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.