2009-08-29 5 views
2

J'écris une application Grails qui utilisera principalement le springws web services plugin avec des points de terminaison soutenus par les services. Les services récupéreront des données à partir d'une variété de bases de données dorsales (c'est-à-dire, pas via des classes de domaine et GORM). Je voudrais stocker le sql que mes services utiliseront pour récupérer les données pour les services Web dans des fichiers externes. Je cherche des suggestions sur:Grails - stocker sql qui sera utilisé par les services

  1. Où est le meilleur endroit pour conserver les fichiers (par exemple, je voudrais les mettre quelque part évidente comme Grails-app/sql) et meilleur format (c.-à- xml, configslurper, etc.)

  2. La meilleure façon de résumer la récupération du texte sql afin que mes services qui exécuteront le sql n'auront pas besoin de savoir où et comment ils sont récupérés. Les services fourniront juste un sqlid et obtiendront le sql.

Répondre

5

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.

2

Avez-vous envisagé d'utiliser Grails GORM et une base de données HSQLDB pour stocker le SQL que vous voulez exécuter? Vous pourriez alors mettre dans un enregistrement pour chaque service contenant ces services SQL et le récupérer en utilisant les fonctions normales de Grails GORM. Vous pourriez générer un ensemble de contrôleurs et de vues par défaut qui vous permettraient d'éditer le SQL. Si vous souhaitez stocker le code SQL dans des fichiers externes, vous pouvez créer un sous-répertoire dans le répertoire Web-app appelé sql, puis stocker vos instructions SQL sous forme de fichiers texte. Vous pouvez créer une classe qui prendra un nom de service, charger le fichier texte associé contenant le SQL et retourner le contenu de ce fichier. Sans savoir à quel point votre SQL sera complexe je ne peux pas dire quel serait le meilleur format. Si vous traitez avec des instructions de sélection normales sans substitution de paramètre, le texte brut serait le meilleur. Si vous traitez avec SQL plus complexe avec des substitutions et des requêtes multiples, vous pouvez utiliser XML.

+0

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. –

Questions connexes