【问题标题】:How to write a generic Database util class in groovy?如何在 groovy 中编写通用数据库实用程序类?
【发布时间】:2014-09-02 09:55:18
【问题描述】:

我想在 groovy 中编写一个 DB util 类,它采用一些强制性和可选的 db 参数并将结果作为映射列表返回。

Groovy 类

class DBUtil {

    private final String ORACLE="oracle"
    private final String DB2="db2"
    private final String SYBASE="sybase"
    private final String SQLSERVER="sqlserver"
    private final String MSSQLSERVER="mssqlserver"

    private final String ORACLE_DRIVER="jdbc:agra:oracle"
    private final String DB2_DRIVER="jdbc:agra:db2"
    private final String SQLSERVER_DRIVER="jdbc:agra:sqlserver"
    private final String SYBASE_DRIVER="jdbc:agra:sybase"

    private final String ORACLE_DRIVER_CLASS="com.agra.jdbc.oracle.OracleDriver"
    private final String DB2_DRIVER_CLASS="com.agra.jdbc.db2.DB2Driver"
    private final String SQLSERVER_DRIVER_CLASS="com.agra.jdbc.sqlserver.SQLServerDriver"
    private final String SYBASE_DRIVER_CLASS="com.agra.jdbc.sybase.SybaseDriver"

    private HashMap<String,String> dbparams
    private HashMap<String,String> sqlStatements

    private String url
    private String username
    private String password
    private String driver
    private String driverClass  

    public void setDbParams(HashMap<String,String> dbparams) {
        this.dbparams=dbparams  
    }

    DBUtil(dbparams, sqlStatements) {
        this.dbparams=dbparams
        this.sqlStatements=sqlStatements
    }

    private void validateDBParams() {
        if (dbparams != null) {
            try {
                if (dbparams?.containsKey("driver")) {
                    driver=dbparams?.get("driver")
                    driverClass=dbparams?.get("driverClass")
                }
                username=dbparams?.get("username")
                password=dbparams?.get("password")
                switch(dbparams?.get("dbtype")) {
                    case ORACLE:
                        if (!dbparams?.containsKey("driver")) {
                            driver=ORACLE_DRIVER
                            driverClass=ORACLE_DRIVER_CLASS
                        }
                        break
                    case DB2:
                        if (!dbparams?.containsKey("driver")) {
                            driver=DB2_DRIVER
                            driverClass=DB2_DRIVER_CLASS
                        }
                        break
                    case SYBASE:
                        if (!dbparams?.containsKey("driver")) {
                            driver=SYBASE_DRIVER
                            driverClass=SYBASE_DRIVER_CLASS
                        }
                        break
                    case SQLSERVER:
                    case MSSQLSERVER:
                        if (!dbparams?.containsKey("driver")) {
                            driver=SQLSERVER_DRIVER
                            driverClass=SQLSERVER_DRIVER_CLASS
                        }
                        break
                }
                url=driver+"://"+dbparams?.get("connectstring")
            } catch (Exception e) {
                e.printStackTrace()
            }
        }
    }

    public List<Map> execute() {
        List<Map> resultSet;
        def sql
        try {
            if (dbparams != null && sqlStatements != null) {
                validateDBParams()
                //println "$url, $username, $password, $driverClass"
                sql = Sql.newInstance(url, username, password, driverClass)
                sqlStatements.each {key, value->
                    List<Map> sqlResult = new ArrayList<Map>()
                    sql.eachRow(value) { row->
                        println row
                    }
                    //resultSet.add(sqlResult)
                    //println sqlResult                             
                }
            }
        }
        catch(SQLException se) {
            println "Exception encountered in DBUtil execute() $se"
        }
        return resultSet
    }

    static main(args) {

        HashMap<String,String> dbparams = ["dbtype":"oracle", "username":"johnkc", "password":"johnc", "connectstring":"apple:1521;SID=ORCL;",
                                            "driver":"jdbc:agra:oracle","driverClass":"com.agra.jdbc.oracle.OracleDriver"]
        HashMap<String,String> sqlStatements = ["sql1":"select name, value from v\$parameter",
                    "sql2":"select POO_NAME, POO_VALUE from PO_OPTION"]
        DBUtil db = new DBUtil(dbparams, sqlStatements)
        db.execute()
    }

}

执行后它给我下面的结果(键可以超过 2 个)

[NAME:lock_name_space, VALUE:[null]]
[NAME:processes, VALUE:1000]
[NAME:sessions, VALUE:1105]
[POO_NAME:username, POO_VALUE:com.agra.jdbc.base.BaseClob@256ef705]
[POO_NAME:jdbcurl, POO_VALUE:com.agra.jdbc.base.BaseClob@181b7c76]
[POO_NAME:dbType, POO_VALUE:com.agra.jdbc.base.BaseClob@34883357]
[POO_NAME:ConnectionString, POO_VALUE:com.agra.jdbc.base.BaseClob@59e2afb2]

如何以以下格式(地图列表)放置在输出上方?

[   "sql1": [ {row1}, {row2}... ],
    "sql2": [ {row1}, {row2}... ],
    ...
]

其中 row1... = {column1:value1, column2:value2, column3:value3...}

更新

sqlStatements.each 内的 sn-p 下面给出了每个列的名称

