Статьи

Облегченные интерфейсы SQL для Java

Ранее я писал в блоге о недостатках JDBC и способе передачи операторов SQL в виде строк без какой-либо проверки во время компиляции или безопасности типов. То же самое относится и к другим библиотекам доступа к базам данных на основе SQL, таким как ODBC , OLE DB и ADO.NET от Microsoft . Ни один из этих API не обеспечивает правильной интеграции SQL с языком хоста. Конечно, вы можете утверждать, что инструменты объектно-реляционного отображения (ORM), такие как Hibernate , избавили от необходимости работать напрямую с SQL, но я обнаружил, что все еще существуют ситуации, когда вы хотите более четко управлять операциями с базами данных.

Microsoft довольно элегантно решила эту проблему, представив LINQ to SQL в .NET Framework 3.5. Хотя в Java нет ничего эквивалентного, недавно я натолкнулся на несколько многообещающих усилий по улучшению языковой интеграции, предоставляя свободно распространяемые интерфейсы или другие облегченные оболочки вокруг JDBC и SQL.

Стандартный пример JDBC

Прежде чем мы углубимся в эти новые подходы, рассмотрим следующий пример с использованием традиционного JDBC (который печатает список роботов, которые «родились» до 1980 года):

public void printClassicRobots() {
    Calendar dobThreshold =
        new GregorianCalendar(1980, 0, 1);
    PreparedStatement statement = null;
    try {
        Connection connection = getConnection();
        statement = connection.prepareStatement(
                "SELECT ID, Name" +
                " FROM Robots" +
                " WHERE DateOfBirth < ?");
        statement.setDate(1, new Date(
                dobThreshold.getTimeInMillis()));

        ResultSet rs = statement.executeQuery();
        while (rs.next()) {
            System.out.format("%08d: %s\n",
                    rs.getInt(1),
                    rs.getString(2));
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        cleanup(statement);
    }
}

  

JEQUEL

Проект JEQUEL (Java Embedded QUEry Language) Майкла Хангера предоставляет внутренний DSL (предметно-ориентированный язык) для построения операторов SQL. Используя JEQUEL, вышеприведенный пример можно переписать следующим образом:

public static class Robots extends BaseTable<Robots>{

    public final Field<Integer> id = integer();
    public final Field<String> name = string();
    public final Field<Date> dateOfBirth = date();

    {
        initFields();
    }
}

public void printClassicRobots() {
    Calendar dobThreshold =
        new GregorianCalendar(1980, 0, 1);
    Robots robots = new Robots();
    Sql query =
        Select(robots.id, robots.name)
        .from(robots)
        .where(robots.dateOfBirth.lt(named("dob")))
        .toSql();
    query.executeOn(getDataSource())
        .withParams("dob", dobThreshold)
        .handleValues(new ValueRowHandler() {
            public void handleValue(int id,
                    String name) {
                System.out.format("%08d: %s\n",
                        id, name);
            }
    });
}

После определения запроса, он выполняется на DataSource , а его результирующий набор обрабатывается. Один из способов (среди прочего) сделать это — предоставить объекту обратного вызова метод handleValue , параметры которого соответствуют столбцам в наборе результатов. К сожалению, до времени выполнения вы не узнаете, не совпадает ли подпись метода с результирующим набором. В целом, я думаю, что JEQUEL выглядит очень элегантным решением, и я рассмотрю его более подробно.

спрашивается

Спрашивается проект Anders Noras призван обеспечить возможности запросов , подобные LINQ в Java. Как и сама LINQ, Quaere не ограничивается доступом к базе данных, но предоставляет общий DSL для запросов к различным типам структур данных и источников данных. Текущая реализация поддерживает массивы и коллекции в памяти, а также объекты JPA (API Java Persistence). В настоящее время нет поддержки SQL-запросов, поэтому он не совсем вписывается в категорию легких альтернатив инструментам ORM (поскольку для него требуется один в форме JPA). Но это, безусловно, проект, о котором стоит упомянуть, и в будущем должна быть возможность добавить поддержку SQL.

EoD SQL

Ранние бета-версии JDK 6 содержали функцию EoD (простота разработки) как часть JDBC 4.0, используя аннотации для определения операторов SQL . Позднее эта функция была удалена из JDK 6 и до сих пор не возвращена (она не включена в JDK 7 с версии 28). Однако тот же API был повторно реализован (с некоторыми дополнительными функциями) в проекте EoD SQL . Используя эту библиотеку, приведенный выше пример можно переписать следующим образом:

public static class Robot {
    public int id;
    public String name;
}

public static interface RobotDAI extends BaseQuery {

    @Select("SELECT ID, Name FROM Robots " +
            "WHERE DateOfBirth < ?{1}")
    public DataSet<Robot> getRobotsOlderThan(
            final Date date);
}

public void printClassicRobots() {
    Calendar dobThreshold =
        new GregorianCalendar(1980, 0, 1);
    try {
        RobotDAI query = QueryTool.getQuery(
                getConnection(), RobotDAI.class);
        DataSet<Robot> robots =
            query.getRobotsOlderThan(
                    dobThreshold.getTime());
        for (Robot robot : robots) {
            System.out.format("%08d: %s\n",
                    robot.id, robot.name);
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

Операторы SQL указываются в аннотациях к методам интерфейса доступа к данным ( RobotDAI выше). Объект, реализующий этот интерфейс, автоматически генерируется библиотекой, и вызов аннотированных методов для этого объекта вызывает выполнение соответствующих операторов SQL. Результаты запроса удобно возвращаются как пользовательские объекты данных, а не просто как ResultSet . К сожалению, сами операторы SQL по-прежнему необходимо указывать в виде строк без какой-либо проверки во время компиляции или поддержки IDE.

FEST-SQL?

В своей статье на InfoQ о внутренних DSL в Java Алекс Руиз (из FEST известности) и Джефф Бэй продемонстрировали пример DSL для построения операторов SQL и намекнули, что он будет выпущен как проект с открытым исходным кодом. Я не уверен, как они это назовут, может быть, «FEST-SQL» (хотя его полезность не должна ограничиваться тестированием)? В любом случае, это, безусловно, перспективный проект.

Вывод

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