Grails - 存储将由服务使用的sql

时间:2009-08-29 23:39:48

标签: sql grails

我正在编写Grails应用程序,该应用程序主要使用springws web services plugin和服务支持的端点。这些服务将从各种后端数据库中检索数据(即,不通过域类和GORM)。我想存储我的服务将用于获取外部文件中的Web服务数据的sql。 我在寻找建议:

  1. 保存文件的最佳位置在哪里(也就是说,我想将它们放在像grails-app / sql这样明显的地方)和最佳格式(即xml,configslurper等)

  2. 抽象检索sql文本的最佳方法,这样我将执行sql的服务不需要知道它们的获取位置和方式。服务只提供一个sqlid并获取sql。

2 个答案:

答案 0 :(得分:5)

我最近正在开展一个项目,我需要做类似的事情。我创建了以下目录来存储sql文件:

<强> ./的grails-app / 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 类,它将加载该目录(和子目录)中的所有文件,并将文件名(减去扩展名)和文件文本存储在Map中。该服务有一个get(id)方法,它返回在Map中缓存的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通过调用get(id)方法来检索sql:

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语句,因此将所有文本存储在Map中不是问题。如果要存储大量的sql文件,则可能需要考虑使用Ehcache之类的东西并定义驱逐策略(即最近最少使用或最少使用),并且只将最常用的存储在内存中,并将其余部分保留在磁盘上直到需要

在此之前,我考虑过使用GORM并将sql文本存储在数据库中。但是决定在文件中使用sql使得开发更容易,因为我们几乎可以直接从我们的sql工具保存sql文件(用问号代替硬编码参数)并且能够让我们的修订控制系统跟踪变化。我不是说上述服务是处理这个问题的最有效或最正确的方法,但它迄今为止都符合我们的需求。

答案 1 :(得分:2)

您是否考虑过使用Grails GORM和HSQLDB数据库来存储您想要执行的SQL?然后,您可以为包含该服务SQL的每个服务放入一条记录,并使用正常的Grails GORM函数检索它。您可以生成一组默认的控制器和视图,以便您编辑SQL。如果要将SQL存储在外部文件中,可以在web-app目录中创建一个名为sql的子目录,然后将SQL语句存储为文本文件。您可以创建一个将获取服务名称的类,加载包含SQL的关联文本文件并返回该文件的内容。不知道你的SQL有多复杂,我不能说出最好的格式。如果你处理没有参数替换纯文本的普通select语句是最好的。如果您使用替换和多个查询处理更复杂的SQL,则可能需要使用XML。