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