不夸张的说,Groovy 在使用 JDBC 对数据库的操作上是简化到了极致。Groovy 中的 SQL 支持在 groovy.sql 包中,而其中最耀眼的明星就数 groovy.sql.Sql 了。
现在我们就来体验一下 GroovySQL 给我们带来的快感。这里所用的示例数据库是 derbyDB, JDK 1.6 中附带了这个数据库(叫做 JavaDB),MyEclipse 6.X 也带了 DerbyDB。假设我们把它安装在 C:\Java\JavaDB,那么在 C:\Java\JavaDB\demo\databases 下有一个 toursdb(目录) 数据库。我们就用这个,当然你可以使用你手边已有的或最拿手的数据库。
我们将以嵌入方式(文件形式) 来使用 toursdb,所以你需要把驱动包 derby.jar 加到 classpath 中。toursdb 中有一个表是:
CITIES(CITY_ID,CITY_NAME,COUNTRY,AIRPORT,LANGUAGE,COUNTRY_ISO); //CITY_ID,COUNTRY_ISO 是数字,其他它段为字符串类型
要查询 CITIES 表,并输出记录的 Groovy 代码如下:
1 2 3 4 5 6 7 8 9 |
import groovy.sql.Sql; url = "jdbc:derby:C:/Java/JavaDB/demo/databases/toursdb;create=false"; sql = Sql.newInstance(url,"org.apache.derby.jdbc.EmbeddedDriver"); //调用的方法原型是:eachRow(String sql, Closure closure),留心一下参数传递的写法 sql.eachRow ("select * from cities where city_id<=5") { row-> println "ID:${row[0]}, Name:${row.city_name}"; //可用索引也可以用字段名 } |
上面的代码很容易理解,不需要多加解释。
脚本语的优势也是其易让人倍感迷乱的地方就是做一件事情的方式过于多样性。就如为创建上面那个 Sql 实例,Sql 提供了六个 newInstance() 工厂方法,三个 Sql() 构造方法。具体参见 http://groovy.codehaus.org/gapi/ 的 groovy.sql.Sql(http://groovy.codehaus.org/gapi/groovy/sql/Sql.html) 部份。
下面看看 Sql 实例的各种创建方式,伪代码表示,要替换成实际的参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
sql1 = Sql.newInstance(url,driver); sql2 = Sql.newInstance(url,user,pass,driver); Properties props = new Properties(); props.put("username","Unmi"); props.put("password",""); sql3 = Sql.newInstance(url,props,driver) //如果事先用 loadDriver() 加载了驱动 Sql.loadDriver(driver); //相当于 DriverManager.registerDriver(Driver) //那么前面的 sql1, sql2, sql3 在 newInstance() 时就可以省去最后那个 driver 参数 //此外还可以使用已有连接 sql4 = new Sql(connection); //或利用 Datasource 来创建 Sql 实例,这种方式在容器很有用 InitialContext ctx = new InitialContext(); DataSource ds = (DataSource) ctx.lookup("jdbc/derbyDB"); sql5 = new Sql(ds); |
三重引号字符串批量执行 SQL 语句
1 2 3 4 |
sql.execute ''' DELETE FROM cities where 1<>1; DELETE FROM cities where 1<>1; ''' |
批量执行分号分隔开来的多行语句,本来为不损坏 toursdb 库中原有的记录,作了一个消极删除操作。可是 derbyDB 的这个驱动不支持执行分号分隔的语句,可以换个别的数据库来试验一下。
使用 GString 查询参数,如:
1 2 3 4 5 |
param = 5; sql.eachRow ("select * from cities where city_id<=${param}") { println "ID:${it[0]}, Name:${it.city_name}"; } |
使用 List 查询参数,如:
1 2 3 4 5 |
params = [5,10]; sql.eachRow ("select * from cities where city_id between ? and ?", params) { println "ID:${it[0]}, Name:${it.city_name}"; } |
传入的参数由左至右依次分配给每个 ? 问号。这种方式能促使 Sql 语句预编译,可防止 SQL 注入攻击。
executeUpdate(),更新、删除或插入操作
1 2 3 4 5 |
new File("foo.csv").splitEachLine(",") { params -> result = sql.executeUpdate("INSERT INTO cities(CITY_ID,CITY_NAME,\ COUNTRY,COUNTRY_ISO_CODE) values(?,?,?,?)",params); println "${result} line has been added."; } |
foo.csv 文件的内容如下:
88,ShenZhen,China,CN
89,Ji'an,China,CN
executeUpdate() 返回受影响的行数,每次 insert 只影会一行,所以执行后控制台输出为:
1 lines has been added
1 lines has been added
execute(),可用来执行所有的 Sql 语句。它用来执行更新、删除或插入语句后,可用 sql.getUpdateCount() 得到受影响的行数。可惜的是执行查询时没法直接获得查得记录的行数。
最后,对 GroovySQL 使用的延伸还是必须去看 groovy.sql.Sql 的 API 说明(http://groovy.codehaus.org/gapi/groovy/sql/Sql.html),还需去关注其他一些方法如:
executeInsert()、firstRow()、query()、queryEach()、rows()、等各方法的使用,还有 GroovySQL 是如何处理 Blob 类型的。
参考:1. 《Java 脚本编程语言、框架与模式》第 5 章
2. 《Groovy in Action》(2007.1) 第 10 章,Database programming with Groovy
本文链接 https://yanbin.blog/unmi-study-groovy-database1/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
三重引号字符串批量执行 SQL 语句,这个我试过Oracle也不支持多行分号分隔的SQL