客串 java 开发:数据库访问的流程简化

    如果非 .net 相关技术不适宜发表在园子的首页,请告知我撤下该主题!

    我从事 asp/.net 开发有两年多了,其间还做过很多 winform 或 windows console 程序,这些只是表现形式;相关技术 ado.net,多线程,.net remoting 等等或多或少有所应用或研究。刚开始工作因为生活、兴趣,现在发展为一种人生哲学:试图在创造中找到生命存在的意义。难道果真如“许三多”说的:好好活就是做有意义的事,做有意义的事就是好好活?

    闲话少扯。最近有幸接触 java,早前我因受 .net 蛊惑,总把她当做异类,印象中这种语言工具书写繁琐、配置杂乱,让人无暇全身心关注业务逻辑,因此,除了对其本身诸多麻烦的恐惧,还有一种诡异的不屑。几个月前“邂逅”老牌艳星 c++,方知世间骚字怎解,悔恨带着有色眼镜看待开源。

    java 还算是个很简便的语言工具(我都不知道该把她当成一个语言,还是一个工具,看官们仁者见仁吧)。记得大学期间应用 jsp 搞过一个《医院管理系统》,当时建个小网站,链接数据库做点小操作,无不令人抓狂,现在看来,无非是当时的我们心高气傲,以为用 vs2003 拖个玩意点击“下一步”就显得很牛逼。自然,语言以及开发工具的易用程度上,java 干不过 .net,但从功能以及成本而言,后者还是很有优势的,风行那么多年的 j2ee,还是拥有相当的高端市场。

    曾经我写过一篇随笔,谈到 .net 环境下“如何简化数据库的访问操作”(http://www.cnblogs.com/howard-queen/archive/2009/07/14/1523500.html),今天我很惊诧,原来 java 也完全可以实现。通常,java 进行数据操作也是通过三个类 Connection(IDbConnection),Statement(IDbCommand),ResultSet(IDataReader),我将长期以来总结出的数据操作接口实现了一个不含参数的简化 java 版本(请同学们同时注意 java 与 c# 不同的命名规范):


package queen.data;
/*
 * 统一数据访问接口
 * 
 * @author Howard Queen
 * @version 1.0.1, 2010/10/12
 * */
public interface IExecutor {
    String getConnectionString();
    void setConnectionString(String value) throws Exception;
    int getTimeout();
    void setTimeout(int value);
    /*
     * 执行语句获取数据集
     * */
    QueryResult executeQuery(String statement) throws Exception;
    /*
     * 执行语句获取单个数据
     * */
    Object executeScale(String statement) throws Exception;
    /*
     * 执行语句获取影响的行数或其他。
     * */
    int executeNonQuery(String statement) throws Exception;
}

    为了便于在获取数据后集中释放非托管资源,我使用自定义的 QueryResult 类返回查询结果,而不是官方 ResultSet 。该类主要提供 close() 方法,其定义如下:


package queen.data;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/*
 * 数据返回类,便于集中释放相关非托管资源。
 * 
 * @author Howard Queen
 * @version 1.0.1, 2010/10/13
 * */
public final class QueryResult {
    
    private Connection _connection;
    private Statement _statement;
    private ResultSet _resultSet;
    
    public QueryResult(Connection connection, Statement statement, ResultSet resultSet){
        _connection = connection;
        _statement = statement;
        _resultSet = resultSet;
    }

    
    private Connection getConnection(){
        return _connection;
    }
    
    private Statement getStatement(){
        return _statement;
    }
    
    public ResultSet getResultSet(){
        return _resultSet;
    }
    
    public void close() throws SQLException{
        getResultSet().close();
        getStatement().close();
        getConnection().close();
    }
    
}

    同时,实现一个链接传统数据库的辅助类:


package queen.data;

import java.io.IOException;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.DriverManager;
import java.util.Properties;

/*
 * 数据库访问器
 * 
 * @author Howard Queen
 * @version 1.0.1, 2010/10/12
 * */
public final class DbExecutor implements IExecutor {
    
    static{
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private String _connectionString;
    private String _userName, _password;
    public String getConnectionString() {
        return _connectionString;
    }
    public void setConnectionString(String value) throws Exception {
        throw new Exception("请使用同名重载方法 setConnectionString(String connectionString, 
                                  String userName, String password) 设置链接参数!");
    }
    
    public void setConnection(String connectionString, String userName, String password){
        _connectionString = connectionString;
        _userName = userName;
        _password = password;
    }
    
    public void setConnectionFromProperties(String fileName, String connectionStringPropertyName, 
                String userNamePropertyName, String passwordPropertyName) throws IOException{
        Properties p = new Properties();
        p.load(DbExecutor.class.getResourceAsStream(fileName));
        String connectionString = p.getProperty(connectionStringPropertyName);
        String userName = p.getProperty(userNamePropertyName);
        String password = p.getProperty(passwordPropertyName);
        setConnection(connectionString, userName, password);
    }
    
    public String getUserName(){
        return _userName;
    }
    
    public String getPassword(){
        return _password;
    }
        
    private int _timeout;
    public int getTimeout() {
        return _timeout;
    }
    public void setTimeout(int value) {
        _timeout = value;
    }
    
    public int executeNonQuery(String statement) throws Exception{
        Connection con = null;
        Statement stm = null;
        try{
            con = DriverManager.getConnection(getConnectionString(), getUserName(), getPassword());
            stm = con.createStatement();
            return stm.executeUpdate(statement);
        }
        catch(Exception E){
            throw E;
        }
        finally{
            if(stm != null){
                stm.close();
            }
            if(con != null){
                con.close();
            }
        }
    }

    public QueryResult executeQuery(String statement) throws Exception {
        Connection con = DriverManager.getConnection(getConnectionString(), getUserName(), getPassword());
        Statement stm = con.createStatement();
        return new QueryResult(con, stm, stm.executeQuery(statement));
    }

    public Object executeScale(String statement) throws Exception {
        Connection con = null;
        Statement stm = null;
        ResultSet rs = null;
        try{
            con = DriverManager.getConnection(getConnectionString(), getUserName(), getPassword());
            stm = con.createStatement();
            rs = stm.executeQuery(statement);
            if(rs.next()){
                return rs.getObject(0);
            }
            return null;
        }
        catch(Exception E){
            throw E;
        }
        finally{        
            if(rs != null){
                rs.close();
            }
            if(stm != null){
                stm.close();
            }
            if(con != null){
                con.close();
            }
        }
    }
    
}

    这样一来,从前进行数据库操作繁琐的构造 Connection、Statement 以及 ResultSet 等均可以省略了。例子如下:


    public static void main(String[] args) throws Exception {
        DbExecutor b = new DbExecutor();
        b.setConnection("jdbc:mysql://databaseUrl:3306/dbName?useUnicode=true&characterEncoding=utf8", 
                "myusername", "mypassword");
        QueryResult r = b.executeQuery("SELECT Name FROM Users LIMIT 10");
        ResultSet s = r.getResultSet();
        while(s.next()){
            System.out.println(s.getString(1));
        }
        r.close();//需要手动释放
        int maxUseAge = b.executeScale("SELECT MAX(Age) FROM Users");//自动释放
    }

    考虑到一般数据库连接参数保存在配置文件中,DbExecutor 还特别提供从配置文件加载链接参数的方法:


   public void setConnectionFromProperties(String fileName, String connectionStringPropertyName, 
                String userNamePropertyName, String passwordPropertyName) throws IOException{...}

    哎,实在不知道该做点什么有意义的事,只好这样弄点残羹冷炙邀各位闲杂人等一起赏日(今天上海还是个阴天,日只出现了不到半小时)。但抛砖是为引玉,我知道园子里卧着华南虎、藏着史前龙,我所刻意追求的优雅编码,在很多东方求败看来不过是个儿戏;你们很多人身怀葵花宝典,却少有传阅,哎,斩不断的技术迷信,迟早要害得小年轻们色老颜衰,青春从此一日不复返!

    呵呵,碰了 java,人说话都糊里糊涂了,哈哈。兄弟们要守住这份贞操啊!

posted @   陛下  阅读(2067)  评论(21编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述
点击右上角即可分享
微信分享提示