1. 程式人生 > 實用技巧 >JDBC(重點)

JDBC(重點)

JDBC(重點)

1、資料庫驅動

驅動:音效卡,顯示卡,資料庫

graph LR 應用程式-->MySQL驅動 應用程式-->Oracle驅動 MySQL驅動-->資料庫 Oracle驅動-->資料庫

2、JDBC

SUN 公司為了簡化 開發人員的 (對資料庫的統一)操作,提供了一個(Java操作資料庫)規範,俗稱 JDBC

沒有什麼是加一層解決不了的

graph LR 應用程式-->JDBC JDBC-->MySQL驅動 JDBC-->Oracle驅動 MySQL驅動-->資料庫 Oracle驅動-->資料庫

3、第一個 JDBC 程式

maven倉庫

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.6</version>
</dependency>

建立測試資料庫

# 建立表
create table users(
    id int primary key ,
    name varchar(40),
    password varchar(40),
    email varchar(60),
    birthday date
);
# 插入資料
insert into users values
(1,'zhangsan','123546','[email protected]','1980-12-04'),
(2,'lisi','123546','[email protected]','1981-12-04'),
(3,'wangwu','123546','[email protected]','1979-12-04');

Java程式碼

package com.raykeyzzz.lession01;

import java.sql.*;

// 我的第一個JDBC程式
public class JdbcFirstDemo {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        // 1.載入驅動
        Class.forName("com.mysql.jdbc.Driver");
        // 2.使用者資訊和 url
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8";
        String username = "root";
        String password = "123456";
        // 3.連線成功,資料庫物件
        Connection connection = DriverManager.getConnection(url, username, password);
        // 4.執行 SQL 的物件
        Statement statement = connection.createStatement();

        // 5.執行 SQL 的物件 去 執行SQL,返回結果
        ResultSet resultSet = statement.executeQuery("select * from jdbcstudy.users");

        while (resultSet.next()){
            System.out.println("id" + resultSet.getObject("id"));
            System.out.println("name" + resultSet.getObject("name"));
            System.out.println("password" + resultSet.getObject("password"));
        }

        // 6.釋放連線

        resultSet.close();
        statement.close();
        connection.close();

    }
}

步驟總結:載入驅動 --> 連線資料庫 DiverManager --> 獲得執行sql物件 Statement --> 返回結果集 -->釋放連線

簡化:寫工具類

工具類程式碼

