Самый чистый способ построить строку SQL в Java



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



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



будет ли Groovy хорош?

1579   14  

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. Смотрите

http://www.jooq.org

(отказ от ответственности: я работаю в компании за 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 в запросах с помощью префикса":"

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

Мне интересно, если вы После что-то вроде цифирки. И что-то очень полезное jDBI. Это не поможет вам с запросами, хотя.

Я бы посмотрел на 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

    Ничего не найдено.