Je travaillais sur un projet récemment où j'avais besoin de faire quelque chose de similaire. J'ai créé le répertoire suivant pour stocker les fichiers sql:
./grails-app/conf/sql
Par exemple il y a un fichier ./grails-app/conf/sql/hr/FIND_PERSON_BY_ID. sql qui a quelque chose comme ce qui suit:
select a.id
, a.first_name
, a.last_name
from person
where id = ?
J'ai créé un SqlCatalogService classe qui charge tous les fichiers dans ce répertoire (et les sous-répertoires) et stocker les noms de fichiers (moins l'extension) et le texte du fichier dans une carte. Le service a une méthode get (id) qui renvoie le texte SQL qui est mis en cache dans la carte. Étant donné que les fichiers/répertoires stockés dans Grails-app/conf sont placés dans le classpath, le SqlCatalogService utilise le code suivant pour lire les fichiers:
....
....
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]
}
Les services qui utilisent diverses sources de données utilisent SqlCatalogService pour récupérer le sql en appelant le get (id) méthode:
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
}
}
}
Pour l'instant nous avons seulement quelques instructions sQL afin stockez tout le texte dans une carte est pas un problème. Si vous avez beaucoup de fichiers sql à stocker, vous devrez peut-être penser à utiliser quelque chose comme Ehcache et définir une stratégie d'éviction (ie, utilisé le moins récemment ou le moins fréquemment utilisé) et stocker uniquement le disque le plus utilisé en mémoire. .
Avant cela, j'ai pensé à utiliser GORM et à stocker le texte sql dans la base de données.Mais nous avons décidé que le sql dans les fichiers rendait le développement plus facile car nous pouvions sauvegarder le sql directement depuis notre outil sql (en remplaçant les params de code dur par des points d'interrogation) et laisser notre système de contrôle de révision suivre changements. Je ne dis pas que le service ci-dessus est la manière la plus efficace ou la plus correcte de gérer cela, mais cela a fonctionné jusqu'à présent pour nos besoins.
Je voudrais +1 si j'avais assez de rep. J'avais envisagé d'utiliser GORM et de stocker le sql dans la base de données en utilisant une classe de domaine. Cependant, je pensais que le stockage dans les fichiers pourrait être la meilleure solution et me permettrait d'utiliser un système de contrôle de source pour garder l'historique des révisions. J'espérais avoir des nouvelles de quelqu'un qui aurait pu le faire par le passé, alors je veux lui donner quelques jours de plus avant d'accepter une réponse. Merci pour votre réponse. –