近期项目组要把oracle数据库迁移改造成mysql数据库,同时也涉及到了后台java代码的改造,因此在迁移过程中遇到了各种坑。
今天讲述一个java代码开发过程中,因为mysql-jdbc驱动包中DatabaseMetaDataUsingInfoSchema类的某个方法导致的表名映射错误。
表命名时常常会使用下划线来分隔,比如普通表名以t_开头,表示为table,命名规则为t_模块名(或有意义的简写)_+table_name。在java代码开发过程中,有些业务需要去数据字典中查询相应的表名,然后在进行业务处理。但是在sql语句中下划线 ’_’ 表示一个占位符,因此采用上述命名规则的表名,如果作为字段中的某个值,在进行like模糊查询时,可能就会匹配出多个表名,进而造成后台java代码业务逻辑处理报错。
具体示例:
需求是:查看ha_test数据库中的t_1表,结果是同时查出t_1 和t11 两个表
mysql> create table t_1(id int);
Query OK, 0 rows affected (0.09 sec)
mysql> create table t11(name varchar(32));
Query OK, 0 rows affected (0.06 sec)
mysql> SELECT
-> table_name,
-> TABLE_SCHEMA
-> FROM
-> information_schema.`TABLES` d
-> WHERE
-> d.TABLE_SCHEMA LIKE 'ha_test'
-> AND d.TABLE_NAME LIKE 't_1';
+------------+--------------+
| table_name | TABLE_SCHEMA |
+------------+--------------+
| t11 | ha_test |
| t_1 | ha_test |
+------------+--------------+
2 rows in set (0.00 sec)
而mysql-jdbc包中DatabaseMetaDataUsingInfoSchema 类中的某个方法代码中存在
WHERE TABLE_SCHEMA LIKE ? AND TABLE_NAME LIKE ? 语句,一旦表的命名规则中有下划线’_’就有可能查询出多个表,造成后续业务逻辑处理出现错误。
public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException {
if (catalog == null) {
if (this.conn.getNullCatalogMeansCurrent()) {
catalog = this.database;
}
}
……
sqlBuf.append(MysqlIO.getMaxBuf() + " AS BUFFER_LENGTH,NUMERIC_SCALE AS DECIMAL_DIGITS, "
+ Integer.toString(java.sql.DatabaseMetaData.versionColumnNotPseudo) + " AS PSEUDO_COLUMN FROM INFORMATION_SCHEMA.COLUMNS "
+ "WHERE TABLE_SCHEMA LIKE ? AND TABLE_NAME LIKE ? AND EXTRA LIKE '%on update CURRENT_TIMESTAMP%'");
public java.sql.ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException {
if (catalog == null) {
if (this.conn.getNullCatalogMeansCurrent()) {
catalog = this.database;
}
}
……
String sql = "SELECT TABLE_SCHEMA AS TABLE_CAT, NULL AS TABLE_SCHEM, TABLE_NAME, "
+ "COLUMN_NAME, SEQ_IN_INDEX AS KEY_SEQ, 'PRIMARY' AS PK_NAME FROM INFORMATION_SCHEMA.STATISTICS "
+ "WHERE TABLE_SCHEMA LIKE ? AND TABLE_NAME LIKE ? AND INDEX_NAME='PRIMARY' ORDER BY TABLE_SCHEMA, TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX";
解决方法:
由于开发必须要调用到DatabaseMetaDataUsingInfoSchema这个类的某个方法,因此只能修改表名