业内流行这么一句话:"三流公司卖产品;二流公司卖服务;一流公司卖标准."
标准就是规范,所以开发中,最难的不是具体功能的实现,而是制定一个开发规范,大家共同去遵守.废话不说了,直接进入正题^-^
一 介绍
commons是apache旗下一个著名的开源项目.他提供了很多方便使用的工具类.今天之所以把标题命名为,是因为相对于方便的工具来说,commons-dbutils的更大意义在于JDBC的开发规范.这样增强了代码的可读性和维护性.本文的出发点也是从规范说起,捎带着一些常用的方法.
commons-dbutils是一个轻量级的JDBC开发框架.里面只是一些非常简单的封装.下面笔者先介绍几个常用的类和接口.
1)org.apache.commons.dbutils.DbUtils.java
这个类提供了数据库初始化和关闭相关的初始操作.包括资源的开关,驱动的加载.事务回滚等常用操作。
public static void closeQuietly(Connection conn, Statement stmt,
ResultSet rs) {
try {
closeQuietly(rs);
} finally {
try {
closeQuietly(stmt);
} finally {
closeQuietly(conn);
}
}
}
这个方法,提供了对Connection,Statement/PrepareStatement,ResultSet的关闭操作.只需要一行代码,就可以安全的关闭.其中具体的细节,大家可以更深入的阅读源代码.
public static void commitAndClose(Connection conn) throws SQLException {
if (conn != null) {
try {
conn.commit();
} finally {
conn.close();
}
}
}
这个接口是先提交,后关闭.
2)org.apache.commons.dbutils.QueryRunner.java
- Object[][] params = new Object[vars.size()][5];
- Var var = new Var();
- int count = 0;
- String sql = "";
- count = vars.size();
- // 组装参数
- for (int i = 0; i < count; i++) {
- var = vars.get(i);
- params[i][0] = var.getDate_Time();
- params[i][1] = var.getId();
- params[i][2] = var.getValue_t();
- params[i][3] = var.getDate_Time();
- params[i][4] = var.getId();
- }
- // 执行批处理
- sql = "insert into vardata(time,name,data) select ?,?,? from dual where not exists (select * from vardata where time=? and name=?)";
- run.batch(sql, params);
上面是一个批处理的例子,这个类提供了相当强大的查询功能,可以类似ORM一样,使用查询.
二 项目应用
1)背景:本人正在从事的项目中,有个数据采集的功能.在SQL SERVER 2005中,只存在1个表,表中有2个字段.这个表只有185条纪录.每天纪录代表一个变量.2个字段分别为name,value.想必读者一看就能明白字段的含义.为了保证硬件设备WINCC的性能,所以他不会把数据累积到SQL
SERVER 2005中,而只是刷新185条记录.所以数据库中,永远只有185条数据.因此我们需要实现个功能,每5秒钟到SQL SERVER 2005中,拿到全部数据,保存在一个可以累积历史数据的库中来.本项目中,我们选择MySQL5.1.49,通过对时间字段分区,实现了大量数据高性能的需求.下面笔者只演示commons-dbutils相关的部分,其中MySQL的数据库结构,也被笔者简化.
2)环境:
数据库:
MySQL 5.1.49
JDK环境:
6.0.21
数据源:
commons-dbcp
commons-pool
3)数据库:
- CREATE DATABASE `test`;
- CREATE TABLE `icerecord` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `value_t` float(10,5) DEFAULT '0.00000',
- `Date_Time` varchar(50) DEFAULT '',
- PRIMARY KEY (`id`)
- ) ;
- INSERT INTO `icerecord` VALUES (1,100,'2010-07-31');
- INSERT INTO `icerecord` VALUES (2,200,'2010-07-30');
- INSERT INTO `icerecord` VALUES (3,300,'2010-07-29');
- INSERT INTO `icerecord` VALUES (4,400,'2010-07-28');
- INSERT INTO `icerecord` VALUES (5,500,'2010-07-27');
- INSERT INTO `icerecord` VALUES (6,600,'2010-07-26');
4)代码
DBBase类中演示了如何通过commons-dbutils来操纵数据源.其中应用了类似ORM的思想.List vars = DBBase.getInstance().queryForOList(sql, null, Var.class);这行代码使用时需要注意:
1)Var与数据库中的表icerecord是映射关系,但名字不需要一样;
2)Var中的属性和类型,要与数据库中的字段类型保持一致;
3)Var中的属性要用标准的getter和setter.
具备了上述3个条件,调用queryForOList方法后,commons-dbutils会自动将查询结果进行封装成List.
笔者也进行了对比实验,使用commons-dbutils封装对象,比自行getter&setter的效率高出20倍.传统方法查询后(185条记录)自行封装,需要370毫秒,而使用commons,仅需要23毫秒.
下面也包含了Var类.所有代码经过本人亲自运行测试.希望对大家有所帮助.
- package test.common.db;
- import java.sql.SQLException;
- import java.util.List;
- import javax.sql.DataSource;
- import org.apache.commons.dbcp.BasicDataSource;
- import org.apache.commons.dbutils.QueryRunner;
- import org.apache.commons.dbutils.handlers.BeanHandler;
- import org.apache.commons.dbutils.handlers.BeanListHandler;
- import org.apache.commons.dbutils.handlers.ScalarHandler;
- public class DBBase {
- private static DBBase dbBase;
- private static QueryRunner run;
- private DataSource dataSource;
- public DataSource getDataSource() {
- return dataSource;
- }
- public void setDataSource(DataSource dataSource) {
- this.dataSource = dataSource;
- }
- private DBBase() {
- }
- private void init() {
- dbBase = this;
- run = new QueryRunner(dataSource);
- }
- public static DBBase getInstance() {
- return dbBase;
- }
- /**
- * eg: select count(1) from user
- *
- * @param sql
- * @param params
- * @return
- */
- public int count(String sql, Object[] params) {
- Object o = getAnAttr(sql, params);
- if (o instanceof Integer) {
- return (Integer) o;
- }
- if (o instanceof Long) {
- Long l = (Long) o;
- return l.intValue();
- }
- String s = (String) o;
- try {
- return Integer.parseInt(s);
- } catch (NumberFormatException e) {
- return 0;
- }
- }
- /**
- * 获得第一个查询第一行第一列
- *
- * @param sql
- * @param params
- * @return
- */
- public Object getAnAttr(String sql, Object[] params) {
- showSql(sql);
- Object s = null;
- try {
- s = run.query(sql, new ScalarHandler(1), params);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return s;
- }
- /**
- * 查询返回单个对象
- *
- * @param sql
- * @param clazz
- * @return
- */
- public T queryForObject(String sql, Object param[], Class clazz) {
- T obj = null;
- try {
- showSql(sql);
- obj = (T) run.query(sql, new BeanHandler(clazz), param);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return obj;
- }
- /**
- * 查询返回list对象
- *
- * @param sql
- * @param clazz
- * @return
- */
- public List queryForOList(String sql, Object[] param, Class clazz) {
- List obj = null;
- try {
- showSql(sql);
- obj = (List) run.query(sql, new BeanListHandler(clazz), param);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return obj;
- }
- /**
- * 保存返回主键
- *
- * @param sql
- * @param param
- * @return
- */
- public int storeInfoAndGetGeneratedKey(String sql, Object[] param) {
- int pk = 0;
- try {
- showSql(sql);
- run.update(sql, param);
- pk = ((Long) run.query("SELECT LAST_INSERT_ID()", new ScalarHandler(1))).intValue();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return pk;
- }
- /**
- * 更新
- *
- * @param sql
- * @return
- */
- public int update(String sql, Object[] param) {
- int i = 0;
- try {
- showSql(sql);
- i = run.update(sql, param);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return i;
- }
- private void showSql(String sql) {
- System.out.println(sql);
- }
- public static void main(String[] args) {
- DataSource ds = setupDataSource();
- DBBase db = new DBBase();
- db.setDataSource(ds);
- db.init();
- // 聚合函数查询结果
- String sql = "select count(*) from IceRecord";
- int result1 = db.count(sql, null);
- System.out.println("聚合函数查询结果:" + result1);
- // 通过List封装
- sql = "select * from IceRecord";
- List vars = DBBase.getInstance().queryForOList(sql, null, Var.class);
- for (Var var : vars) {
- System.out.println("通过List封装:" + var.getId() + " " + var.getValue_t() + " " + var.getDate_Time());
- }
- // 插入数据
- sql = "insert into IceRecord(value_t) values(?)";
- int pk = DBBase.getInstance().storeInfoAndGetGeneratedKey(sql, new Object[] { 1 });
- System.out.println("/插入数据:" + pk);
- // 按条件查询数据
- sql = "select Date_Time from IceRecord where id =?";
- String result2 = (String) DBBase.getInstance().getAnAttr(sql, new Object[] { 1 });
- System.out.println("按条件查询数据:" + result2);
- }
- // 初始化数据源
- private static DataSource setupDataSource() {
- BasicDataSource ds = new BasicDataSource();
- ds.setDriverClassName("com.mysql.jdbc.Driver");
- ds.setUsername("root");
- ds.setPassword("147258369");
- ds.setUrl("jdbc:mysql://127.0.0.1:3306/test");
- return ds;
- }
- /*
- 运行结果:
- select count(*) from IceRecord
- 聚合函数查询结果:7
- select * from IceRecord
- 通过List封装:1 100.0 2010-07-31
- 通过List封装:2 200.0 2010-07-30
- 通过List封装:3 300.0 2010-07-29
- 通过List封装:4 400.0 2010-07-28
- 通过List封装:5 500.0 2010-07-27
- 通过List封装:6 600.0 2010-07-26
- 通过List封装:7 1.0
- insert into IceRecord(value_t) values(?)
- /插入数据:8
- select Date_Time from IceRecord where id =?
- 按条件查询数据:2010-07-31
- */
- }
- package test.common.db;
- public class Var {
- private int id;
- private float value_t;
- private String Date_Time;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public float getValue_t() {
- return value_t;
- }
- public void setValue_t(float valueT) {
- value_t = valueT;
- }
- public String getDate_Time() {
- return Date_Time;
- }
- public void setDate_Time(String dateTime) {
- Date_Time = dateTime;
- }
- }
总结,这是一个轻量级架构,功能肯定没有JPA和Hibernate强大,仅适用于JDBC编写的应用.同时他更重要的意义是规范.请读者们根据具体项目,选择最适合项目框架进行应用.而不要生搬硬套本代码到那些不适合commons-dbutils的项目中.^-^