Java_JDBC 鏈接

  今天,接着上一篇( mysql 數據庫 )的基礎上,我就寫一下 Java 怎樣鏈接數據庫,而且操做數據庫。html

  首先,咱們先來準備一下數據庫鏈接的驅動:java

  mysql 的 jar 包下載地址:https://dev.mysql.com/downloads/connector/j/mysql

  Oracle 的 jar 包下載地址:https://www.oracle.com/technetwork/cn/middleware/goldengate/downloads/index.htmlsql

  本文章還用到 c3p0 的數據庫鏈接池數據庫

  c3p0 的 jar 包下載地址:https://sourceforge.net/projects/c3p0/apache

  接下來,咱們就開始正式瞭解一下什麼是 JDBC ,用 Java 怎樣鏈接數據庫,而且怎樣操做數據庫。編程

什麼是JDBC

  JDBC(Java DataBase Connectivity,java數據庫鏈接)是一種用於執行SQL語句的Java API,能夠爲多種關係數據庫提供統一訪問,它由一組用Java語言編寫的類和接口組成。JDBC提供了一種基準,據此能夠構建更高級的工具和接口,使數據庫開發人員可以編寫數據庫應用程序。服務器

數據庫驅動

  咱們安裝好數據庫以後,咱們的應用程序也是不能直接使用數據庫的,必需要經過相應的數據庫驅動程序,經過驅動程序去和數據庫打交道。其實也就是數據庫廠商的JDBC接口實現,即對Connection等接口的實現類的jar文件。oracle

Driver接口

  Driver接口由數據庫廠家提供,做爲java開發人員,只須要使用Driver接口就能夠了。在編程中要鏈接數據庫,必須先裝載特定廠商的數據庫驅動程序,不一樣的數據庫有不一樣的裝載方法。如:工具

  裝載MySql驅動:Class.forName("com.mysql.jdbc.Driver");

  裝載Oracle驅動:Class.forName("oracle.jdbc.driver.OracleDriver");

Connection接口

  Connection與特定數據庫的鏈接(會話),在鏈接上下文中執行sql語句並返回結果。DriverManager.getConnection(url, user, password)方法創建在JDBC URL中定義的數據庫Connection鏈接上。

  鏈接MySql數據庫:Connection conn = DriverManager.getConnection("jdbc:mysql://host:port/database", "user", "password");

  鏈接Oracle數據庫:Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@host:port:database", "user", "password");

  鏈接SqlServer數據庫:Connection conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://host:port; DatabaseName=database", "user", "password");

  經常使用方法:

    • createStatement():建立向數據庫發送sql的statement對象。
    • prepareStatement(sql) :建立向數據庫發送預編譯sql的PrepareSatement對象。
    • prepareCall(sql):建立執行存儲過程的callableStatement對象。
    • setAutoCommit(boolean autoCommit):設置事務是否自動提交。
    • commit() :在連接上提交事務。
    • rollback() :在此連接上回滾事務。

 

使用JDBC的步驟

  加載JDBC驅動程序 → 創建數據庫鏈接Connection → 建立執行SQL的語句Statement → 處理執行結果ResultSet → 釋放資源

初始化驅動

  經過初始化驅動類com.mysql.jdbc.Driver,該類就在 mysql-connector-java-5.0.8-bin.jar中。若是你使用的是oracle數據庫那麼該驅動類將不一樣。

 

//加載數據庫驅動程序(對應的 Driver 實現類中有註冊驅動的靜態代碼塊.)
String driver ="com.mysql.jdbc.Driver";
Class.forName(driver);

 

創建JDBC和數據庫之間的Connection鏈接

//經過 DriverManager 的 getConnection() 方法獲取數據庫鏈接.
Connection conn = DriverManager.getConnection(url,user,password);

