携手创作,共同成长!这是我参与「掘金日新计划 · 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)
中多封装了两个参数,agentID
和dbName
分别用于找到对应的客户端,和客户端对于收到的调用消息进行分发。测试运行时,在客户端显示如下:
写的程序有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;
}
导致本来已经被解析为test
的database
:
被覆盖成了mysql
导致了上面所说的错误。
可以看到进入getConnectionURLInstance
时,dbName
还是驼峰命名。
被处理为connectionURL
之后就变成了dbname
,这也是上面覆盖database
的前置条件。
至于为什么驼峰命名的变量被解析到全小写的变量里了(已知Properties大小写敏感),那是因为mysql驱动在解析映射DBNAME的时候,设置了大小写不敏感: