Connection
與特定數(shù)據(jù)庫的一個連接(會話)胀葱,執(zhí)行SQL語句并在連接的上下文中返回結(jié)果党涕。
- 數(shù)據(jù)庫信息
// 數(shù)據(jù)庫元信息包括:數(shù)據(jù)庫表、SQL語法巡社、存儲過程、連接的功能等手趣。
DatabaseMetaData getMetaData();
- 連接屬性
// 自動提交:默認是
// 自動提交時晌该,所有SQL都以單個事務執(zhí)行和提交;
// 語句完成時進行提交绿渣,完成的時機取決于語句類型:
// DML語句:完成執(zhí)行時提交事務
// Select語句:ResultSet關閉時提交
// CallableStatement:所有ResultSet關閉朝群、所有更新數(shù)和輸出參數(shù)檢索完
// 非自動提交時,多個SQL組成一個事務中符,顯式提交或回滾事務姜胖。
boolean getAutoCommit();
void setAutoCommit(boolean autoCommit);
// 只讀:
boolean isReadOnly();
// 此方法不能在事務中調(diào)用
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);
- 創(chuàng)建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)
- 創(chuàng)建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[]);
- 創(chuàng)建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持有的所有數(shù)據(jù)庫鎖
void commit();
// 非自動提交是晨抡,使用此方法回滾事務。
// 撤銷上次commit/rollback之后的所有更改则剃,釋放Connection持有的所有數(shù)據(jù)庫鎖
void rollback();
- 保存點
// 在當前事務中創(chuàng)建一個命名保存點
// 如果在事務外調(diào)用耘柱,則啟動一個新事務
Savepoint setSavepoint(String name);
// 創(chuàng)建一個匿名保存點
Savepoint setSavepoint();
// 回滾到指定保存點(只在非自動提交時調(diào)用)
void rollback(Savepoint savepoint);
void releaseSavepoint(Savepoint savepoint);
- 關閉連接
// 立即釋放Connection持有的數(shù)據(jù)庫和JDBC資源,而不是等待自動釋放棍现。
// 如果已關閉调煎,調(diào)用此方法則無操作。
// 強烈建議在調(diào)用此方法前己肮,顯式調(diào)用commit或rollback方法汛蝙。
void close();
// 查詢連接是否關閉烈涮。
// 連接在調(diào)用close或發(fā)生特定錯誤時被關閉
// 此方法并不用來判斷連接是否有效。典型的是通過捕獲操作異常來判斷連接失效窖剑。
boolean isClosed();
// 驅(qū)動發(fā)送查詢語句或使用其他方式已檢查連接是否有效
// 有效返回true坚洽,無效返回false,超時拋出異常
boolean isValid(int timeout);
- 類型映射
Map<String,Class<?>> getTypeMap();
void setTypeMap(Map<String,Class<?>> map);
DatabaseMetaData
// 獲取數(shù)據(jù)庫
// 返回:ResultSet列
// TABLE_CAT:String西土,數(shù)據(jù)庫名
ResultSet getCatalogs();
// 獲取表
// catalog:數(shù)據(jù)庫讶舰,null表示不指定
// schemaPattern:表模式
// tableNamePattern:表名模式
// types:表類型,見TABLE_TYPE
// 返回:ResultSet列
// TABLE_CAT:String需了,數(shù)據(jù)庫名跳昼,可能為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:數(shù)據(jù)庫,null表示不指定
// schemaPattern:表模式
// tableNamePattern:表名模式
// columnNamePattern:列名模式
// 返回:ResultSet列
// TABLE_CAT:String孕锄,數(shù)據(jù)庫名吮廉,可能為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:數(shù)據(jù)庫,null表示不指定
// schema:表模式
// table:表名艺智,不允許為null
// unique:唯一索引
// approximate:
// 返回:ResultSet列
// TABLE_CAT:String倘要,數(shù)據(jù)庫名,可能為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);
獲取數(shù)據(jù)庫表結(jié)構(gòu)
- 表結(jié)構(gòu)Bean
public class Database {
/** 數(shù)據(jù)庫名 */
private String databaseName;
/** 表 */
private Map<String, Table> tables = new LinkedHashMap<>();
static class Table {
/** 表名 */
String tableName;
/** 備注 */
String comment;
/** 列 */
Map<String, Column> columns = new LinkedHashMap<>();
/** 索引 */
Map<String, Index> 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<String> columnNames = new ArrayList<>();
}
// 打印表結(jié)構(gòu)
@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();
}
}
- 獲取表結(jié)構(gòu)
public static Map<String, Database> getDatabases(String url, String database, String table) {
Map<String, Database> 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<String> databaseNames = new ArrayList<>();
if (database != null) {
databaseNames.add(database);
} else {
Set<String> 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<String, Database> databaseMap = SchemaUtil.getDatabases(url, "test", "user");
for (Database database : databaseMap.values()) {
System.out.println(database);
}
}
結(jié)果:
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`)
);