Как работает Java PreparedStatement?
-
03-07-2019 - |
Вопрос
Я планирую заменить многократно выполненные объекты Statement на объекты PreparedStatement
для повышения производительности. Я использую аргументы, такие как функция MySQL now ()
и строковые переменные. Р>
Большинство запросов PreparedStatement
, которые я видел, содержали в качестве аргументов значения констант (например, 10
и строки типа " New York "
). используется для ?
в запросах. Как мне использовать функции типа now ()
и переменные в качестве аргументов? Необходимо ли использовать ?
в запросах вместо фактических значений? Я довольно смущен.
Решение
Если у вас есть переменные, используйте '?'
int temp = 75;
PreparedStatement pstmt = con.prepareStatement(
"UPDATE test SET num = ?, due = now() ");
pstmt.setInt(1, temp);
pstmt.executeUpdate():
Создает SQL-оператор, который выглядит следующим образом:
UPDATE test SET num = 75, due = now();
Другие советы
Если у вас есть переменная, полученная из пользовательского ввода, важно, чтобы вы использовали? вместо того, чтобы объединять строки. Пользователи могут вводить строку злонамеренно, и если вы уроните строку прямо в SQL, он может выполнить команду, которую вы не собирались.
Я понимаю, что этот злоупотребляют, но он говорит это прекрасно:
Вам не нужно использовать заполнители в PreparedStatement. Что-то вроде:
PreparedStatement stmt = con.prepareStatement("select sysdate from dual");
будет работать просто отлично. Однако вы не можете использовать заполнитель, а затем привязать к нему вызов функции. Нечто подобное нельзя использовать для вызова функции sysdate:
PreparedStatement stmt = con.prepareStatement("select ? from dual");
stmt.setSomethingOrOther(1, "sysdate");
Если вы вызываете встроенные функции вашего сервера SQL, используйте PreparedStatement .
Если вы вызываете хранимые процедуры, которые были загружены на ваш сервер SQL, используйте CallableStatement .
Используйте вопросительные знаки в качестве заполнителей для параметров функции / процедуры, которые вы передаете, и возвращаемых значений функции, которые вы получаете.
Я разработал функцию, которая позволяет вам использовать именованные параметры в ваших запросах SQL:
private PreparedStatement generatePreparedStatement(String query, Map<String, Object> parameters) throws DatabaseException
{
String paramKey = "";
Object paramValue = null;
PreparedStatement statement = null;
Pattern paramRegex = null;
Matcher paramMatcher = null;
int paramIndex = 1;
try
{
//Create the condition
paramRegex = Pattern.compile("(:[\\d\\w_-]+)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
paramMatcher = paramRegex.matcher(query);
statement = this.m_Connection.prepareStatement(paramMatcher.replaceAll("?"),
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
//Check if there are parameters
paramMatcher = paramRegex.matcher(query);
while (paramMatcher.find())
{
paramKey = paramMatcher.group().substring(1);
if(parameters != null && parameters.containsKey(paramKey))
{
//Add the parameter
paramValue = parameters.get(paramKey);
if (paramValue instanceof Date)
{
statement.setDate(paramIndex, (java.sql.Date)paramValue);
}
else if (paramValue instanceof Double)
{
statement.setDouble(paramIndex, (Double)paramValue);
}
else if (paramValue instanceof Long)
{
statement.setLong(paramIndex, (Long)paramValue);
}
else if (paramValue instanceof Integer)
{
statement.setInt(paramIndex, (Integer)paramValue);
}
else if (paramValue instanceof Boolean)
{
statement.setBoolean(paramIndex, (Boolean)paramValue);
}
else
{
statement.setString(paramIndex, paramValue.toString());
}
}
else
{
throw new DatabaseException("The parameter '" + paramKey + "' doesn't exists in the filter '" + query + "'");
}
paramIndex++;
}
}
catch (SQLException l_ex)
{
throw new DatabaseException(tag.lib.common.ExceptionUtils.getFullMessage(l_ex));
}
return statement;
}
Вы можете использовать это следующим образом:
Map<String, Object> pars = new HashMap<>();
pars.put("name", "O'Really");
String sql = "SELECT * FROM TABLE WHERE NAME = :name";