如何在groovy中编写通用的Database util类?

时间:2014-09-02 09:55:18

标签: java groovy

我想在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中的代码段下方为我提供了每个

的列名
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
    }

它提供了地图列表。

1 个答案:

答案 0 :(得分:2)

我现在无法测试,但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属性来执行另一组查询。
  5. 这非常粗糙,因为我没有数据库来测试它,但它可能是这样的:

    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 }