Ранее я писал в блоге о недостатках 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 может оказаться неподходящим инструментом для работы. Я определенно хотел бы, чтобы эти усилия продолжались и получили более широкое признание. Спасибо всем, кто предоставил эти инновационные инструменты!