Grails - магазин sql, который будет использоваться сервисами - PullRequest
2 голосов
/ 30 августа 2009

Я пишу приложение Grails, которое в основном будет использовать плагин для веб-сервисов springws с конечными точками, поддерживаемыми сервисами. Службы будут извлекать данные из различных внутренних баз данных (т. Е. Не через доменные классы и GORM). Я хотел бы сохранить sql, который мои службы будут использовать для извлечения данных для веб-служб во внешних файлах. Я ищу предложения по:

  1. Где лучше всего хранить файлы (т. Е. Я бы хотел разместить их где-нибудь очевидно, например, в grails-app / sql) и лучший формат (т. Е. Xml, configslurper и т. Д.)

  2. Лучший способ абстрагировать получение текста sql, поэтому моим службам, которые будут выполнять sql, не нужно будет знать, где и как они выбираются. Сервисы просто предоставят sqlid и получат sql.

Ответы [ 2 ]

5 голосов
/ 05 сентября 2009

Я недавно работал над проектом, где мне нужно было сделать что-то подобное. Я создал следующий каталог для хранения файлов sql:

. / Grails-приложение / CONF / SQL

Например, есть файл ./grails-app/conf/sql/hr/FIND_PERSON_BY_ID.sql, в котором есть что-то вроде следующего:

select a.id
, a.first_name
, a.last_name 
from person 
where id = ?

Я создал класс SqlCatalogService , который загружал бы все файлы в этом каталоге (и подкаталогах) и сохранял имена файлов (без расширения) и текст файла на карте. У сервиса есть метод get (id), который возвращает текст sql, который кэшируется на карте. Поскольку файлы / каталоги, хранящиеся в grails-app / conf, помещаются в путь к классам, SqlCatalogService использует следующий код для чтения в файлах:

....
....
Map<String,String> sqlCache = [:]
....
....
void loadSqlCache() {
    try {
        loadSqlCacheFromDirectory(new File(this.class.getResource("/sql/").getFile()))
    } catch (Exception ex) {
        log.error(ex)
    }       
}

void loadSqlCacheFromDirectory(File directory) {
    log.info "Loading SQL cache from disk using base directory ${directory.name}"
    synchronized(sqlCache) {
        if(sqlCache.size() == 0) {
            try {  
                directory.eachFileRecurse { sqlFile ->
                    if(sqlFile.isFile() && sqlFile.name.toUpperCase().endsWith(".SQL")) {
                        def sqlKey = sqlFile.name.toUpperCase()[0..-5]
                        sqlCache[sqlKey] = sqlFile.text
                        log.debug "added SQL [${sqlKey}] to cache"
                    }
                }                                   
            } catch (Exception ex) {
                log.error(ex)
            }       
        } else {
            log.warn "request to load sql cache and cache not empty: size [${sqlCache.size()}]"
        }
    }
}

String get(String sqlId) {
    def sqlKey = sqlId?.toUpperCase()
    log.debug "SQL Id requested: ${sqlKey}"
    if(!sqlCache[sqlKey]) {
        log.debug "SQL [${sqlKey}] not found in cache, loading cache from disk"
        loadSqlCache()
    }
    return sqlCache[sqlKey]
}

Сервисы, использующие различные источники данных, используют SqlCatalogService для извлечения sql путем вызова метода get (id):

class PersonService {

    def hrDataSource
    def sqlCatalogService

    private static final String SQL_FIND_PERSON_BY_ID = "FIND_PERSON_BY_ID"

    Person findPersonById(String personId) {
        try {
            def sql = new groovy.sql.Sql(hrDataSource)
            def row = sql.firstRow(sqlCatalogService.get(SQL_FIND_PERSON_BY_ID), [personId])
            row ? new Person(row) : null
        } catch (Exception ex) {
            log.error ex.message, ex
            throw ex
        }
    }
}

Пока у нас есть только несколько SQL-операторов, поэтому сохранение всего текста на карте не является проблемой. Если вы храните много файлов sql, вам, возможно, придется подумать об использовании чего-то вроде Ehcache и определении стратегии выселения (т. Е. Наименее недавно использованной или наименее часто используемой) и хранении только наиболее используемой в памяти и оставляющей оставшуюся часть на диске до тех пор, пока она не понадобится. .

Перед этим я подумал об использовании GORM и сохранении текста sql в базе данных. Но решил, что с использованием sql в файлах стало легче разрабатывать, поскольку мы могли в значительной степени сохранить sql в файл непосредственно из нашего инструмента sql (заменяя параметры жесткого кода на вопросительные знаки) и могли позволить нашей системе контроля версий отслеживать изменения. Я не говорю, что вышеуказанный сервис - самый эффективный или правильный способ справиться с этим, но до сих пор он работал для наших нужд.

2 голосов
/ 30 августа 2009

Рассматривали ли вы использование Grails GORM и базы данных HSQLDB для хранения SQL, который вы хотите выполнить? Затем вы можете поместить запись для каждого сервиса, содержащего этот сервис SQL, и извлечь его, используя обычные функции Grails GORM. Вы можете создать набор контроллеров и представлений по умолчанию, которые позволят вам редактировать SQL. Если вы хотите сохранить SQL во внешних файлах, вы можете создать в каталоге веб-приложения подкаталог sql, а затем сохранить операторы SQL в виде текстовых файлов. Вы можете создать класс, который будет принимать имя службы, загрузить связанный текстовый файл, содержащий SQL, и вернуть содержимое этого файла. Не зная, насколько сложным будет ваш SQL, я не могу сказать, какой будет лучший формат. Если вы имеете дело с обычными операторами выбора без подстановки параметров, лучше всего использовать обычный текст. Если вы имеете дело с более сложным SQL с подстановками и несколькими запросами, вы можете использовать XML.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...