Самый чистый способ создания строки SQL в Java

Я хочу создать строку SQL для обработки базы данных (обновления, удаления, вставки, выборки, что-то вроде этого) - вместо ужасного метода строки concat с использованием миллионов "+" и кавычек, которые в лучшем случае нечитаемы - должен быть лучший способ.

Я думал об использовании MessageFormat, но его предполагалось использовать для пользовательских сообщений, хотя я думаю, что он выполнил бы разумную работу, но я думаю, что должно быть что-то более согласованное с операциями типа SQL в java-sql-библиотеках.

Будет ли Groovy быть хорошим?

Ответ 1

Прежде всего рассмотрим использование параметров запроса в подготовленных операторах:

PreparedStatement stm = c.prepareStatement("UPDATE user_table SET name=? WHERE id=?");
stm.setString(1, "the name");
stm.setInt(2, 345);
stm.executeUpdate();

Другое, что можно сделать, это сохранить все запросы в файле свойств. Например в файле queries.properties может быть указан следующий запрос:

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"));

Это довольно простое решение, но хорошо работает.

Ответ 2

Для произвольного 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. См

http://www.jooq.org

(Отказ от ответственности: я работаю в компании за jOOQ)

Ответ 3

Одной технологией, которую вы должны рассмотреть, является 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 в запросах с использованием префикса ":"

Для большинства основных поставщиков баз данных существуют реализации переводчика, поэтому вы должны легко найти все, что вам нужно.

Ответ 4

Мне интересно, если вы после чего-то вроде Squiggle. Также очень полезно jDBI. Это не поможет вам с запросами.

Ответ 5

Я бы посмотрел Spring JDBC. Я использую его всякий раз, когда мне нужно программно выполнять SQL. Пример:

int countOfActorsNamedJoe
    = jdbcTemplate.queryForInt("select count(0) from t_actors where first_name = ?", new Object[]{"Joe"});

Это действительно отлично подходит для любого исполнения sql, особенно для запросов; это поможет вам отображать объекты результатов в объекты, не добавляя сложность полного ORM.

Ответ 6

Я обычно использую Spring Именованные параметры JDBC, поэтому могу написать стандартную строку типа "select * from blah where colX = ': someValue'"; Я думаю, что это довольно читаемый.

Альтернативой будет предоставление строки в отдельном файле .sql и чтение содержимого с использованием утилиты.

О, также стоит взглянуть на Squill: https://squill.dev.java.net/docs/tutorial.html

Ответ 7

Почему вы хотите сгенерировать все sql вручную? Вы рассматривали ORM как Hibernate. В зависимости от вашего проекта он, вероятно, сделает не менее 95% того, что вам нужно, сделайте это более чистым способом, чем исходный SQL, и если вам нужно получить последний бит производительности, вы можете создать SQL-запросы, которые необходимо настроить вручную.

Ответ 8

Во-вторых, рекомендации по использованию ORM, например Hibernate. Однако есть ситуации, когда это не работает, поэтому я воспользуюсь этой возможностью, чтобы обсудить некоторые вещи, которые я помог написать: SqlBuilder - это java-библиотека для динамического создания sql-операторов с использованием стиля "строитель". он довольно мощный и довольно гибкий.

Ответ 9

Вы также можете посмотреть MyBatis (www.mybatis.org). Это помогает вам писать инструкции SQL за пределами вашего java-кода и отображать результаты sql в ваши java-объекты, между прочим.

Ответ 10

Я работал над приложением Java-сервлета, которое должно создавать очень динамические операторы SQL для специальных отчетов. Основная функция приложения заключается в том, чтобы подавать кучу названных параметров HTTP-запроса в предварительно кодированный запрос и генерировать красиво отформатированную таблицу вывода. Я использовал Spring MVC и инфраструктуру инъекции зависимостей для хранения всех моих 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-запроса непосредственно в запросе с надлежащей проверкой типов и проверкой ограничений. Никаких дополнительных сопоставлений, необходимых для проверки ввода. В вышеприведенном примере параметр с именем serverId будет проверен, чтобы убедиться, что он может быть отлит до целого числа и находится в диапазоне 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 в настоящий момент, и весь код принадлежит крупной корпорации. Когда-нибудь я смогу принять мои идеи и создать новую инфраструктуру с открытым исходным кодом, но я надеюсь, что один из существующих крупных игроков возьмет на себя эту задачу.

Ответ 11

Чтение XML файла.

Вы можете прочитать его из файла XML. Его легко поддерживать и работать. Есть стандартные анализаторы STaX, DOM, SAX, доступные там, чтобы сделать несколько строк кода в java.

Сделайте больше с атрибутами

У вас может быть семантическая информация с атрибутами тега, чтобы помочь сделать больше с SQL. Это может быть имя метода или тип запроса или все, что помогает вам меньше кода.

Maintaince

Вы можете поместить xml за пределы банки и легко сохранить его. Такие же преимущества, как и файл свойств.

Конверсия

XML расширяемый и легко конвертируемый в другие форматы.

Пример использования

Metamug использует xml для настройки файлов ресурсов REST с помощью sql.

Ответ 12

Если вы поместите строки SQL в файл свойств и затем прочитаете это, вы можете сохранить строки SQL в текстовом файле.

Это не решает проблемы типа SQL, но, по крайней мере, значительно облегчает копирование и вставку из TOAD или sqlplus.

Ответ 13

Google предоставляет библиотеку, называемую Room Persitence Library, которая обеспечивает очень чистый способ написания 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.

Ответ 14

Как вы получаете конкатенацию строк, за исключением длинных строк SQL в PreparedStatements (которые вы можете легко предоставить в текстовом файле и загружать как ресурс в любом случае), что вы разбиваете несколько строк?

Вы не создаете строки SQL напрямую? Это самый большой нет-нет в программировании. Пожалуйста, используйте PreparedStatements и поставьте данные как параметры. Это значительно сокращает вероятность внедрения SQL Injection.