На этой неделе мы рассмотрим некоторые удивительные сценарии SQL на стороне сервера с Nashorn и Java 8. В Интернете можно найти лишь несколько вещей, касающихся использования JDBC в Nashorn. Но зачем использовать JDBC и заботиться о болезненном управлении ресурсами и составлении строк SQL, когда вы можете использовать jOOQ ? Все работает из коробки!
Давайте настроим небольшой пример файла JavaScript так:
var someDatabaseFun = function() {
var Properties = Java.type("java.util.Properties");
var Driver = Java.type("org.h2.Driver");
var driver = new Driver();
var properties = new Properties();
properties.setProperty("user", "sa");
properties.setProperty("password", "");
try {
var conn = driver.connect("jdbc:h2:~/test", properties);
// Database code here
}
finally {
try {
if (conn) conn.close();
} catch (e) {}
}
}
someDatabaseFun();
Это почти все, что вам нужно для взаимодействия с JDBC и базой данных H2. Таким образом, мы могли бы выполнять операторы SQL с JDBC следующим образом:
try {
var stmt = conn.prepareStatement(
"select table_schema, table_name " +
"from information_schema.tables");
var rs = stmt.executeQuery();
while (rs.next()) {
print(rs.getString("TABLE_SCHEMA") + "."
+ rs.getString("TABLE_NAME"))
}
}
finally {
if (rs)
try {
rs.close();
}
catch(e) {}
if (stmt)
try {
stmt.close();
}
catch(e) {}
}
Большая часть раздувания связана с обработкой ресурсов JDBC, поскольку, к сожалению, у нас нет оператора try-with-resources в JavaScript. Выше генерируется следующий вывод:
INFORMATION_SCHEMA.FUNCTION_COLUMNS INFORMATION_SCHEMA.CONSTANTS INFORMATION_SCHEMA.SEQUENCES INFORMATION_SCHEMA.RIGHTS INFORMATION_SCHEMA.TRIGGERS INFORMATION_SCHEMA.CATALOGS INFORMATION_SCHEMA.CROSS_REFERENCES INFORMATION_SCHEMA.SETTINGS INFORMATION_SCHEMA.FUNCTION_ALIASES INFORMATION_SCHEMA.VIEWS INFORMATION_SCHEMA.TYPE_INFO INFORMATION_SCHEMA.CONSTRAINTS ...
Давайте посмотрим, сможем ли мы выполнить тот же запрос, используя jOOQ :
var DSL = Java.type("org.jooq.impl.DSL");
print(
DSL.using(conn)
.fetch("select table_schema, table_name " +
"from information_schema.tables")
);
Вот как вы можете выполнять простые операторы SQL в jOOQ, с гораздо меньшим раздуванием, чем в JDBC. Вывод примерно такой же:
+------------------+--------------------+ |TABLE_SCHEMA |TABLE_NAME | +------------------+--------------------+ |INFORMATION_SCHEMA|FUNCTION_COLUMNS | |INFORMATION_SCHEMA|CONSTANTS | |INFORMATION_SCHEMA|SEQUENCES | |INFORMATION_SCHEMA|RIGHTS | |INFORMATION_SCHEMA|TRIGGERS | |INFORMATION_SCHEMA|CATALOGS | |INFORMATION_SCHEMA|CROSS_REFERENCES | |INFORMATION_SCHEMA|SETTINGS | |INFORMATION_SCHEMA|FUNCTION_ALIASES | ...
Но сила jOOQ не в его простых возможностях SQL, а в API DSL, который абстрагирует все тонкости SQL, специфичные для поставщика, и позволяет быстро составлять запросы (а также DML). Рассмотрим следующий оператор SQL:
// Let's assume these objects were generated
// by the jOOQ source code generator
var Tables = Java.type("org.jooq.db.h2.information_schema.Tables");
var t = Tables.TABLES;
var c = Tables.COLUMNS;
// This is the equivalent of Java's static imports
var count = DSL.count;
var row = DSL.row;
// We can now execute the following query:
print(
DSL.using(conn)
.select(
t.TABLE_SCHEMA,
t.TABLE_NAME,
c.COLUMN_NAME)
.from(t)
.join(c)
.on(row(t.TABLE_SCHEMA, t.TABLE_NAME)
.eq(c.TABLE_SCHEMA, c.TABLE_NAME))
.orderBy(
t.TABLE_SCHEMA.asc(),
t.TABLE_NAME.asc(),
c.ORDINAL_POSITION.asc())
.fetch()
);
Обратите внимание, что в приведенном выше запросе очевидно нет безопасности типов, так как это JavaScript. Но я думаю, что создатели IntelliJ, Eclipse или NetBeans в конечном итоге обнаружат зависимости Nashorn от Java-программ и обеспечат автоматическое завершение и выделение синтаксиса, поскольку некоторые вещи можно анализировать статически.
Все становится еще лучше, если вы используете Java 8 Streams API от Nashorn. Давайте рассмотрим следующий запрос:
DSL.using(conn)
.select(
t.TABLE_SCHEMA,
t.TABLE_NAME,
count().as("CNT"))
.from(t)
.join(c)
.on(row(t.TABLE_SCHEMA, t.TABLE_NAME)
.eq(c.TABLE_SCHEMA, c.TABLE_NAME))
.groupBy(t.TABLE_SCHEMA, t.TABLE_NAME)
.orderBy(
t.TABLE_SCHEMA.asc(),
t.TABLE_NAME.asc())
// This fetches a List<Map<String, Object>> as
// your ResultSet representation
.fetchMaps()
// This is Java 8's standard Collection.stream()
.stream()
// And now, r is like any other JavaScript object
// or record!
.forEach(function (r) {
print(r.TABLE_SCHEMA + '.'
+ r.TABLE_NAME + ' has '
+ r.CNT + ' columns.');
});
Выше генерирует этот вывод:
INFORMATION_SCHEMA.CATALOGS has 1 columns. INFORMATION_SCHEMA.COLLATIONS has 2 columns. INFORMATION_SCHEMA.COLUMNS has 23 columns. INFORMATION_SCHEMA.COLUMN_PRIVILEGES has 8 columns. INFORMATION_SCHEMA.CONSTANTS has 7 columns. INFORMATION_SCHEMA.CONSTRAINTS has 13 columns. INFORMATION_SCHEMA.CROSS_REFERENCES has 14 columns. INFORMATION_SCHEMA.DOMAINS has 14 columns. ...
Если ваша база данных поддерживает массивы, вы даже можете получить доступ к таким столбцам массива по индексу, например,
r.COLUMN_NAME[3]
Так что, если вы являетесь поклонником JavaScript на стороне сервера, скачайте jOOQ сегодня и начните писать потрясающий SQL на JavaScript сейчас! Чтобы узнать больше о Nashorn, прочитайте эту статью здесь .