def tableColumns=[:]
                sql.rows(value, {meta ->
                    def columns=[]
                    int colCount=meta.columnCount
                    (1..colCount).each{
                        columns.add(meta.getColumnName(it))
                    }
                    tableColumns.put(key, columns)
                })

更新我的解决方案

public List<Map> execute() {
        List<Map<String,Object>> resultSet=new ArrayList<HashMap<String,Object>>()      
        def sql
        try {
            if (dbparams != null && sqlStatements != null) {
                boolean validParams=validateDBParams()
                if (validParams) {
                    sql = Sql.newInstance(url, username, password, driverClass)
                    sqlStatements.each {key, value->
                        def sqlResultMap=[:]
                        def tableColumns=[:]
                        sql.rows(value, {meta ->
                            def columns=[]
                            int colCount=meta.columnCount
                            (1..colCount).each{
                                columns.add(meta.getColumnName(it))
                            }
                            tableColumns.put(key, columns)
                        })
                        def rows=[]
                        sql.eachRow(value) {row->
                            def dbrow=[:]
                            tableColumns.get(key).each{ columnname->
                                dbrow.put(columnname, row."$columnname")
                            }
                            rows.add(dbrow)
                        }
                        sqlResultMap.put(key, rows)
                        resultSet.add(sqlResultMap)
                    }
                }
            }
        }
        catch(SQLException se) {
            println "Exception encountered in DBUtil execute() $se"
        }
        return resultSet
    }

它给出了一个地图列表。

【问题讨论】:

    标签: java groovy


    【解决方案1】:

    我现在不能测试这个,但是 IIRC 你可以做这样的事情:

    Map<String, List> resultSets = [:]
    
    ...
    
    sqlStatements.each { queryAlias, query ->
    
        def columns=[]
        sql.eachRow(query) { row ->
            if (columns.isEmpty()) {
                int colCount = row.columnCount
                columns = (1..colCount).collect { row.getColumnName it }
            }
    
            resultSets[queryAlias] = columns.collect { column -> 
                row.getColumn(column) 
            }
        }
    }
    

    更新:我几乎可以肯定,您可以简单地执行 row as Map 并从结果列表中获取地图,而无需获取每个列名。


    不相关,但我想就该类建模提出一些建议:

    1. 在类上声明的所有这些常量都是不相关的,提供了一个过程代码,最好将它们中的每一个重构到自己的类中。每个子类都可以处理每个数据库的特殊性,尽管这个例子没有显示任何(我也不记得任何一个);
    2. 工厂方法会很酷,也可以进行验证;
    3. 处理每种数据库类型的枚举;
    4. execute() 可以接收它应该执行的 SQL,因此您无需设置 sqlStatements 属性即可执行另一组查询。

    这很粗糙,因为我没有数据库来测试它,但它可能是这样的:

    abstract class Database {
      enum Type { ORACLE, POSTGRES }
    
      String url
      String username
      String password
      abstract def getJdbc()
      abstract def getDriver()  
    
      static Database create(Database.Type type, Map params) {
        def db = [
          (Type.ORACLE)   : OracleDatabase, 
          (Type.POSTGRES) : PostgresDatabase
        ][type].newInstance() 
    
        assert (db.username = params.username), "No username given"
        assert (db.password = params.password), "No password given"
        assert (db.url = params.url), "No database URL given" 
    
        return db
      }
    
      Map<String, List> execute(sqlStatements) {
        try {
          Map<String, List> resultSets = [:]
    
          assert sqlStatements != null 
    
          def sql = groovy.sql.Sql.newInstance(url, username, password, driver)
    
          sqlStatements.each { queryAlias, query ->
    
            def columns=[]
            sql.eachRow(query) { row ->
              if (columns.isEmpty()) {
                int colCount = row.columnCount
                columns = (1..colCount).collect { row.getColumnName it }
              }
    
              resultSets[queryAlias] = columns.collect { column -> row.getColumn(column) }
            }
          }
          return resultSet
        }
        catch(se) {
          println "Exception encountered in DBUtil execute() $se"
          throw se
        }
      }
    
    }
    
    class OracleDatabase extends Database {
      def getJdbc() { "jdbc:agra:oracle" }
      def getDriver() { "com.agra.jdbc.oracle.OracleDriver" }
    }
    
    class PostgresDatabase extends Database {
      def getJdbc() { "jdbc:agra:mysql" }
      def getDriver() { "org.postgresql.Driver" }
    }
    
    
    def dbparams = [
      "username":"johnkc", 
      "password":"johnc", 
      "url":"apple:1521;SID=ORCL;"
    ]
    
    def sqlStatements = [
      "sql1":"select name, value from v\$parameter",
      "sql2":"select POO_NAME, POO_VALUE from PO_OPTION"
    ]
    
    def db = Database.create(Database.Type.ORACLE, dbparams)
    
    def result = db.execute(sqlStatements)
    assert result instanceof Map
    assert result.keySet().size() == 2
    assert result.each { key, value -> value instanceof List }
    

    【讨论】:

    • 感谢您的回答和对重构的建议 +1。我还需要返回类型为 List of maps List&lt;Map&gt;
    猜你喜欢
    • 1970-01-01
    • 2012-10-19
    • 2015-08-12
    • 1970-01-01
    • 2015-01-22
    • 1970-01-01
    • 2011-03-03
    • 1970-01-01
    相关资源
    最近更新 更多