package com.raykeyzzz.lession02;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class jdbcUtils {
    private static String driver = null;
    private static String url = null;
    private static String username = null;
    private static String password = null;

    // 載入驅動
    static {
        try {
            InputStream resourceAsStream = jdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(resourceAsStream);
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            Class.forName(driver);

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    
    
    // 獲取資料庫連線
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,username,password);
    }

    // 釋放資源
    public static void release(Connection connection, Statement statement, ResultSet resultSet){
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

操作資料庫程式碼

package com.raykeyzzz.lession02;

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

public class TestInsert {
    public static void main(String[] args) {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
            connection = jdbcUtils.getConnection();
            statement = connection.createStatement();
            resultSet = statement.executeQuery("select * from jdbcstudy.users");
            while (resultSet.next()) {
                System.out.println(resultSet.getObject("id"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            jdbcUtils.release(connection,statement,resultSet);
        }
    }
}

SQL注入問題

SQL 存在漏洞,會被攻擊導致資料洩漏,SQL會被拼接 or

package com.raykeyzzz.lession02;

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

public class TestInsert {
    public static void main(String[] args) {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
            connection = jdbcUtils.getConnection();
            statement = connection.createStatement();
            String sql = query("'' or 1 = 1"); // 將所有使用者資訊都查了出來,資訊洩露
            System.out.println(sql);
            resultSet = statement.executeQuery(sql);
            while (resultSet.next()) {
                System.out.println(resultSet.getObject("id"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            jdbcUtils.release(connection,statement,resultSet);
        }
    }

    // 查詢 某個使用者資訊
    public static String query(String name){
        return "select * from jdbcstudy.users " + "where name = " + name;
    }
}

4、第二個 JDBC 程式

PreparedStatement 可以防止SQL注入。效果更好!

工具類

package com.raykeyzzz.lession03;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class jdbcUtils {
    private static String driver = null;
    private static String url = null;
    private static String username = null;
    private static String password = null;

    // 載入驅動
    static {
        try {
            InputStream resourceAsStream = jdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(resourceAsStream);
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            Class.forName(driver);

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    // 獲取資料庫連線
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,username,password);
    }

    // 釋放資源
    public static void release(Connection connection, PreparedStatement statement, ResultSet resultSet){
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

操作資料庫程式碼

package com.raykeyzzz.lession03;

import java.sql.*;

public class TestInsert {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;

        try {
            connection = jdbcUtils.getConnection();
            String sql = insert();
            // 預編譯
            statement = connection.prepareStatement(sql);
            statement.setInt(1,4);
            statement.setString(2,"qinjiang");
            statement.setString(3,"123132456");
            statement.setString(4,"[email protected]");
            statement.setDate(5,new java.sql.Date(new java.util.Date().getTime()));

            int i = statement.executeUpdate();
            if (i > 0) {
                System.out.println("插入成功");
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            jdbcUtils.release(connection,statement,resultSet);
        }
    }

    // 查詢 某個使用者資訊
    public static String insert(){
        return "insert into users(id,name,password,email,birthday) values(?,?,?,?,?)";
    }
}

PreparedStatement 防注入原理

使用 作為佔位符,一個 代表一個引數,將一些非法字元轉義 再 拼接

如 " or 1 = 1"

使用 Statement

select * from jdbcstudy.users where name = '' or 1 = 1

使用 PreparedStatement

程式碼

package com.raykeyzzz.lession03;

import java.sql.*;

public class TestInsert {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet1 = null;

        try {
            connection = jdbcUtils.getConnection();
            String sql = query();
            // 預編譯
            statement = connection.prepareStatement(sql);
            statement.setString(1,"'' or 1 = 1");
            resultSet1 = statement.executeQuery();
            System.out.println(statement);
            while (resultSet1.next()) {
                System.out.println(resultSet1.getObject("name"));
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            jdbcUtils.release(connection,statement,resultSet1);
        }
    }
    
    public static String query() {
        return "select * from jdbcstudy.users where name = ?";
    }
}

結果

com.mysql.jdbc.JDBC4PreparedStatement@5010be6: select * from jdbcstudy.users where name = '\'\' or 1 = 1'

5、事務

ACID

原子性(Atomic)

一致性(Consistency)

隔離性(Isolation)

永續性(Durability)

目的:一致性(提交前後按照預想的結果走,要不都成功,要麼都失敗)

實現保證:原子性、永續性、隔離性

原子性:事務是最小元素不可分割,技術支援:事務回滾

隔離性:事務之間相互不干擾,技術支援:鎖和MVCC機制

永續性:保證儲存到磁碟上,防止斷電即失。技術支援:redo log日誌記錄事務操作記錄, 當事務提交的時候,會將redo log日誌進行刷盤(redo log一部分在記憶體中,一部分在磁碟上) 。當資料庫宕機重啟的時候,會將redo log中的內容恢復到資料庫中,再根據undo logbinlog內容決定回滾資料還是提交資料。

6、資料庫連線池

graph LR 資料庫連線 --> 執行完畢 執行完畢 --> 釋放

連線--釋放 十分耗費資源

池化技術:不用頻繁的 建立--釋放 資料庫

最小連線數

最大連線數

等待超時

編寫連線池

實現一個介面 DataSource

開源資料來源實現

本質:實現 DateSource 介面

該工廠用於提供到此 DataSource 物件所表示的物理資料來源的連線。作為 DriverManager 工具的替代項,DataSource 物件是獲取連線的首選方法。實現 DataSource 介面的物件通常在基於 JavaTM Naming and Directory Interface (JNDI) API 的命名服務中註冊。

DataSource 介面由驅動程式供應商實現。共有三種類型的實現:

  1. 基本實現 - 生成標準的 Connection 物件
  2. 連線池實現 - 生成自動參與連線池的 Connection 物件。此實現與中間層連線池管理器一起使用。
  3. 分散式事務實現 - 生成一個 Connection 物件,該物件可用於分散式事務,大多數情況下總是參與連線池。此實現與中間層事務管理器一起使用,大多數情況下總是與連線池管理器一起使用。
  • DBCP

  • C3P0

  • Druid:阿里巴巴

DBCP 實現程式碼:

maven倉庫

<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>

配置檔案

########DBCP配置檔案##########
#驅動名
driverClassName=com.mysql.jdbc.Driver
#url
url=jdbc:mysql://localhost:3306/jdbcstudy
#使用者名稱
username=root
#密碼
password=123456
#初試連線數
initialSize=30
#最大活躍數
maxTotal=30
#最大idle數
maxIdle=10
#最小idle數
minIdle=5
#最長等待時間(毫秒)
maxWaitMillis=1000
#程式中的連線不使用後是否被連線池回收(該版本要使用removeAbandonedOnMaintenance和removeAbandonedOnBorrow)
#removeAbandoned=true
removeAbandonedOnMaintenance=true
removeAbandonedOnBorrow=true
#連線在所指定的秒數內未使用才會被刪除(秒)(為配合測試程式才配置為1秒)
removeAbandonedTimeout=1

工具類

package com.raykeyzzz.lession04;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils {
    private static String driver = null;
    private static String url = null;
    private static String username = null;
    private static String password = null;

    // 載入驅動
    static {
        try {
            InputStream resourceAsStream = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(resourceAsStream);
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            Class.forName(driver);

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    // 獲取資料庫連線
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,username,password);
    }

    // 釋放資源
    public static void release(Connection connection, PreparedStatement statement, ResultSet resultSet){
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

操作資料庫程式碼

package com.raykeyzzz.lession04;

import com.raykeyzzz.lession02.jdbcUtils;

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

public class TestInsert {
    public static void main(String[] args) {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
            connection = JdbcUtils.getConnection();
            statement = connection.createStatement();
            String sql = query("'' or 1 = 1"); // 將所有使用者資訊都查了出來,資訊洩露
            System.out.println(sql);
            resultSet = statement.executeQuery(sql);
            while (resultSet.next()) {
                System.out.println(resultSet.getObject("id"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            jdbcUtils.release(connection,statement,resultSet);
        }
    }

    // 查詢 某個使用者資訊
    public static String query(String name){
        return "select * from jdbcstudy.users " + "where name = " + name;
    }
}