Java JDBC 2

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`)
);
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末韧骗,一起剝皮案震驚了整個濱河市嘉抒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌袍暴,老刑警劉巖些侍,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隶症,死亡現(xiàn)場離奇詭異,居然都是意外死亡岗宣,警方通過查閱死者的電腦和手機蚂会,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來狈定,“玉大人颂龙,你說我怎么就攤上這事∨κ玻” “怎么了措嵌?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長芦缰。 經(jīng)常有香客問我企巢,道長,這世上最難降的妖魔是什么让蕾? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任浪规,我火速辦了婚禮,結(jié)果婚禮上探孝,老公的妹妹穿的比我還像新娘笋婿。我一直安慰自己,他們只是感情好顿颅,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布缸濒。 她就那樣靜靜地躺著,像睡著了一般粱腻。 火紅的嫁衣襯著肌膚如雪庇配。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天绍些,我揣著相機與錄音捞慌,去河邊找鬼。 笑死柬批,一個胖子當著我的面吹牛啸澡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播氮帐,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锻霎,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了揪漩?” 一聲冷哼從身側(cè)響起旋恼,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后冰更,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體产徊,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年蜀细,在試婚紗的時候發(fā)現(xiàn)自己被綠了舟铜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡奠衔,死狀恐怖谆刨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情归斤,我是刑警寧澤痊夭,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站脏里,受9級特大地震影響她我,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜迫横,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一番舆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧矾踱,春花似錦恨狈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至圣蝎,卻和暖如春刃宵,著一層夾襖步出監(jiān)牢的瞬間衡瓶,已是汗流浹背徘公。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留哮针,地道東北人关面。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像十厢,于是被迫代替她去往敵國和親等太。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容