参数命名的重要性,记一次JDBC参数冲突

756 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情


Properties info = new Properties();
info.setProperty("user", "root");
info.setProperty("password", "850656");
info.setProperty("agentID", "1001");
info.setProperty("dbName", "mysql");
                
// 载入自定义的驱动
Class.forName("com.fanruan.jdbc.driver.MyDriver");
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", info);
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("select * from `student`");

如上,由于我重写了JDBC驱动,也就是上文的com.fanruan.jdbc.driver.MyDriver。 重写的效果大概是通过RPC调用客户端的JDBC执行相应操作(没有展示出来)。由于RPC调用的需要,在DriverManager.getConnection(String url, Properties info)中多封装了两个参数,agentIDdbName分别用于找到对应的客户端,和客户端对于收到的调用消息进行分发。测试运行时,在客户端显示如下:

Properties参数冲突.png

写的程序有bug我已经习惯了,但是令我费解的是,我明明在 url中指明了数据库为 test, 为何会报错说Table 'mysql.student' doesn't exist呢?

已知建立连接最终调用的是connect方法:

    public java.sql.Connection connect(String url, Properties info) throws SQLException {
        ...
    }
​

mysql的JDBC实现中,会对传入的 Properties 参数进行解析

public ConnectionImpl(HostInfo hostInfo) throws SQLException {
    ...
        this.database = hostInfo.getDatabase();
    ...
 public String getDatabase() {
     // 在 PropertyKey 中刚好有个叫 dbname 的键
        String database = this.hostProperties.get(PropertyKey.DBNAME.getKeyName());
        return isNullOrEmpty(database) ? "" : database;
    }

dbname键.png

导致本来已经被解析为testdatabase

originDataBase.png

被覆盖成了mysql导致了上面所说的错误。

finaldatabase.png

可以看到进入getConnectionURLInstance时,dbName还是驼峰命名。

被处理为connectionURL之后就变成了dbname,这也是上面覆盖database的前置条件。

connectionURL.png

至于为什么驼峰命名的变量被解析到全小写的变量里了(已知Properties大小写敏感),那是因为mysql驱动在解析映射DBNAME的时候,设置了大小写不敏感:

dbname.png