這裏須要提供:url包括如下(jdbc:mysql://ip地址:端口號/須要鏈接的數據庫名字),例如:jdbc:mysql://localhost:3306/db_database05

       數據庫所處於的ip:127.0.0.1 (這裏是本機,若是鏈接其餘電腦上的數據庫,請改變該ip)
                         數據庫的端口號: 3306 (mysql專用端口號)
                         數據庫名稱: (根據你本身數據庫中的名稱填寫)

       數據庫鏈接的用戶名:user

       數據庫的登陸密碼:password

建立數據庫鏈接的工具方法

/*
 * 數據庫鏈接工具類
 */
package com.hzc.util;

import java.sql.Connection;
import java.sql.DriverManager;

public class DataBaseUtil {
    /**
     * 獲取數據庫鏈接
     * @return Connection 對象
     */
    public static Connection getConnection(){
        Connection conn = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/db_database05";
            conn = DriverManager.getConnection(url,user,password);    //這裏的user和password根據本身的數據庫登陸和密碼填寫
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }
    /**
     * 關閉數據庫鏈接
     * @param conn Connection 對象
     */
    public static void closeConnection(Connection conn){
        //判斷 conn 是否爲空
        if(conn != null){
            try {
                conn.close();            //關閉數據庫鏈接
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

 

  這裏在提供 c3p0 數據庫鏈接池的方法

C3P0 數據庫鏈接池

package jdbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

/*
 * 操做JDBC的工具類,其中封裝了一些工具方法
 */
public class JDBCTools {
    
    private static DataSource dataSource = null;
    //數據庫鏈接池應只初始化一次
    static{
        dataSource = new ComboPooledDataSource("helloc3p0");
    }

    //數據庫鏈接:經過讀取配置文件從數據庫服務器獲取一個鏈接
    public static Connection getConnection() throws Exception{
        
        return dataSource.getConnection();
    }
    
    //關閉 ResultSet、Statement 和 Connection
    public static void release(ResultSet rs,Statement statement,Connection conn){
        if(rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        //數據庫鏈接池的 Connection 對象進行 close 時
        //並非真的進行關閉, 而是把該數據庫鏈接會歸還到數據庫鏈接池中.
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    
    /*
     * 處理數據庫的事務
     */
    
    //提交事務
    public static void commit(Connection conn){
        if(conn != null){
            try {
                conn.commit();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    
    //回滾事務
    public static void rollback(Connection conn){
        if(conn != null){
            try {
                conn.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    
    //開始事務
    public static void beginTx(Connection conn){
        if(conn != null){
            try {
                conn.setAutoCommit(false);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

  C3P0 要在 src 目錄下配置:建立一個名爲 c3p0-config.xml ,而且記住要導入 c3p0 的 jar 包。

c3p0-config.xml 的配置

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>

    <named-config name="helloc3p0">
        
        <!-- 指定鏈接數據源的基本屬性 -->
        <property name="user">登陸名</property>
        <property name="password">密碼</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
        
        <!-- 若數據庫中鏈接數不足時, 一次向數據庫服務器申請多少個鏈接 -->
        <property name="acquireIncrement">5</property>
        <!-- 初始化數據庫鏈接池時鏈接的數量 -->
        <property name="initialPoolSize">5</property>
        <!-- 數據庫鏈接池中的最小的數據庫鏈接數 -->
        <property name="minPoolSize">5</property>
        <!-- 數據庫鏈接池中的最大的數據庫鏈接數 -->
        <property name="maxPoolSize">10</property>

        <!-- C3P0 數據庫鏈接池能夠維護的 Statement 的個數 -->
        <property name="maxStatements">20</property>
        <!-- 每一個鏈接同時可使用的 Statement 對象的個數 -->
        <property name="maxStatementsPerConnection">5</property>
    
    </named-config>
        
</c3p0-config>

Statement接口

  用於執行靜態SQL語句並返回它所生成結果的對象。

  三種Statement類:

    • Statement:由createStatement建立,用於發送簡單的SQL語句(不帶參數)。
    • PreparedStatement :繼承自Statement接口,由preparedStatement建立,用於發送含有一個或多個參數的SQL語句。PreparedStatement對象比Statement對象的效率更高,而且能夠防止SQL注入,因此咱們通常都使用PreparedStatement。
    • CallableStatement:繼承自PreparedStatement接口,由方法prepareCall建立,用於調用存儲過程。

  經常使用Statement方法:

    • execute(String sql):運行語句,返回是否有結果集
    • executeQuery(String sql):運行select語句,返回ResultSet結果集。
    • executeUpdate(String sql):運行insert/update/delete操做,返回更新的行數。
    • addBatch(String sql) :把多條sql語句放到一個批處理中。
    • executeBatch():向數據庫發送一批sql語句執行。

 

ResultSet接口

  ResultSet提供檢索不一樣類型字段的方法,經常使用的有:

 

    • getString(int index)、getString(String columnName):得到在數據庫裏是varchar、char等類型的數據對象。
    • getFloat(int index)、getFloat(String columnName):得到在數據庫裏是Float類型的數據對象。
    • getDate(int index)、getDate(String columnName):得到在數據庫裏是Date類型的數據。
    • getBoolean(int index)、getBoolean(String columnName):得到在數據庫裏是Boolean類型的數據。
    • getObject(int index)、getObject(String columnName):獲取在數據庫裏任意類型的數據。

 

  ResultSet還提供了對結果集進行滾動的方法:

 

    • next():移動到下一行
    • Previous():移動到前一行
    • absolute(int row):移動到指定行
    • beforeFirst():移動resultSet的最前面。
    • afterLast() :移動到resultSet的最後面。

 

使用後依次關閉對象及鏈接:ResultSet → Statement → Connection

  這裏就直接提供數據庫通用的查詢方法,本身寫成一個公用類,須要用查詢方法的時候,就能夠繼承它,調用裏面的方法。

JDBC 的 Dao 方法

package jdbc;

/*
 * JDBC的工具方法
 */
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;

public class Dao {

    // 執行 SQL 語句,使用 PreparedStatement
    public void update(String sql, Object... args) {
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = JDBCTools.getConnection();
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCTools.release(null, ps, conn);
        }
    }

    // 執行SQL的方法,使用 Statement:insert、update、delete,而不包含select
    public void update(String sql) {
        Connection conn = null;
        Statement st = null;
        try {
            conn = JDBCTools.getConnection();
            st = conn.createStatement();
            st.executeUpdate(sql);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCTools.release(null, st, conn);
        }
    }

    // 查詢一條記錄,返回對應的對象
    public <T> T get(Class<T> clazz, String sql, Object... args)throws Exception {
        List<T> result = getForList(clazz, sql, args);
        if (result.size() > 0) {
            return result.get(0);
        }
        return null;
    }

    /*
     * 傳入 SQL 語句和 Class 對象,返回 SQL 語句查詢的記錄對應的 Class 類的對象的集合
     * 
     * @param clazz: 對象的類型
     * 
     * @param sql: SQL 語句
     * 
     * @param args: 填充 SQL 語句的佔位符的可變參數
     * 
     * @return
     */
    public <T> List<T> getForList(Class<T> clazz, String sql, Object... args)throws Exception {
        List<T> list = new ArrayList<>();
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            // 一、獲得結果集
            conn = JDBCTools.getConnection();
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            rs = ps.executeQuery();

            // 二、處理結果集,獲得 Map 的 List, 其中一個 Map 對象就是一條記錄. Map 的 key 爲 rs 中列的別名,
            // Map 的 value 爲列的值
            List<Map<String, Object>> values = handleResultSetToMapList(rs);

            // 三、把 Map 的 List 轉爲 clazz 對應的 List, 其中 Map 的 key 即爲 clazz 對應的對象的
            // propertyName,
            // 而 Map 的 value 即爲 clazz 對應的對象的 propertyValue
            list = transfterMapListToBeanList(clazz, values);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCTools.release(rs, ps, conn);
        }

        return list;
    }

    // 把 Map 的 List 轉爲 clazz 對應的 List
    public <T> List<T> transfterMapListToBeanList(Class<T> clazz, List<Map<String, Object>> values)throws Exception {
        List<T> result = new ArrayList<>();
        T bean = null;
        if (values.size() > 0) {
            for (Map<String, Object> m : values) {
                bean = clazz.newInstance();
                for (Map.Entry<String, Object> entry : m.entrySet()) {
                    String propertyName = entry.getKey();
                    Object value = entry.getValue();

                    BeanUtils.setProperty(bean, propertyName, value);
                }
                // 把 Object 對象放入到 list 中
                result.add(bean);
            }
        }
        return result;
    }

    /**
     * 處理結果集, 獲得 Map 的一個 List, 其中一個 Map 對象對應一條記
     * 
     * @param resultSet
     * @return
     * @throws SQLException
     */
    public List<Map<String, Object>> handleResultSetToMapList(ResultSet rs) throws Exception {
        // 準備一個 List<Map<String, Object>>:鍵: 存放列的別名, 值: 存放列的值. 其中一個 Map
        // 對象對應着一條記錄
        List<Map<String, Object>> values = new ArrayList<>();
        List<String> columnLabels = getColumnLabels(rs);
        Map<String, Object> map = null;

        // 處理 ResultSet, 使用 while 循環
        while (rs.next()) {
            map = new HashMap<>();
            for (String columnLabel : columnLabels) {
                Object value = rs.getObject(columnLabel);
                map.put(columnLabel, value);
            }

            // 把一條記錄的一個 Map 對象放入 List 中
            values.add(map);
        }
        return values;
    }

    /**
     * 獲取結果集的 ColumnLabel 對應的 List
     * 
     * @param rs
     * @return
     * @throws SQLException
     */
    private List<String> getColumnLabels(ResultSet rs) throws Exception {
        List<String> labels = new ArrayList<>();
        ResultSetMetaData rsmd = rs.getMetaData();
        for (int i = 0; i < rsmd.getColumnCount(); i++) {
            labels.add(rsmd.getColumnLabel(i + 1));
        }
        return labels;
    }

    // 返回某條記錄的某一個字段的值 或 一個統計的值(一共有多少條記錄等.)
    @SuppressWarnings("unchecked")
    public <E> E getForValue(String sql, Object... args) {
        // 1. 獲得結果集: 該結果集應該只有一行, 且只有一列
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            // 1. 獲得結果集
            conn = JDBCTools.getConnection();
            ps = conn.prepareStatement(sql);

            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }

            rs = ps.executeQuery();

            if (rs.next()) {
                return (E) rs.getObject(1);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            JDBCTools.release(rs, ps, conn);
        }
        // 2. 取得結果

        return null;
    }
}

  掌握好 JDBC 的鏈接,Java 寫不少項目都要與數據庫打交道。

  本身寫的不是專業,但願你們提一下意見。本身也是在學習 Java 的小白。寫一下博客記錄一下本身的學習狀況。寫一下博客,能瞭解本身學習的水平。

相關文章
相關標籤/搜索