欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java JDBC API介紹與實(shí)現(xiàn)數(shù)據(jù)庫連接池流程

 更新時間:2022年12月08日 10:42:03   作者:-BoBooY-  
JDBC是指Java數(shù)據(jù)庫連接,是一種標(biāo)準(zhǔn)Java應(yīng)用編程接口( JAVA API),用來連接 Java 編程語言和廣泛的數(shù)據(jù)庫。從根本上來說,JDBC 是一種規(guī)范,它提供了一套完整的接口,允許便攜式訪問到底層數(shù)據(jù)庫,本篇文章我們來了解JDBC API及數(shù)據(jù)庫連接池

前言:上一節(jié)我?guī)Т蠹疑鲜至?a href="http://www.dbjr.com.cn/article/269474.htm" target="_blank">JDBC的基本代碼,這節(jié)我們仔細(xì)講一下JDBC的API和數(shù)據(jù)庫連接池。

JDBC API詳解

DriverManager

DriverManager(驅(qū)動管理類)作用:注冊驅(qū)動、獲取數(shù)據(jù)庫連接

注冊驅(qū)動

registerDriver方法是用于注冊驅(qū)動的,但是我們之前做的入門案例并不是這樣寫的。而是如下實(shí)現(xiàn)

Class.forName("com.mysql.jdbc.Driver");

我們查詢MySQL提供的Driver類,看它是如何實(shí)現(xiàn)的,源碼如下:

static {
try {
DriverManager.registerDriver(new Driver());
}catch (SQLException var1) {
throw new RuntimeException( "can 't register driver! ");
}
}

在該類中的靜態(tài)代碼塊中已經(jīng)執(zhí)行了 DriverManager 對象的registerDriver() 方法進(jìn)行驅(qū)動的注冊了,那么我們只需要加載 Driver 類,該靜態(tài)代碼塊就會執(zhí)行。而Class.forName("com.mysql.jdbc.Driver"); 就可以加載Driver 類。

提示:MySQL 5之后的驅(qū)動包,可以省略注冊驅(qū)動的步驟,自動加載jar包中META-INF/services/java.sql.Driver文件中的驅(qū)動類

獲取數(shù)據(jù)庫連接

參數(shù)說明:

  • user :用戶名
  • password:密碼
  • url : 連接路徑

語法:

jdbc:mysql://ip地址(域名):端口號/數(shù)據(jù)庫名稱?參數(shù)鍵值對1&參數(shù)鍵值對2…

示例:
jdbc:mysql://localhost:3306/jdbc

補(bǔ)充:

  • 如果連接的是本機(jī)mysql服務(wù)器,并且mysql服務(wù)默認(rèn)端口是3306,則url可以簡寫為:jdbc:mysql:///數(shù)據(jù)庫名稱?參數(shù)鍵值對
  • 配置 useSSL=false 參數(shù),禁用安全連接方式,解決警告提示

Connection

Connection(數(shù)據(jù)庫連接對象)作用:獲取執(zhí)行 SQL 的對象、管理事務(wù)

獲取執(zhí)行對象

普通執(zhí)行SQL對象

Statement createStatement()

入門案例中就是通過該方法獲取的執(zhí)行對象。

