【发布时间】:2011-02-25 22:23:47
【问题描述】:
我有一个嵌入了数据库的桌面应用程序。当我执行我的程序时,我需要检查特定表是否存在,如果不存在则创建它。
如果我的数据库有一个名为 conn 的 Connection 对象,我该如何检查呢?
【问题讨论】:
-
请在您的问题中更具体。
我有一个嵌入了数据库的桌面应用程序。当我执行我的程序时,我需要检查特定表是否存在,如果不存在则创建它。
如果我的数据库有一个名为 conn 的 Connection 对象,我该如何检查呢?
【问题讨论】:
DatabaseMetaData dbm = con.getMetaData();
// check if "employee" table is there
ResultSet tables = dbm.getTables(null, null, "employee", null);
if (tables.next()) {
// Table exists
}
else {
// Table does not exist
}
【讨论】:
您可以使用可用的元数据:
DatabaseMetaData meta = con.getMetaData();
ResultSet res = meta.getTables(null, null, "My_Table_Name",
new String[] {"TABLE"});
while (res.next()) {
System.out.println(
" "+res.getString("TABLE_CAT")
+ ", "+res.getString("TABLE_SCHEM")
+ ", "+res.getString("TABLE_NAME")
+ ", "+res.getString("TABLE_TYPE")
+ ", "+res.getString("REMARKS"));
}
请参阅here 了解更多详情。还要注意the JavaDoc 中的注意事项。
【讨论】:
getTables() 方法的第三个参数!!! (而不是像你一样使用'null')
meta.getTables("Schema_Name", null, "My_Table_Name", new String[] {"TABLE"})
Note: Some databases may not return information for all tables. 除非您知道您的供应商确实完全支持它,否则很难依赖它。
我实际上并没有发现这里提供的任何解决方案是完全完整的,所以我将添加我自己的解决方案。这里没有什么新鲜事。您可以从其他提供的解决方案以及各种 cmets 中将其拼接在一起。
您至少需要确保两件事:
确保将表名传递给getTables() method,
而不是传递一个空值。在第一种情况下,您让
数据库服务器在您请求的第二秒内为您过滤结果
来自服务器的 all 表列表,然后过滤列表
本地。如果您只搜索一个,前者要快得多
单表。
确保检查结果集中的表名是否为等号
匹配。原因是getTables() 进行模式匹配
表的查询和_ 字符是SQL 中的通配符。
假设您正在检查是否存在名为
EMPLOYEE_SALARY。然后,您也会在 EMPLOYEESSALARY 上找到匹配项
这不是你想要的。
哦,记得关闭这些结果集。从 Java 7 开始,您可能希望为此使用 try-with-resources statement。
这是一个完整的解决方案:
public static boolean tableExist(Connection conn, String tableName) throws SQLException {
boolean tExists = false;
try (ResultSet rs = conn.getMetaData().getTables(null, null, tableName, null)) {
while (rs.next()) {
String tName = rs.getString("TABLE_NAME");
if (tName != null && tName.equals(tableName)) {
tExists = true;
break;
}
}
}
return tExists;
}
您可能需要考虑在 getTables() 调用中作为 types 参数(第 4 个参数)传递的内容。通常我会离开null,因为你不想限制自己。 VIEW 和 TABLE 一样好,对吧?如今,许多数据库允许您通过 VIEW 进行更新,因此在大多数情况下将自己限制为仅 TABLE 类型并不是可行的方法。 YMMV。
【讨论】:
tName.equals(tableName) 更改为tName.equals(tableName.toLowerCase()),如果tableName 为大写则将无法使用。
添加到 Gaby 的帖子中,我的 jdbc getTables() for Oracle 10g 需要全部大写才能工作:
"employee" -> "EMPLOYEE"
否则我会得到一个异常:
java.sql.SqlExcepcion 耗尽结果集
(即使“员工”在架构中)
【讨论】:
/**
* Method that checks if all tables exist
* If a table doesnt exist it creates the table
*/
public void checkTables() {
try {
startConn();// method that connects with mysql database
String useDatabase = "USE " + getDatabase() + ";";
stmt.executeUpdate(useDatabase);
String[] tables = {"Patients", "Procedures", "Payments", "Procedurables"};//thats table names that I need to create if not exists
DatabaseMetaData metadata = conn.getMetaData();
for(int i=0; i< tables.length; i++) {
ResultSet rs = metadata.getTables(null, null, tables[i], null);
if(!rs.next()) {
createTable(tables[i]);
System.out.println("Table " + tables[i] + " created");
}
}
} catch(SQLException e) {
System.out.println("checkTables() " + e.getMessage());
}
closeConn();// Close connection with mysql database
}
【讨论】:
如果使用 jruby,这里是一个代码 sn-p 来返回一个 db 中所有表的数组。
require "rubygems"
require "jdbc/mysql"
Jdbc::MySQL.load_driver
require "java"
def get_database_tables(connection, db_name)
md = connection.get_meta_data
rs = md.get_tables(db_name, nil, '%',["TABLE"])
tables = []
count = 0
while rs.next
tables << rs.get_string(3)
end #while
return tables
end
【讨论】: