DatabaseMetaData in Java
DatabaseMetaData provides information about the database as a whole, and about the driver you are connected through. You get it from a connection with con.getMetaData(). It can tell you the database product and version, which features it supports, and what it contains: the tables, their columns, primary keys and foreign keys. Tools depend on it: database browsers list tables with it, migration tools check whether a table already exists, and frameworks adapt their SQL to the database they find. In this lesson, you will learn its main methods and explore a small schema with them.
Methods: About the Product and Driver
| Method | Description |
|---|---|
getDatabaseProductName(), getDatabaseProductVersion() | They are used to get the database's name and version. |
getDriverName(), getDriverVersion() | They return the JDBC driver's name and version. |
getJDBCMajorVersion(), getJDBCMinorVersion() | They return the JDBC version the driver supports. |
getURL(), getUserName() | They return the connection's URL and user. |
Methods: What the Database Supports
| Method | Description |
|---|---|
supportsTransactions() | It tells whether transactions are available. |
supportsBatchUpdates() | It tells whether batch updates work. |
supportsSavepoints() | It tells whether savepoints are available. |
supportsStoredProcedures() | It tells whether procedures can be called. |
supportsResultSetType(type) | It tells whether a result set type, such as scrollable, is supported. |
getDefaultTransactionIsolation() | It returns the default isolation level. |
Methods: What the Database Contains
Each of these returns a ResultSet, with one row per item:
| Method | Rows describe |
|---|---|
getTables(catalog, schema, namePattern, types) | Tables and views |
getColumns(catalog, schema, table, columnPattern) | Columns of a table |
getPrimaryKeys(catalog, schema, table) | Primary key columns |
getImportedKeys(catalog, schema, table) | Foreign keys of this table, pointing to other tables |
getExportedKeys(catalog, schema, table) | Foreign keys in other tables that point to this one |
getIndexInfo(...) | Indexes |
getSchemas(), getCatalogs() | Schemas and catalogs (databases) |
In the pattern arguments, % matches any text and null means "don't filter".
Example: Exploring a Schema
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class DbMeta {
public static void main(String[] args) throws Exception {
try (Connection con =
DriverManager.getConnection("jdbc:h2:mem:school");
Statement st = con.createStatement()) {
st.execute("CREATE TABLE course ("
+ "code VARCHAR(10) PRIMARY KEY, title VARCHAR(40) NOT NULL)");
st.execute("CREATE TABLE student (id INT PRIMARY KEY, "
+ "name VARCHAR(50) NOT NULL, course VARCHAR(10), "
+ "FOREIGN KEY (course) REFERENCES course(code))");
DatabaseMetaData md = con.getMetaData();
System.out.println("Product: " + md.getDatabaseProductName());
System.out.println("Driver: " + md.getDriverName());
System.out.println("JDBC: " + md.getJDBCMajorVersion() + "."
+ md.getJDBCMinorVersion());
System.out.println("Transactions? " + md.supportsTransactions());
System.out.println("Batch updates? " + md.supportsBatchUpdates());
System.out.println("Savepoints? " + md.supportsSavepoints());
System.out.println("Tables:");
try (ResultSet rs = md.getTables(
null, "PUBLIC", "%", new String[] {"TABLE"})) {
while (rs.next()) {
System.out.println(" " + rs.getString("TABLE_NAME"));
}
}
System.out.println("Columns of STUDENT:");
try (ResultSet rs = md.getColumns(null, "PUBLIC", "STUDENT", "%")) {
while (rs.next()) {
System.out.println(" " + rs.getString("COLUMN_NAME") + " "
+ rs.getString("TYPE_NAME") + "("
+ rs.getInt("COLUMN_SIZE") + ") nullable="
+ rs.getString("IS_NULLABLE"));
}
}
try (ResultSet rs = md.getPrimaryKeys(null, "PUBLIC", "STUDENT")) {
rs.next();
System.out.println("Primary key: "
+ rs.getString("COLUMN_NAME"));
}
try (ResultSet rs = md.getImportedKeys(null, "PUBLIC", "STUDENT")) {
rs.next();
System.out.println("Foreign key: "
+ rs.getString("FKCOLUMN_NAME") + " -> "
+ rs.getString("PKTABLE_NAME") + "."
+ rs.getString("PKCOLUMN_NAME"));
}
}
}
}Product: H2
Driver: H2 JDBC Driver
JDBC: 4.3
Transactions? true
Batch updates? true
Savepoints? true
Tables:
COURSE
STUDENT
Columns of STUDENT:
ID INTEGER(32) nullable=NO
NAME CHARACTER VARYING(50) nullable=NO
COURSE CHARACTER VARYING(10) nullable=YES
Primary key: ID
Foreign key: COURSE -> COURSE.CODEExplanation:
- The first lines identify the database and driver, and report three features as supported.
getTables(null, "PUBLIC", "%", new String[] {"TABLE"})asks for every ordinary table in thePUBLICschema. Each row has aTABLE_NAMEcolumn, among others.getColumnsreturns one row per column ofSTUDENT, with its name, type, size and whether it acceptsNULL.getPrimaryKeysreports thatIDis the primary key.getImportedKeysreports the foreign key:STUDENT.COURSErefers toCOURSE.CODE.
The column names of these result sets, such as TABLE_NAME, COLUMN_NAME and FKCOLUMN_NAME, are fixed by the JDBC specification, so the code works on any database. The values differ: H2 and Oracle store names in upper case, PostgreSQL in lower case, and the type names are each database's own.
ResultSetMetaData vs DatabaseMetaData
| Point | ResultSetMetaData | DatabaseMetaData |
|---|---|---|
| Obtained from | resultSet.getMetaData() | connection.getMetaData() |
| Describes | The columns of one result | The database and the driver |
| Typical question | "What columns did this query return?" | "Which tables exist? Does this database support savepoints?" |
| Returns | Simple values | Simple values and result sets |
Common Mistakes
Assuming name case. A table created as student may be reported as STUDENT or student depending on the database. Compare names case-insensitively, or use the case the database uses.
Passing the wrong schema. If nothing comes back, try null for the schema to search all of them.
Calling metadata methods in hot code. They are far more expensive than they look.
Interview Corner
What is DatabaseMetaData?
DatabaseMetaData, obtained from connection.getMetaData(), describes the database and driver: product name and version, driver name and version, the JDBC version, supported features (transactions, batch updates, savepoints, stored procedures, result set types), limits, and the database's structure through methods such as getTables, getColumns, getPrimaryKeys and getImportedKeys, which return result sets. It is used by database tools, migration utilities and frameworks that must adapt to different databases.
What is the difference between DatabaseMetaData and ResultSetMetaData?
DatabaseMetaData comes from a Connection and describes the whole database and its driver, including capabilities and schema objects. ResultSetMetaData comes from a ResultSet and describes only the columns of that particular result: their count, names, labels and types.
Practice
- Easy: Print the product name, product version and driver version of your connection.
- Harder: Write
boolean tableExists(Connection con, String name)usinggetTables, comparing names without regard to case.
Key Takeaways
Was this tutorial helpful?