預(yù)編譯SQL的執(zhí)行SQL對象:防止SQL注入(重要?。。。?/p>

PreparedStatement prepareStatement(sql)

執(zhí)行存儲過程的對象

CallableStatement prepareCall(sql)

事務(wù)管理

回顧一下MySQL事務(wù)管理的操作:

開啟事務(wù) :

BEGIN; 
或者 
START TRANSACTION;

提交事務(wù) :

COMMIT;

回滾事務(wù) :

ROLLBACK;

MySQL默認(rèn)是自動提交事務(wù)

JDBC事務(wù)管理的方法

Connection幾口中定義了3個對應(yīng)的方法:

開啟事務(wù)

參與autoCommit 表示是否自動提交事務(wù),true表示自動提交事務(wù),false表示手動提交事務(wù)。而開啟事務(wù)需要將該參數(shù)設(shè)為為false。

提交事務(wù)

回滾事務(wù)

案例測試事務(wù)管理

編寫代碼

package com.bby;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class JdbcTransaction {
    public static void main(String[] args) throws Exception {
        String url = "jdbc:mysql:///jdbc?useSSL=false";
        String username = "root";
        String password = "1234";
        String sql = "update acount set money = 1002 where id = 1";
        String sql2 = "update acount set money = 1002 whe id = 1"; //注意這里SQL語句故意將where寫錯
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = DriverManager.getConnection(url, username, password);
        Statement statement = connection.createStatement();
        try {
            connection.setAutoCommit(false); // 開啟手動事務(wù)
            //執(zhí)行SQL語句并處理結(jié)果
            int count = statement.executeUpdate(sql);
            System.out.println(count);
            int count2 = statement.executeUpdate(sql2);
            System.out.println(count2);
            //提交事務(wù)
            connection.commit();
        } catch (Exception e) {
            //程序出現(xiàn)異常,回滾事務(wù)
            connection.rollback();
            e.printStackTrace();
        }        
    }
}

執(zhí)行程序,看控制臺結(jié)果

數(shù)據(jù)庫更新前

數(shù)據(jù)庫更新后

這里程序出現(xiàn)異常,進(jìn)行了事務(wù)的回滾,所以數(shù)據(jù)都沒有被更新

將代碼更改正確

String sql2 = "update acount set money = 1002 wher id = 2";

執(zhí)行程序測試

Statement

概述

Statement對象的作用就是用來執(zhí)行SQL語句。而針對不同類型的SQL語句使用的方法也不一樣。

執(zhí)行DDL、DML語句

執(zhí)行DQL語句

代碼演示

此處只展示核心代碼,具體代碼可以參考上面的代碼案例

DML語句

// 定義sql
String sql = "update account set money = 3000 where id = 1";
// 獲取執(zhí)行sql的對象 Statement
Statement stmt = conn.createStatement();
// 執(zhí)行sql
int count = stmt.executeUpdate(sql);  //執(zhí)行完DML語句,受影響的行數(shù) 

執(zhí)行DDL語句

// 定義sql
String sql = "drop database db2";
// 獲取執(zhí)行sql的對象 Statement
Statement stmt = conn.createStatement();
// 執(zhí)行sql
int count = stmt.executeUpdate(sql); //執(zhí)行完DDL語句,可能是0

ResultSet

概述

ResultSet(結(jié)果集對象)作用:封裝了SQL查詢語句的結(jié)果

執(zhí)行了DQL語句后就會返回該對象,對應(yīng)執(zhí)行DQL語句的方法如下:

ResultSet executeQuery(sql):執(zhí)行DQL 語句,返回 ResultSet 對象

那么我們就需要從 ResultSet 對象中獲取我們想要的數(shù)據(jù)。ResultSet 對象提供了操作查詢結(jié)果數(shù)據(jù)的方法,如下:

如下圖為執(zhí)行SQL語句后的結(jié)果

一開始光標(biāo)指定于第一行前,如圖所示紅色箭頭指向于表頭行。當(dāng)我們調(diào)用了 next() 方法后,光標(biāo)就下移到第一行數(shù)據(jù),并且方法返回true,此時就可以通過 getInt(“id”) 獲取當(dāng)前行id字段的值,也可以通過 getString(“name”) 獲取當(dāng)前行name字段的值。如果想獲取下一行的數(shù)據(jù),繼續(xù)調(diào)用 next() 方法,以此類推。

代碼演示

編寫JdbcResultSet

package com.bby;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JdbcResultSet {
    public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3306/jdbc?useSSL=false";
        String username = "root";
        String password = "1234";
        Connection connection = DriverManager.getConnection(url, username, password);
        Statement statement = connection.createStatement();
        //定義查詢的SQL語句
        String sql = "select * from acount";
        //執(zhí)行查詢語句,獲取結(jié)果集
        ResultSet resultSet = statement.executeQuery(sql);
        //遍歷結(jié)果集
        while(resultSet.next()){
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            String money = resultSet.getString("money");
            System.out.println("id:" + id);
            System.out.println("name:" + name);
            System.out.println("money:" + money);
            System.out.println("-----------------");
        }
        resultSet.close();
        statement.close();
        connection.close();
    }
}

