Самый чистый способ построить строку SQL в Java
Я хочу построить строку SQL для выполнения манипуляций с базой данных (обновления, удаления, вставки, выбора и т. д.) - вместо ужасного метода конката строк, использующего миллионы "+"и кавычек, которые в лучшем случае не читаются - должен быть лучший способ.
Я думал об использовании MessageFormat - но его предполагается использовать для пользовательских сообщений, хотя я думаю, что это будет разумная работа - но я думаю, что должно быть что-то более согласованное с операциями типа SQL в Java и SQL для библиотеки.
будет ли Groovy хорош?
14 ответов:
прежде всего рассмотрите возможность использования параметров запроса в подготовленных операторах:
PreparedStatement stm = c.prepareStatement("UPDATE user_table SET name=? WHERE id=?"); stm.setString(1, "the name"); stm.setInt(2, 345); stm.executeUpdate();другое, что можно сделать, это сохранить все запросы в файле свойств. Например в запросы.свойства файла можно разместить выше запрос:
update_query=UPDATE user_table SET name=? WHERE id=?затем с помощью простого служебного класса:
public class Queries { private static final String propFileName = "queries.properties"; private static Properties props; public static Properties getQueries() throws SQLException { InputStream is = Queries.class.getResourceAsStream("/" + propFileName); if (is == null){ throw new SQLException("Unable to load property file: " + propFileName); } //singleton if(props == null){ props = new Properties(); try { props.load(is); } catch (IOException e) { throw new SQLException("Unable to load property file: " + propFileName + "\n" + e.getMessage()); } } return props; } public static String getQuery(String query) throws SQLException{ return getQueries().getProperty(query); } }вы можете использовать свои запросы следующим образом:
PreparedStatement stm = c.prepareStatement(Queries.getQuery("update_query"));Это достаточно простое решение, но работает хорошо.
для произвольного SQL используйте jOOQ. jOOQ в настоящее время поддерживает
SELECT,INSERT,UPDATE,DELETE,TRUNCATEиMERGE. Вы можете создать SQL следующим образом:String sql1 = DSL.using(SQLDialect.MYSQL) .select(A, B, C) .from(MY_TABLE) .where(A.equal(5)) .and(B.greaterThan(8)) .getSQL(); String sql2 = DSL.using(SQLDialect.MYSQL) .insertInto(MY_TABLE) .values(A, 1) .values(B, 2) .getSQL(); String sql3 = DSL.using(SQLDialect.MYSQL) .update(MY_TABLE) .set(A, 1) .set(B, 2) .where(C.greaterThan(5)) .getSQL();вместо получения строки SQL, вы также можете просто выполнить его, используя jOOQ. Смотрите
(отказ от ответственности: я работаю в компании за jOOQ)
одна технология, которую вы должны рассмотреть, является SQLJ - способ встраивания операторов SQL непосредственно в Java. В качестве простого примера можно привести следующий файл с именем TestQueries.sqlj:
public class TestQueries { public String getUsername(int id) { String username; #sql { select username into :username from users where pkey = :id }; return username; } }существует дополнительный шаг предварительной компиляции, который принимает ваш .sqlj файлы и переводит их в чистую Java-короче говоря, он ищет специальные блоки, разделенные
#sql { ... }и превращает их в вызовы JDBC. Есть несколько ключевых преимуществ использования SQLJ:
- полностью абстрагируется от уровня JDBC-программистам нужно только думать о Java и SQL
- переводчик может быть сделано, чтобы проверить свои запросы за синтаксис и т. д. против базы данных во время компиляции
- возможность напрямую связывать переменные Java в запросах с помощью префикса":"
есть реализации транслятора для большинства основных поставщиков баз данных, так что вы должны быть в состоянии найти все вам нужно легко.
Я бы посмотрел на Spring JDBC. Я использую его всякий раз, когда мне нужно выполнить SQLs программно. Пример:
int countOfActorsNamedJoe = jdbcTemplate.queryForInt("select count(0) from t_actors where first_name = ?", new Object[]{"Joe"});это действительно отлично подходит для любого вида выполнения sql, особенно запросов; это поможет вам сопоставить результирующие наборы объектов, не добавляя сложности полного ORM.
Я обычно использую параметры Spring с именем JDBC, поэтому я могу написать стандартную строку, такую как" select * from blah where colX=':someValue'"; я думаю, что это довольно читабельно.
альтернативой было бы поставить строку в отдельном .sql-файл и прочитать содержимое с помощью служебного метода.
о, Также стоит взглянуть на Squill:https://squill.dev.java.net/docs/tutorial.html
Почему вы хотите создать все sql вручную? Вы смотрели на ORM, как Hibernate в зависимости от вашего проекта, он, вероятно, будет делать не менее 95% того, что вам нужно, делать это более чистым способом, а затем raw SQL, и если вам нужно получить последний бит производительности, вы можете создать SQL-запросы, которые нужно настроить вручную.
Я поддерживаю рекомендации по использованию ORM, таких как Hibernate. Тем не менее, есть, конечно, ситуации, когда это не работает, поэтому я воспользуюсь этой возможностью, чтобы рекламировать некоторые вещи, которые я помог написать: SqlBuilder библиотека java для динамического построения операторов sql с использованием стиля "builder". это довольно мощный и довольно гибкий.
вы также можете посмотреть на MyBatis (www.mybatis.org) . Это помогает вам писать операторы SQL вне вашего кода java и сопоставлять результаты sql с вашими объектами java среди прочего.
Я работал над приложением Java servlet, которое должно создавать очень динамические операторы SQL для целей отчетности adhoc. Основная функция приложения состоит в том, чтобы передать кучу именованных параметров HTTP-запроса в предварительно закодированный запрос и создать красиво отформатированную таблицу вывода. Я использовал Spring MVC и Dependency injection framework для хранения всех моих SQL-запросов в XML-файлах и загрузки их в приложение для отчетов вместе с информацией о форматировании таблицы. В конце концов, требования к отчетности стали более сложными, чем возможности существующих фреймворков сопоставления параметров, и мне пришлось написать свой собственный. Это было интересное упражнение в разработке и создало структуру для отображения параметров гораздо более надежную, чем все остальное, что я мог найти.
новые сопоставления параметров выглядели так:
select app.name as "App", ${optional(" app.owner as "Owner", "):showOwner} sv.name as "Server", sum(act.trans_ct) as "Trans" from activity_records act, servers sv, applications app where act.server_id = sv.id and act.app_id = app.id and sv.id = ${integer(0,50):serverId} and app.id in ${integerList(50):appId} group by app.name, ${optional(" app.owner, "):showOwner} sv.name order by app.name, sv.nameкрасота результирующей структуры заключалась в том, что она могла обрабатывать параметры HTTP-запроса непосредственно в запрос с правильной проверкой типа и проверкой предела. Для проверки ввода не требуется никаких дополнительных сопоставлений. В приведенном выше примере запроса параметр с именем идентификатор будет проверено, чтобы убедиться, что он может привести к целому числу и находится в диапазоне 0-50. Параметр appId будет обрабатываться как массив целых чисел, с ограничением по длине 50. Если поле showOwner присутствует и установлено в "true", биты SQL в кавычках будут добавлены к созданный запрос для дополнительных полей. поле доступно еще несколько сопоставлений типов параметров, включая необязательные сегменты SQL с дополнительными сопоставлениями параметров. Это позволяет настолько сложное сопоставление запросов, насколько разработчик может придумать. Он даже имеет элементы управления в конфигурации отчета, чтобы определить, будет ли данный запрос иметь окончательные сопоставления с помощью PreparedStatement или просто выполняется как предварительно построенный запрос.
для примера Http-запроса значения:
showOwner: true serverId: 20 appId: 1,2,3,5,7,11,13Он будет производить следующий SQL:
select app.name as "App", app.owner as "Owner", sv.name as "Server", sum(act.trans_ct) as "Trans" from activity_records act, servers sv, applications app where act.server_id = sv.id and act.app_id = app.id and sv.id = 20 and app.id in (1,2,3,5,7,11,13) group by app.name, app.owner, sv.name order by app.name, sv.nameЯ действительно думаю, что Spring или Hibernate или одна из этих структур должны предлагать более надежный механизм отображения, который проверяет типы, позволяет использовать сложные типы данных, такие как массивы и другие подобные функции. Я написал свой движок только для своих целей, он не совсем читается для общего выпуска. На данный момент он работает только с запросами Oracle, и весь код принадлежит большой корпорации. Когда-нибудь я могу взять мои идеи и построить новую структуру с открытым исходным кодом, но я надеюсь, что один из существующих крупных игроков примет вызов.
чтение XML-файла.
Вы можете прочитать его из файла XML. Его легко поддерживать и работать. Есть стандартные Stax, DOM, SAX Парсеры доступны там, чтобы сделать его несколько строк кода в java.
сделать больше с атрибутами
Вы можете иметь некоторую семантическую информацию с атрибутами в теге, чтобы помочь сделать больше с SQL. Это может быть имя метода или тип запроса или что-нибудь, что поможет вам кодировать меньше.
Maintaince
вы смогите положить xml вне опарника и легко поддерживать его. Те же преимущества, что и файл свойств.
преобразование
XML является расширяемым и легко конвертируемым в другие форматы.
Use Case
Metamug использует xml для настройки файлов ресурсов REST с помощью sql.
Google предоставляет библиотеку под названием Номер Упорством Библиотека что обеспечивает очень чистый способ написания sql. Ниже приведен короткий фрагмент кода с официального сайта:
@Dao public interface UserDao { @Query("SELECT * FROM user") List<User> getAll(); @Query("SELECT * FROM user WHERE uid IN (:userIds)") List<User> loadAllByIds(int[] userIds); @Query("SELECT * FROM user WHERE first_name LIKE :first AND " + "last_name LIKE :last LIMIT 1") User findByName(String first, String last); @Insert void insertAll(User... users); @Delete void delete(User user); }есть больше примеров и лучшей документации в официальных документах для библиотеки.
есть также один называется MentaBean, который является Java ORM. Он имеет хорошие функции и, кажется, довольно простой способ написания SQL.
Если вы помещаете строки SQL в файл свойств, а затем читаете это, вы можете сохранить строки SQL в обычном текстовом файле.
Это не решает проблемы типа SQL, но, по крайней мере, это делает копирование и вставку из жабы или sqlplus намного проще.
Как вы получаете конкатенацию строк, помимо длинных строк SQL в PreparedStatements (которые вы можете легко предоставить в текстовом файле и загрузить в качестве ресурса в любом случае), которые вы разбиваете на несколько строк?
вы не создаете строки SQL непосредственно вы? Это самое большое нет-нет в программировании. Пожалуйста, используйте PreparedStatements, и предоставить данные в качестве параметров. Это значительно снижает вероятность SQL-инъекции.
Comments