Connection
与特定数据库的一个连接(会话),执行SQL语句并在连接的上下文中返回结果。
- 数据库信息
// 数据库元信息包括:数据库表、SQL语法、存储过程、连接的功能等。
DatabaseMetaData getMetaData();
- 连接属性
// 自动提交:默认是
// 自动提交时,所有SQL都以单个事务执行和提交;
// 语句完成时进行提交,完成的时机取决于语句类型:
// DML语句:完成执行时提交事务
// Select语句:ResultSet关闭时提交
// CallableStatement:所有ResultSet关闭、所有更新数和输出参数检索完
// 非自动提交时,多个SQL组成一个事务,显式提交或回滚事务。
boolean getAutoCommit();
void setAutoCommit(boolean autoCommit);
// 只读:
boolean isReadOnly();
// 此方法不能在事务中调用
void setReadOnly(boolean readOnly);
// ResultSet保持性
// ResultSet.HOLD_CURSORS_OVER_COMMIT 事务提交时ResultSet仍打开
// ResultSet.CLOSE_CURSORS_AT_COMMIT 事务提交时ResultSet关闭
int getHoldability();
void setHoldability(int holdability);
// 事务级别:
// Connection.TRANSACTION_NONE:0,无事务
// Connection.TRANSACTION_READ_UNCOMMITTED:1,未提交读
// Connection.TRANSACTION_READ_COMMITTED:2,已提交读
// Connection.TRANSACTION_REPEATABLE_READ:4,可重复读
// Connection.TRANSACTION_SERIALIZABLE:8,串行化
int getTransactionIsolation();
void setTransactionIsolation(int level);
- 创建Statement
// resultSetType:
// ResultSet.TYPE_FORWARD_ONLY
// resultSetConcurrency:
// ResultSet.CONCUR_READ_ONLY
// holdability:
// getHoldability()
Statement createStatement();
Statement createStatement(int resultSetType, int resultSetConcurrency);
// resultSetType:
// ResultSet.TYPE_FORWARD_ONLY
// ResultSet.TYPE_SCROLL_INSENSITIVE
// ResultSet.TYPE_SCROLL_SENSITIVE
// resultSetConcurrency:
// ResultSet.CONCUR_READ_ONLY
// ResultSet.CONCUR_UPDATABLE
// resultSetHoldability:
// ResultSet.HOLD_CURSORS_OVER_COMMIT
// ResultSet.CLOSE_CURSORS_AT_COMMIT
Statement createStatement(int resultSetType, int resultSetConcurrency,
int resultSetHoldability)
- 创建PreparedStatement
PreparedStatement prepareStatement(String sql);
PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency);
PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability);
PreparedStatement prepareStatement(String sql, int autoGeneratedKeys);
PreparedStatement prepareStatement(String sql, int columnIndexes[]);
PreparedStatement prepareStatement(String sql, String columnNames[]);
- 创建CallableStatement
CallableStatement prepareCall(String sql);
CallableStatement prepareCall(String sql, int resultSetType,int resultSetConcurrency);
CallableStatement prepareCall(String sql, int resultSetType,int resultSetConcurrency,
int resultSetHoldability);
- 事务
// 非自动提交时,使用此方法显式提交事务。
// 提交上次commit/rollback之后的所有更改,释放Connection持有的所有数据库锁
void commit();
// 非自动提交是,使用此方法回滚事务。
// 撤销上次commit/rollback之后的所有更改,释放Connection持有的所有数据库锁
void rollback();
- 保存点
// 在当前事务中创建一个命名保存点
// 如果在事务外调用,则启动一个新事务
Savepoint setSavepoint(String name);
// 创建一个匿名保存点
Savepoint setSavepoint();
// 回滚到指定保存点(只在非自动提交时调用)
void rollback(Savepoint savepoint);
void releaseSavepoint(Savepoint savepoint);
- 关闭连接
// 立即释放Connection持有的数据库和JDBC资源,而不是等待自动释放。
// 如果已关闭,调用此方法则无操作。
// 强烈建议在调用此方法前,显式调用commit或rollback方法。
void close();
// 查询连接是否关闭。
// 连接在调用close或发生特定错误时被关闭
// 此方法并不用来判断连接是否有效。典型的是通过捕获操作异常来判断连接失效。
boolean isClosed();
// 驱动发送查询语句或使用其他方式已检查连接是否有效
// 有效返回true,无效返回false,超时抛出异常
boolean isValid(int timeout);
- 类型映射
Map> getTypeMap();
void setTypeMap(Map> map);
DatabaseMetaData
// 获取数据库
// 返回:ResultSet列
// TABLE_CAT:String,数据库名
ResultSet getCatalogs();
// 获取表
// catalog:数据库,null表示不指定
// schemaPattern:表模式
// tableNamePattern:表名模式
// types:表类型,见TABLE_TYPE
// 返回:ResultSet列
// TABLE_CAT:String,数据库名,可能为null
// TABLE_SCHEM:String,表模式,可能为null
// TABLE_NAME:String,表名
// TABLE_TYPE:String,表类型,有TABLE,VIEW,SYSTEM TABLE,
// GLOBAL TEMPORARY,LOCAL TEMPORARY,ALIAS,SYNONYM
// REMARKS:String,表备注
ResultSet getTables(String catalog, String schemaPattern,
String tableNamePattern, String types[]);
// 获取列
// catalog:数据库,null表示不指定
// schemaPattern:表模式
// tableNamePattern:表名模式
// columnNamePattern:列名模式
// 返回:ResultSet列
// TABLE_CAT:String,数据库名,可能为null
// TABLE_SCHEM:String,表模式,可能为null
// TABLE_NAME:String,表名
// COLUMN_NAME:String,列名
// DATA_TYPE:int,类型,见java.sql.Types
// TYPE_NAME:String,类型名
// COLUMN_SIZE:int,列大小
// REMARKS:String,备注
// COLUMN_DEF:String,默认值,可能为null
// ORDINAL_POSITION:int,列顺序,1起
// IS_NULLABLE:String:YES,可以保护NULL;NO,不能;空白,未知;
// IS_AUTOINCREMENT:String:YES,自增;NO,不是;空白,未知;
ResultSet getColumns(String catalog, String schemaPattern,
String tableNamePattern, String columnNamePattern);
// 获取索引
// catalog:数据库,null表示不指定
// schema:表模式
// table:表名,不允许为null
// unique:唯一索引
// approximate:
// 返回:ResultSet列
// TABLE_CAT:String,数据库名,可能为null
// TABLE_SCHEM:String,表模式,可能为null
// TABLE_NAME:String,表名
// INDEX_NAME:String,索引名
// NON_UNIQUE:boolean,是否不是唯一索引
// COLUMN_NAME:String,索引列名
// ORDINAL_POSITION:short,索引列名位置
ResultSet getIndexInfo(String catalog, String schema, String table,
boolean unique, boolean approximate);
获取数据库表结构
- 表结构Bean
public class Database {
/** 数据库名 */
private String databaseName;
/** 表 */
private Map tables = new LinkedHashMap<>();
static class Table {
/** 表名 */
String tableName;
/** 备注 */
String comment;
/** 列 */
Map columns = new LinkedHashMap<>();
/** 索引 */
Map indexes = new LinkedHashMap<>();
}
static class Column {
/** 列名 */
String columnName;
/** 类型,见java.sql.Types */
int dataType;
/** 类型名 */
String typeName;
/** 大小*/
int columnSize;
/** null,未知;true,yes;false,no;*/
Boolean nullable;
/** 默认值 */
String defaultValue;
/** null,未知;true,yes;false,no;*/
Boolean autoIncrement;
/** 备注 */
String comment;
}
static class Index {
/** 索引名 */
private String indexName;
/** 是否是唯一索引 */
private boolean unique;
/** 列名 */
private List columnNames = new ArrayList<>();
}
// 打印表结构
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(databaseName + ": " + tables.size() + "\n\n");
for (Table table : tables.values()) {
sb.append("CREATE TABLE `" + table.tableName + "` (\n");
for (Column column : table.columns.values()) {
sb.append(" `" + column.columnName + "` " + column.typeName + "(" + column.columnSize + ")");
if (column.nullable != null && !column.nullable) {
sb.append(" NOT NULL");
}
if (StringUtils.isNotBlank(column.defaultValue)) {
sb.append(" DEFAULT '" + column.defaultValue + "'");
}
if (column.autoIncrement != null && column.autoIncrement) {
sb.append(" AUTO_INCREMENT");
}
if (StringUtils.isNotBlank(column.comment)) {
sb.append(" COMMENT '" + column.comment + "'");
}
sb.append(",\n");
}
for (Index index : table.indexes.values()) {
sb.append(" ");
String indexName = index.indexName;
if (StringUtils.equalsIgnoreCase(indexName, "PRIMARY")) {
sb.append("PRIMARY KEY");
} else if (index.unique) {
sb.append("UNIQUE KEY `" + indexName + "`");
} else {
sb.append("KEY `" + indexName + "`");
}
sb.append(" (");
for (int j = 0; j < index.columnNames.size(); j++) {
String columnName = index.columnNames.get(j);
sb.append("`" + columnName + "`");
if (j != index.columnNames.size()-1) {
sb.append(", ");
}
}
sb.append("),\n");
}
// 去掉最后一行的“,”
sb.replace(sb.length()-2, sb.length(), "\n)");
if (StringUtils.isNotBlank(table.comment)) {
sb.append(" COMMENT='" + table.comment + "'");
}
sb.append(";\n\n");
}
return sb.toString();
}
}
- 获取表结构
public static Map getDatabases(String url, String database, String table) {
Map databaseMap = new HashMap<>();
Connection connection = null;
ResultSet resultSet = null;
try {
Properties info = new Properties();
connection = DriverManager.getConnection(url, info);
DatabaseMetaData metaData = connection.getMetaData();
// Database
{
List databaseNames = new ArrayList<>();
if (database != null) {
databaseNames.add(database);
} else {
Set systemDatabases = new HashSet<>();
// MySQL
systemDatabases.add("information_schema");
systemDatabases.add("performance_schema");
resultSet = metaData.getCatalogs();
while (resultSet.next()) {
String databaseName = resultSet.getString("TABLE_CAT");
if (!systemDatabases.contains(databaseName)) {
databaseNames.add(databaseName);
}
}
resultSet.close();
}
for (String databaseName : databaseNames) {
databaseMap.put(database, new Database(databaseName));
}
}
// Table
{
resultSet = metaData.getTables(null, null, table, new String[]{"TABLE"});
while (resultSet.next()) {
String databaseName = resultSet.getString("TABLE_CAT");
String tableName = resultSet.getString("TABLE_NAME");
// Type: TABLE, VIEW, SYSTEM TABLE, GLOBAL TEMPORARY, LOCAL TEMPORARY, ALIAS, SYNONYM
// String tableType = resultSet.getString("TABLE_TYPE");
String comment = resultSet.getString("REMARKS");
databaseMap.get(databaseName).addTable(tableName, comment);
}
resultSet.close();
}
// Column
{
resultSet = metaData.getColumns(null, null, table, null);
while (resultSet.next()) {
String databaseName = resultSet.getString("TABLE_CAT");
String tableName = resultSet.getString("TABLE_NAME");
String columnName = resultSet.getString("COLUMN_NAME");
// SQL type from java.sql.Types
int dataType = resultSet.getInt("DATA_TYPE");
// Data source dependent type name, for a UDT the type name is fully qualified
String typeName = resultSet.getString("TYPE_NAME");
int columnSize = resultSet.getInt("COLUMN_SIZE");
String comment = resultSet.getString("REMARKS");
// may be null
String defaultValue = resultSet.getString("COLUMN_DEF");
// YES: include NULLs
// NO: not include NULLs
// empty string: nullability is unknown
String isNullable = resultSet.getString("IS_NULLABLE");
Boolean nullable = null;
if (StringUtils.equalsIgnoreCase(isNullable, "YES")) {
nullable = true;
} else if (StringUtils.equalsIgnoreCase(isNullable, "NO")) {
nullable = false;
}
// YES: is auto incremented
// NO: is not auto incremented
// empty string: unknown
String IS_AUTOINCREMENT = resultSet.getString("IS_AUTOINCREMENT");
Boolean autoIncrement = null;
if (StringUtils.equalsIgnoreCase(IS_AUTOINCREMENT, "YES")) {
autoIncrement = true;
} else if (StringUtils.equalsIgnoreCase(IS_AUTOINCREMENT, "NO")) {
autoIncrement = false;
}
databaseMap.get(databaseName).addColumn(tableName, columnName, dataType, typeName, columnSize, nullable, defaultValue, autoIncrement, comment);
}
resultSet.close();
}
// Index
{
for (Database db : databaseMap.values()) {
for (String tb : db.getTableNames()) {
resultSet = metaData.getIndexInfo(db.getDatabaseName(), null, tb, false, false);
while (resultSet.next()) {
String databaseName = resultSet.getString("TABLE_CAT");
String tableName = resultSet.getString("TABLE_NAME");
String indexName = resultSet.getString("INDEX_NAME");
boolean unique = !resultSet.getBoolean("NON_UNIQUE");
String columnName = resultSet.getString("COLUMN_NAME");
databaseMap.get(databaseName).addIndex(tableName, indexName, unique, columnName);
}
resultSet.close();
}
}
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return databaseMap;
}
- 测试
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/test?user=root&password=123456&useUnicode=true&characterEncoding=UTF-8";
Map databaseMap = SchemaUtil.getDatabases(url, "test", "user");
for (Database database : databaseMap.values()) {
System.out.println(database);
}
}
结果:
test: 1
CREATE TABLE `user` (
`id` BIGINT(19) NOT NULL AUTO_INCREMENT,
`userName` VARCHAR(128) NOT NULL COMMENT '账号',
`nickName` VARCHAR(100) NOT NULL,
`status` TINYINT(3) DEFAULT '0',
`createTime` BIGINT(19) NOT NULL,
`updateTime` BIGINT(19) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u_s` (`userName`, `status`),
KEY `key_un` (`userName`)
);