查看控制臺輸出

PreparedStatement

SQL注入

SQL注入是通過操作輸入來修改事先定義好的SQL語句,用以達(dá)到執(zhí)行代碼對服務(wù)器進(jìn)行攻擊的方法。

代碼模擬SQL注入問題

package com.bby;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JdbcSqlInjection {
    public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3306/jdbc?useSSL=false";
        String username = "root";
        String password = "1234";
        Connection connection = DriverManager.getConnection(url, username, password);
        // 接收用戶輸入 用戶名和密碼
        String name = "abcdefg";
        String pwd = "' or '1' = '1";
        String sql = "select * from users where name = '" + name + "' and password = '" + pwd + "'";
        Statement statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery(sql);
        // 判斷登錄是否成功
        if (resultSet.next()) {
            System.out.println("登錄成功~");
        } else {
            System.out.println("登錄失敗~");
        }
        resultSet.close();
        statement.close();
        connection.close();
    }
}

上面代碼是將用戶名和密碼拼接到sql語句中,拼接后的sql語句如下:

select * from users where name = 'abcdefg' and password = '' or '1' = '1'

從上面語句可以看出條件name = 'abcdefg' and password = ''不管是否滿足,而 or 后面的 '1' = '1' 是始終滿足的,最終條件是成立的,就可以正常的進(jìn)行登陸了。

所以不管登錄的密碼是否正確都可以登錄成功,控制臺輸出如下

PreparedStatement 概述

PreparedStatement作用:預(yù)編譯SQL語句并執(zhí)行,預(yù)防SQL注入問題

獲取 PreparedStatement 對象

// SQL語句中的參數(shù)值,使用?占位符替代
String sql = "select * from users where name = ? and password = ?";
// 通過Connection對象獲取,并傳入對應(yīng)的sql語句
PreparedStatement ps = connection.prepareStatement(sql);

設(shè)置參數(shù)值

上面的sql語句中參數(shù)使用 ? 進(jìn)行占位,在之前之前肯定要設(shè)置這些 ? 的值。

PreparedStatement對象:

setXxx(參數(shù)1,參數(shù)2);//給 ? 賦值, 參數(shù)1是編號(從1開始) 參數(shù)2是值

(1)Xxx:數(shù)據(jù)類型 ; 如 setInt (參數(shù)1,參數(shù)2)

(2)參數(shù)1: ?的位置編號,從1 開始 參數(shù)2: ?的值

執(zhí)行SQL語句

executeUpdate(); // 執(zhí)行DDL語句和DML語句
executeQuery(); // 執(zhí)行DQL語句

注意:調(diào)用這兩個方法時不需要傳遞SQL語句,因?yàn)楂@取SQL語句執(zhí)行對象時已經(jīng)對SQL語句進(jìn)行預(yù)編譯了。

代碼演示

編寫JdbcPreparedStatement

package com.bby;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class JdbcPreparedStatement {
    public static void main(String[] args) throws Exception {
        String url = "jdbc:mysql:///jdbc?useSSL=false";
        String username = "root";
        String password = "1234";
        String name = "abcdefg";
        String pwd = "' or '1' = '1";
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = DriverManager.getConnection(url, username, password);
        //定義SQL語句
        String sql = "select * from users where name = ? and password = ?";
        //預(yù)編譯SQL語句
        PreparedStatement ps = connection.prepareStatement(sql);
        //填充占位符
        ps.setString(1, name);
        ps.setString(2, pwd);
        //執(zhí)行SQL語句
        ResultSet resultSet = ps.executeQuery();
        //判斷登錄是否成功
        if(resultSet.next()) {
            System.out.println("登陸成功!");
        } else {
            System.out.println("登錄失敗");
        }
        resultSet.close();
        ps.close();
        connection.close();
    }
}

查看控制臺結(jié)果

執(zhí)行上面語句就可以發(fā)現(xiàn)不會出現(xiàn)SQL注入漏洞問題了。那么PreparedStatement又是如何解決的呢?它是將特殊字符進(jìn)行了轉(zhuǎn)

義,轉(zhuǎn)義的SQL如下:

select * from `users` where name = 'abcdefg' and password = '\'or \'1\' = \'1'

PreparedStatement原理

PreparedStatement 好處:1.預(yù)編譯SQL,性能更高。2.防止SQL注入:將敏感字符進(jìn)行轉(zhuǎn)義

Java代碼操作數(shù)據(jù)庫流程如圖所示:

將sql語句發(fā)送到MySQL服務(wù)器端

MySQL服務(wù)端會對sql語句進(jìn)行如下操作

檢查SQL語句

檢查SQL語句的語法是否正確。

編譯SQL語句。將SQL語句編譯成可執(zhí)行的函數(shù)。

檢查SQL和編譯SQL花費(fèi)的時間比執(zhí)行SQL的時間還要長。如果我們只是重新設(shè)置參數(shù),那么檢查SQL語句和編譯SQL語句將不需要重復(fù)執(zhí)行。這樣就提高了性能。

執(zhí)行SQL語句

MySQL服務(wù)端將結(jié)果返回

數(shù)據(jù)庫連接池

數(shù)據(jù)庫連接池簡介

  • 數(shù)據(jù)庫連接池是個容器,負(fù)責(zé)分配、管理數(shù)據(jù)庫連接(Connection)
  • 它允許應(yīng)用程序重復(fù)使用一個現(xiàn)有的數(shù)據(jù)庫連接,而不是再重新建立一個;
  • 釋放空閑時間超過最大空閑時間的數(shù)據(jù)庫連接來避免因?yàn)闆]有釋放數(shù)據(jù)庫連接而引起的數(shù)據(jù)庫連接遺漏
  • 好處:資源重用、提升系統(tǒng)響應(yīng)速度、避免數(shù)據(jù)庫連接遺漏

之前我們代碼中使用連接使沒有使用都創(chuàng)建一個Connection對象,使用完畢就會將其銷毀。這樣重復(fù)創(chuàng)建銷毀的過程是特別耗費(fèi)計(jì)算機(jī)的性能的及消耗時間的。而數(shù)據(jù)庫使用了數(shù)據(jù)庫連接池后,就能達(dá)到Connection對象的復(fù)用,如下圖:

連接池是在一開始就創(chuàng)建好了一些連接(Connection)對象存儲起來。用戶需要連接數(shù)據(jù)庫時,不需要自己創(chuàng)建連接,而只需要從連

接池中獲取一個連接進(jìn)行使用,使用完畢后再將連接對象歸還給連接池;這樣就可以起到資源重用,也節(jié)省了頻繁創(chuàng)建連接銷毀連接

所花費(fèi)的時間,從而提升了系統(tǒng)響應(yīng)的速度。

數(shù)據(jù)庫連接池實(shí)現(xiàn)

標(biāo)準(zhǔn)接口:DataSource

官方(SUN) 提供的數(shù)據(jù)庫連接池標(biāo)準(zhǔn)接口,由第三方組織實(shí)現(xiàn)此接口。該接口提供了獲取連接的功能:

Connection getConnection()

那么以后就不需要通過 DriverManager 對象獲取 Connection對象,而是通過連接池(DataSource)獲取 Connection 對象。

常見的數(shù)據(jù)庫連接池:DBCP 、C3P0 、Druid

我們現(xiàn)在使用更多的是Druid,它的性能比其他兩個會好一些

Druid(德魯伊)

Druid連接池是阿里巴巴開源的數(shù)據(jù)庫連接池項(xiàng)目,功能強(qiáng)大,性能優(yōu)秀,是Java語言最好的數(shù)據(jù)庫連接池之一

Driud 的使用

導(dǎo)入jar包 druid-1.1.12.jar

將druid的jar包放到項(xiàng)目下的lib下并添加為庫文件

編寫配置文件 druid.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///jdbc
useSSL=false&useServerPrepStmts=true
username=root
password=1234
# 初始化連接數(shù)量
initialSize=5
# 最大連接數(shù)
maxActive=10
# 最大等待時間
maxWait=3000

編寫Java代碼(JdbcDruid)

package com.bby;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;
public class JdbcDruid {
    public static void main(String[] args) throws Exception {
        // 加載配置文件
        Properties prop = new Properties();
        prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
        // 獲取連接池對象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
        // 獲取數(shù)據(jù)庫連接 Connection
        Connection connection = dataSource.getConnection();
        System.out.println(connection); //獲取到了連接后就可以繼續(xù)做其他操作了
    }
}

運(yùn)行查看控制臺結(jié)果

到此這篇關(guān)于Java JDBC API介紹與實(shí)現(xiàn)數(shù)據(jù)庫連接池流程的文章就介紹到這了,更多相關(guān)Java JDBC API內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 如何解決@NotBlank不生效的問題

    如何解決@NotBlank不生效的問題

    這篇文章主要介紹了如何解決@NotBlank不生效的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 詳解Java?Synchronized的實(shí)現(xiàn)原理

    詳解Java?Synchronized的實(shí)現(xiàn)原理

    談到多線程就不得不談到Synchronized,重要性不言而喻,今天主要談?wù)凷ynchronized的實(shí)現(xiàn)原理。文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2022-09-09
  • Java 如何使用JDBC連接數(shù)據(jù)庫

    Java 如何使用JDBC連接數(shù)據(jù)庫

    這篇文章主要介紹了Java 如何使用JDBC連接數(shù)據(jù)庫,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-02-02
  • Java面試必考之如何在項(xiàng)目中優(yōu)雅的拋出異常

    Java面試必考之如何在項(xiàng)目中優(yōu)雅的拋出異常

    這篇文章主要為大家詳細(xì)介紹了Java中的幾種異常關(guān)鍵字和異常類相關(guān)知識,本文比較適合剛?cè)肟覬ava的小白以及準(zhǔn)備秋招的大佬閱讀,需要的可以收藏一下
    2023-06-06
  • java+mysql實(shí)現(xiàn)圖書館管理系統(tǒng)實(shí)戰(zhàn)

    java+mysql實(shí)現(xiàn)圖書館管理系統(tǒng)實(shí)戰(zhàn)

    這篇文章主要為大家詳細(xì)介紹了java+mysql實(shí)現(xiàn)圖書館管理系統(tǒng)實(shí)戰(zhàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • mybatis之多參數(shù)查詢方式

    mybatis之多參數(shù)查詢方式

    這篇文章主要介紹了mybatis之多參數(shù)查詢方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Elasticsearch(ES)多種查詢方式案例

    Elasticsearch(ES)多種查詢方式案例

    Elasticsearch是一個分布式的RESTful搜索和分析引擎,可讓您輕松地大規(guī)模存儲,搜索和分析,這篇文章主要給大家介紹了關(guān)于Elasticsearch(ES)多種查詢方式的相關(guān)資料,需要的朋友可以參考下
    2023-09-09
  • ActiveMQ基于zookeeper的主從(levelDB Master/Slave)搭建

    ActiveMQ基于zookeeper的主從(levelDB Master/Slave)搭建

    這篇文章主要介紹了ActiveMQ基于zookeeper的主從levelDB Master/Slave搭建,以及Spring-boot下的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • Java經(jīng)典排序算法之冒泡排序代碼實(shí)例

    Java經(jīng)典排序算法之冒泡排序代碼實(shí)例

    這篇文章主要介紹了Java經(jīng)典排序算法之冒泡排序代碼實(shí)例,相鄰兩元素進(jìn)行比較,如過左側(cè)元素大于右側(cè)元素,則進(jìn)行交換,每完成一次循環(huán)就將最大元素排在最后,下一次循環(huán)是將其它的數(shù)進(jìn)行類似操作,需要的朋友可以參考下
    2023-11-11
  • SpringBoot項(xiàng)目啟動打包報(bào)錯類文件具有錯誤的版本 61.0, 應(yīng)為 52.0的解決方法

    SpringBoot項(xiàng)目啟動打包報(bào)錯類文件具有錯誤的版本 61.0, 應(yīng)為 52.0的解決

    這篇文章主要給大家介紹了關(guān)于SpringBoot項(xiàng)目啟動打包報(bào)錯類文件具有錯誤的版本 61.0, 應(yīng)為 52.0的解決方法,文中有詳細(xì)的排查過程和解決方法,通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11

最新評論