Эта статья была первоначально написана Стефано Санторо
VoltDB приветствует Groovy в своей экосистеме в качестве первого встроенного языка процедур. Код вашей логики процедуры прямо в DDL, обходя требования процедуры Java для отдельного редактирования / компиляции исходных файлов Java.
С помощью хранимых процедур VoltDB Groovy вы можете кодировать реализацию вашей процедуры как часть инструкций CREATE PROCEDURE в вашем файле DDL.
CREATE PROCEDURE groovy.procedures.Item AS ### selectItem = new SQLStmt('SELECT ITEM_ID, DESCRIPTION FROM ITEMS WHERE ITEM_ID = ?') transactOn = { id -> voltQueueSQL(selectItem, EXPECT_ZERO_OR_ONE_ROW, id) voltExecuteSQL(true) } ### LANGUAGE GROOVY; PARTITION PROCEDURE Item ON TABLE ITEMS COLUMN ITEM_ID;
Как написать заводную процедуру
Вы можете положиться на тот факт, что следующие процедуры импорта предопределены и доступны для процедур Groovy:
import static org.voltdb.VoltTypes.* import static org.voltdb.VoltProcedure.* import org.voltdb.* import org.voltdb.groovy.TableBuilder import org.voltdb.groovy.Tuplerator import org.voltdb.VoltProcedure.VoltAbortException
Сначала вы определяете экземпляры SQLStmt
этого, как в Java, никогда не должны изменяться в коде процедуры. Это потому, что VoltDB размышляет, анализирует и создает план для этих заявлений.
Вам необходимо определить transactOn
закрытие. VoltDB вызывает это закрытие, когда фактически выполняет процедуру. Замыкание может принимать любые аргументы, которые его эквивалентный метод запуска Java может. Он также должен возвращать a VoltTable
, или массив VoltTable
s, или длинное значение.
Если вам нужно прервать транзакцию во время выполнения закрытия транзакции, вам нужно выбросить VoltAbortException
.
Также имейте в виду следующие рекомендации.
- определить ваш SQLStmt вне
transactOn
замыкания - использовать таблицы для сохранения любого состояния, которое должно существовать между вызовами процедур
Groovy Таблица читателей и строителей
Следующая процедура демонстрирует два дополнения, которые делают чтение и создание таблицы немного проще
CREATE PROCEDURE voter.procedures.ContestantWinningStates AS ### resultStmt = new SQLStmt(''' SELECT contestant_number, state, SUM(num_votes) AS num_votes FROM v_votes_by_contestant_number_state GROUP BY contestant_number, state ORDER BY 2 ASC, 3 DESC, 1 ASC; ''') transactOn = { int contestantNumber, int max -> voltQueueSQL(resultStmt) results = [] state = "" tuplerator(voltExecuteSQL()[0]).eachRow { isWinning = state != it[1] state = it[1] if (isWinning && it[0] == contestantNumber) { results << [state: state, votes: it[2]] } } if (max > results.size) max = results.size buildTable(state:STRING, num_votes:BIGINT) { results.sort { a,b -> b.votes - a.votes }[0..<max].each { row it.state, it.votes } } } ### LANGUAGE GROOVY;
tuplerator(VoltTable table)
возвращает Groovy-оболочку вокруг VoltTable. Метод eachRow принимает замыкание, которое вызывается для каждой строки в таблице. Доступ к значениям столбца можно легко получить по индексу столбца или имени столбца. В приведенном выше примере «это» является неявным параметром, передаваемым закрытию eachRow, и «он» обращается к первому значению столбца для строки с помощью метода it[0]
доступа. То же самое можно получить с помощью it['contestantNumber']
или более просто с it.contestantNumber
. Если вам необходимо получить доступ непосредственно к базовой таблице, вы можете сделать это, ссылаясь на его «планшетном» аксессоре: it.table.get(1,STRING)
. Доступны и другие методы rowAt(int rowNum)
, которые устанавливают курсор таблицы на указанную строку и reset()
сбрасывают курсор таблицы. Например
tuplerator(voltExecuteSQL()[0]).atRow(0)['state']
получает значение столбца состояния для первой строки.
buildTable (имя столбца: карта типов) позволяет легко создавать таблицы. Параметры метода:
- карта, где ключи — это имена столбцов, а значения — их соответствующие типы столбцов.
- замыкание, при котором вызовы строк добавляют строки в базовую таблицу
Приведенный выше код показывает таблицу с двумя столбцами (state и num_votes), в которую передаются значения из коллекции результатов.
Оба могут быть объединены следующим образом, где результаты одной таблицы обрабатываются и передаются во вновь созданную таблицу:
CREATE PROCEDURE voter.procedures.GetStateHeatmap AS ### resultStmt = new SQLStmt(''' SELECT contestant_number, state, SUM(num_votes) AS num_votes FROM v_votes_by_contestant_number_state GROUP BY contestant_number, state ORDER BY 2 ASC, 3 DESC, 1 ASC; ''') transactOn = { voltQueueSQL(resultStmt) state = "" buildTable( state:STRING, contestant_number:INTEGER, num_votes:BIGINT, is_winning:TINYINT ) { tuplerator(voltExecuteSQL()[0]).eachRow { byte isWinning = state != it.state ? (byte)1 : (byte)0 state = it.state row state, it.contestantNumber, it.numVotes, isWinning } } } ### LANGUAGE GROOVY;
Вышеприведенные выдержки из кода можно просмотреть, посетив пример DDL в нашем репозитории Github.
Процедуры Java все еще быстрее, чем процедуры Groovy
The syntactic conciseness that leverages the dynamic code interpretation capabilities of Groovy comes at a performance cost. Java should be your procedure implementation language choice if you really need to eek out as much performance as you can. But if you want something to get you started faster with VoltDB, and explore its features, and power, then Groovy procedures are a very good option.