詳解JDBC連接數據庫

一、概念

  1. 為了能讓程序操作數據庫,對數據庫中的表進行操作,每一種數據庫都會提供一套連接和操作該數據庫的驅動,而且每種數據庫的驅動都各不相同,例如mysql數據庫使用mysql驅動,oracle數據庫使用oracle驅動,這樣假如我們編寫的程序哪一天想要換數據庫,那樣就會很不方便,因為所有連接數據庫的代碼都要從新編寫。SUN公司為了簡化。統一對數據庫的操作,定義了一套java操作數據庫的標準或者規范,這個規范就是JDBC。

  2.JDBC全稱為:Java Data Base Connectivity(java數據庫連接),它主要由接口組成。我們在開發過程中,只要實現它相應的接口就可以非常進行連接。    

  3.我們在開發JDBC應用時,還需要導入相應的數據庫的驅動jar包,這些驅動jar包是由數據庫公司自己編寫的。

?

二、編寫JDBC應用程序(需要連接數據庫的程序)的前提準備

?  1.首先要確定連接的是哪個數據庫實例,例如在mysql中,我們可以先創建一個庫,然后在庫中新建一張表,在表中插入一些數據,我在這里提供一段在mysql數據庫中創建一個庫,以及表和數據的sql語句,這也是下面連接數據庫后操作的庫和表。

復制代碼
create database test ;     /*創建一個名為Test的數據庫*/
use test;              /*使用該數據庫或者說切換到該數據庫*/
create table book (id int primary key auto_increment,  /*列:id ,類型:int,從0開始,自動增加, 備注:主鍵*/name varchar(40) NOT NULL,        /*列:name ,類型:varchar, 備注:非空*/author varchar(40)NOT NULL,        /*列:author ,類型:varchar, 備注:非空*/prices double NOT NULL            /*列:prices ,類型:double, 備注:非空*/
);        /*新建一張名為book的表*/
/*插入四大名著的數據*/
insert into book(id,name,author,prices) values (null,'西游記','吳承恩',25.00);
insert into book(id,name,author,prices) values (null,'水滸傳','施耐庵',30.00);
insert into book(id,name,author,prices) values (null,'紅樓夢','曹雪芹',35.00);
insert into book(id,name,author,prices) values (null,'三國演義','羅貫中',40.00);
復制代碼

?  2.新建一個java項目,然后把mysql的驅動jar包導入進來,即添加到程序運行的庫中,具體的驅動jar包,我們可以在數據庫的安裝目錄下找到,或者都網上自己下載相對應的數據庫驅動jar包

?

三、連接數據庫操作的步驟解析

  (1)注冊數據庫驅動

? ? 雖然我們剛才在新建java項目的時候將mysql數據庫的驅動jar包導入進來了,但是JBDC不知道這里有一個驅動包,此時我們就需要將這個驅動包交給JBDC去管理,我們可以使用java.sql包下的DriverManager 工具類 提供的registerDriver(Driver driver) 方法來在JDBC中注冊這個數據驅動,這個registerDriver(Driver driver)方法需要一個Driver對象,而這個Driver類本身是JDBC提供的一個接口,我們的驅動里面已經實現了這個接口所以我們只需要寫如下代碼就可以實現注冊數據庫驅動的功能

  

import java.sql.DriverManager; //需要導入的是接口類包
DriverManager.registerDriver(new Driver());

  

  (2)獲取(創建)數據庫的連接

  ?我們注冊好數據庫驅動后,并沒有連接上數據庫,以往,我們不管在CMD窗口下,通過可視化數據庫管理工具操作數據庫時,我們都需要先連接數據庫服務器,java程序連接數據庫也不例外,這里的java程序就相當于客戶端,只有先連接上數據庫服務,才能對數據庫進行操作

客戶端與數據庫所有交互都是通過connection對象完成的,這個對象的常用方法:

     ?createStatement():創建向數據庫發送sql的statement對象。

      prepareStatement(sql) :創建向數據庫發送預編譯sql的

  這里我們可以通過DriverManager 工具類里的getConnection(url,user,password)方法來創建數據庫連接對象,此方法需要傳入三個參數:

????????????? User: 數據庫的用戶名

????????????? Password:用戶密碼

    ???URL:數據庫服務器地址,不同的數據庫的URL寫法不同,我在這里提供三種主流數據庫的URL地址寫法:

        Oracle寫法:jdbc:oracle:thin:@localhost:1521:sid

        SqlServe寫法:jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=sid

        MySql寫法:jdbc:mysql://localhost:3306/sid

        Mysql的url地址的簡寫形式: jdbc:mysql:///sid

        注:后面的sid就是數據庫的實例名稱(使用的數據庫名)

import java.sql.Connection; //導入的是接口類包
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root"); //這里使用的是一個名為test的mysql數據庫,用戶名和密碼都是root

 

  (3)創建傳輸器對象

? 上面我們已經創建了數據庫的連接,已經連上數據庫了,但是如果我們想要操作該數據庫,我們需要用到sql語句,而我們怎樣使用在java程序中使用sql語句來操作數據庫呢,這里我們就需要一個傳輸器對象來傳輸sql語句到數據庫中去執行。上文提到在Connection 類中就有一個createStatement()的方法可以創建一個傳輸器對象

import java.sql.Statement; //導入的是接口類包
Statement stat = conn.createStatement();

? ?

  (4)利用傳輸器對象傳輸sql語句到數據庫中執行操作,將結果用結果集返回

? java.sql.Statement身上有許多傳輸sql語句的方法:其中用的最多的是

    executeQuery(String?sql) :用于向數據發送查詢語句。

    executeUpdate(String?sql):用于向數據庫發送insert、update或delete語句

    execute(String sql):用于向數據庫發送任意sql語句

? ?

import java.sql.ResultSet; //需要導入的接口類包
ResultSet rs =  stat.executeQuery("select * from book"); //傳輸一條查詢語句,查詢book表中所有的元組數據

?

  (5) 遍歷結果集,并獲取查詢對象

? ? ?Jdbc程序中的ResultSet用于代表Sql語句的執行結果。Resultset封裝執行結果時,采用的類似于表格的方式。ResultSet 對象維護了一個指向表格數據行的游標,初始的時候,游標在第一行之前,調用ResultSet.next() 方法,可以使游標指向具體的數據行,進行調用方法獲取該行的數據。

  ResultSet既然用于封裝執行結果的,所以該對象提供的都是用于獲取數據的get方法:

  獲取指定類型的數據,例如:

    getString(int index)

    getString(String columnName)

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

    next():移動到下一行

    Previous():移動到前一行

    absolute(int row):移動到指定行

    beforeFirst():移動resultSet的最前面。

    afterLast() :移動到resultSet的最后面。

while(rs.next()){String name = rs.getString("name");System.out.println(name);
}

?

  (6)關閉連接(先創建的后關閉)

  Jdbc程序運行完后,切記要釋放程序在運行過程中,創建的那些與數據庫進行交互的對象,這些對象通常是ResultSet, Statement和Connection對象。

  特別是Connection對象,它是非常稀有的資源,用完后必須馬上釋放,如果Connection不能及時、正確的關閉,極易導致系統宕機。Connection的使用原則是盡量晚創建,盡量早的釋放。

rs.close(); 
stat.close();
conn.close();

?

  初期完整的源代碼

復制代碼
 1 package jdbcDemo;2 /****************************3  * 初版連接數據庫程序4  **************************/5 import java.sql.Connection;6 import java.sql.DriverManager;7 import java.sql.ResultSet;8 import java.sql.SQLException;9 import java.sql.Statement;
10 //不能導入 java.sql 中的 Driver 接口,要導入驅動jar包中實現該接口的類,只有這要才能注冊相對應的數據庫驅動
11 import com.mysql.jdbc.Driver; 
12 public class JDBCTest {
13     public static void main(String[] args) throws SQLException  {
14         //1.注冊數據庫驅動
15         DriverManager.registerDriver(new Driver());
16         //2.獲取數據庫的連接 
17         Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false", "root", "root");
18         //3.創建傳輸器對象
19         Statement  stat = conn.createStatement();
20         //4.利用傳輸器對象傳輸sql語句到數據庫中執行操作,將結果用結果集返回
21          ResultSet rs =  stat.executeQuery("select * from book");
22         //5.遍歷結果集,并獲取查詢結果
23         while(rs.next()) {
24             String name = rs.getString("name");
25             System.out.println(name);
26         }
27         //6.關閉連接(后開先關)
28         rs.close(); 
29         stat.close();
30         conn.close();
31     }    
32 }
復制代碼

  數據表視圖和運行結果:

    

?

四、初期連接數據庫程序中出現的問題

  ?1--注冊數據庫驅動方法不當導致出現了兩次注冊,程序通用性低

  我們在查看Driver類的源碼中可以看到如下代碼,從第7行代碼中我們可以看到,mysql在Driver類的實現中自己注冊了一次,而我們在程序中又注冊了一次,導致注冊兩次

  我們在注冊驅動時,需要導入mysql驅動jar包中已經實現的Driver類,這樣程序就和具體的數據庫綁定在一起了,程序的通用性就降低了,如果我們想要切換數據庫,還得改動源碼

? ? ??

復制代碼
 1 public class Driver extends NonRegisteringDriver implements java.sql.Driver {2     //3     // Register ourselves with the DriverManager4     //5     static {6         try {7             java.sql.DriverManager.registerDriver(new Driver());8         } catch (SQLException E) {9             throw new RuntimeException("Can't register driver!");
10         }
11     }
復制代碼

  修復方法:

  使用Class.forname()?方法將mysql中已經實現的Driver類加載到程序中來,由于Driver類在實現接口時使用的是靜態代碼塊,而靜態代碼塊只會在類加載的時候執行一次,即保證了數據庫驅動只會被注冊一次,同時不用導入mysql驅驅動里的類包,程序通用性提高

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

  

  2--忽略了程序中可能會拋出的異常(最大的問題)

  我們在執行程序時,它的許多方法的調用都會拋出異常,如果它拋出異常后,沒有做相應的處理(catch 這個異常)那么程序就會中斷執行,Statement對象和Connection對象就沒有被關閉,而我們知道Connection對象,它是非常稀有的資源,用完后必須馬上釋放,如果Connection不能及時、正確的關閉,極易導致系統宕機,所以我們需要保證無論程序中哪一步出現了異常導致程序中斷,連接關閉的代碼都會被執行,此時我們就會想到異常處理中的finally代碼塊,我們可以把異常向上拋出,而是先?try?住然后?catch?異常,最后執行?finally?代碼塊

  修改之后,我們發現每個close() 都提示有異常要處理,此時我們也直接?try/catch?每個異常

  修改后的源代碼:

復制代碼
 1 package jdbcDemo;2 /****************************3  * 修改版連接數據庫程序4  **************************/5 import java.sql.Connection;6 import java.sql.DriverManager;7 import java.sql.ResultSet;8 import java.sql.SQLException;9 import java.sql.Statement;
10 
11 public class JDBCTest {
12     public static void main(String[] args)  {
13         Connection conn = null;
14         Statement stat = null;
15         ResultSet rs = null;
16         try {
17                 //1.注冊數據庫驅動
18                 Class.forName("com.mysql.jdbc.Driver");
19                 //2.獲取數據庫的連接 
20                  conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false", "root", "root");
21                 //3.創建傳輸器對象
22                   stat = conn.createStatement();
23                 //4.利用傳輸器對象傳輸sql語句到數據庫中執行操作,將結果用結果集返回
24                   rs =  stat.executeQuery("select * from book");
25                 //5.遍歷結果集,并獲取查詢結果
26                 while(rs.next()) {
27                     String name = rs.getString("name");
28                     System.out.println(name);
29                 }
30         }catch(Exception e) {
31             e.printStackTrace();
32         }finally {
33             //6.關閉連接(后開先關)
34             try {
35                 rs.close();
36             } catch (SQLException e) {
37                 e.printStackTrace();
38             } 
39             try {
40                 stat.close();
41             } catch (SQLException e) {
42                 e.printStackTrace();
43             }
44             try {
45                 conn.close();
46             } catch (SQLException e) {
47                 e.printStackTrace();
48             }
49         }
50     }    
51 }
復制代碼

?

五、修改后程序中被忽略的異常

  異常問題

  1.由于我們在程序開頭先聲明了三個對象的引用,并且都賦值為null,假如程序在執行到注冊數據庫這一步時就拋出了異常,此時catch 到這個異常 后執行finally 代碼塊,結果發現ResultSet 對象的引用,Connection對象的引用以及Statement對象的引用都是空值,調用這個對象上的方法就會拋出空指針異常

  2.close()這個方法身上也有異常,如果我們不做相應的異常處理,那些對象還是不能被正常關閉

  解決辦法

1---為了防止出現空指針異常,我們可以先判斷哪些對象的引用是否為null,如果不為null,則執行異常處理代碼

2---在每個close()異常處理后在加上一個finally靜態代碼塊,將每個相應對象的引用值置為null,原理是:如果程序執行到close() 方法并拋出了異常,那么最后finally代碼塊執行,給該對象的應用值置為null,由于這個對象沒有任何引用指向它,它就成為了垃圾對象,JVM垃圾回收器就會回收這個對象資源,這個對象也就關閉了

  異常處理完后最終的源代碼:

復制代碼
 1 package jdbcDemo;2 /****************************3  * 無異常版連接數據庫程序4  **************************/5 import java.sql.Connection;6 import java.sql.DriverManager;7 import java.sql.ResultSet;8 import java.sql.SQLException;9 import java.sql.Statement;
10 
11 public class JDBCTest {
12     public static void main(String[] args)  {
13         Connection conn = null;
14         Statement stat = null;
15         ResultSet rs = null;
16         try {
17                 //1.注冊數據庫驅動
18                 Class.forName("com.mysql.jdbc.Driver");
19                 //2.獲取數據庫的連接 
20                  conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false", "root", "root");
21                 //3.創建傳輸器對象
22                   stat = conn.createStatement();
23                 //4.利用傳輸器對象傳輸sql語句到數據庫中執行操作,將結果用結果集返回
24                   rs =  stat.executeQuery("select * from book");
25                 //5.遍歷結果集,并獲取查詢結果
26                 while(rs.next()) {
27                     String name = rs.getString("name");
28                     System.out.println(name);
29                 }
30         }catch(Exception e) {
31             e.printStackTrace();
32         }finally {
33             //6.關閉連接(后開先關)
34             if(rs != null) {
35                     try {
36                         rs.close();
37                     } catch (SQLException e) {
38                         e.printStackTrace();
39                     } finally {
40                         rs = null;
41                     }
42             }
43             if(stat != null) {
44                     try {
45                         stat.close();
46                     } catch (SQLException e) {
47                         e.printStackTrace();
48                     }finally {
49                         stat = null;
50                     }
51             }
52             if(conn != null) {
53                     try {
54                         conn.close();
55                     } catch (SQLException e) {
56                         e.printStackTrace();
57                     }finally {
58                         conn = null;
59                     }
60             }    
61         } //--finally
62     } //--main    
63 }//--class
復制代碼

?

總結:

   這里我只是把所有的異常處理完,但是程序的通用性還不是特別高,因為連接數據庫用到的Driver類名、URL、user以及password 都寫在程序中,我們其實可以寫在一個文本文件中,通過對文件的讀取來獲得每種數據庫特有的連接參數。

  還有就是在實際開發過程中,連接數據庫的程序代碼一般會寫在一個工具類中,我們想要對數據庫中的數據進行操作時,只需要調用這個工具類就可以了,不用每次都寫那么多代碼

  接下來我還會更新一篇如何將數據庫的連接信息保存在文本文件中,然后讀取這個文件來實現連接數據庫的操作,同時我也會將這個程序修改為連接數據庫的一個工具類

轉載于:https://www.cnblogs.com/zhuyeshen/p/10968080.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/248800.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/248800.shtml
英文地址,請注明出處:http://en.pswp.cn/news/248800.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ASP.NET MVC 自定義模型綁定1 - 自動把以英文逗號分隔的 ID 字符串綁定成 Listint...

直接貼代碼了: CommaSeparatedModelBinder.cs using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Web.Mvc;namespace MvcSample.Extensions {public class CommaSeparatedMode…

ZOJ4024 Peak

題意 給出一個數組 判斷這個數組是否形成了一個“山峰” 即中間有個數最大 從第一個數到這個數遞增 從這個數到最后一個數遞減 模擬 從兩端分別以遞增和遞減判斷 看第一個不滿足遞增或遞減的數是否相等并且沒越界就可以了 AC代碼&#xff1a; 1 #include<bits/stdc.h>2 u…

基本數據類型與String之間的轉換

字符串轉基本數據類型 調用基本數據類型對應的包裝類中的方法parseXXX(String)或valueOf(String)即可返回相應基本類型。 基本數據類型轉字符串 一種方法是將基本數據類型與空字符串&#xff08;""&#xff09;連接&#xff08;&#xff09;即可獲得其所對應的字符串…

springmvc跨域問題

1、跨域問題&#xff1a; 按照網上所有的方法試了一遍&#xff0c;都沒跨過去&#xff0c;正在無助之際&#xff0c;使用filter按照下面的方法解決的時候出現了轉機&#xff1a; 添加filter&#xff1a; package com.thc.bpm.filter;import javax.servlet.*; import javax.serv…

柳傳志給年輕人的建議:比起過日子,更要奔日子

改革開放的 40 年&#xff0c;是柳傳志實現人生價值的 40 年。 十一屆三中全會后&#xff0c;伴隨“科學的春天”&#xff0c;迎著改革開放的大潮&#xff0c;柳傳志“下海”了。但他并沒想到&#xff0c;自己選擇的電腦行業&#xff0c;讓他和聯想集團站在了潮頭。 從 1984 年…

成功秀了一波scala spark ML邏輯斯蒂回歸

1、直接上官方代碼&#xff0c;調整過的&#xff0c;方可使用 package com.test import org.apache.spark.{SparkConf, SparkContext} import org.apache.spark.mllib.classification.{LogisticRegressionModel, LogisticRegressionWithLBFGS} import org.apache.spark.mllib.e…

記錄一次查詢log的經歷

一大早發現生產數據庫的基礎資料被刪除。 由于每天都做了差異備份&#xff0c;而且是基礎資料&#xff0c;這樣數據就不會擔心找不回來。 首先通過每天的差異本分文件進行查看數據丟失的大概時間&#xff0c;查到數據丟失是在17晚上備份過后18丟失的。 然后找18號的數據庫執行記…

移動端輪播圖

1. 頁面布局 1.1 頁面框架 <body><div class"box"><div class"tupian"><img src"4.webp" alt""><img src"1.webp" alt""><img src"2.webp" alt""><…

Boost 序列化

原文鏈接&#xff1a; https://blog.csdn.net/qq2399431200/article/details/45621921 1. 編譯器 gcc, boost 1.55 2.1第一個簡單的例子 —— Hello World &#xff0c;將字符串內容歸檔到文本文件中 #include <iostream>#include <fstream>#include <string>…

docker CE 的安裝

一、Docker CE的安裝1.先決條件運行環境&#xff1a;Ubuntu 64位或者其他支持Docker的64位系統運行配置&#xff0c;linux內核版本必須大于 3.10&#xff0c;否則會因為缺少容器運行所需的功能而出錯。 2.在ubuntu下安裝Docker CEUbuntu版本? Cosmic 18.10 ? Bionic 18.04 (…

nodeJS中的異步編程

nodejs 不是單線程 在博客項目中關于異步問題&#xff1a; 1.當用戶添加一條博客時 需要通過post方式向服務器發送數據 后臺獲取用戶以post方式拿到傳送過來的數據 然后存入數據庫&#xff1a; 上面的代碼&#xff1a;創建一個空字符串 當用戶向服務器發送請求時出發data事件將…

day01筆記

linux基本命令的學習&#xff1a; 1.查看主機名hostname 2.修改主機名hostnamectl set-hostname s16ds 3.linux命令提示符 [roots16ds ~]# # 超級用戶的身份提示符 $ 普通用戶的身份提示符4.修改命令提示符 PS1變量控制 [roots16ds ~]# echo $PS1 [\u\h \W]\$PS1[\u\h \w \t]…

angular 路由

1. vscode編輯器快速新建主路由&#xff1a; ng-router注意修改為 根路由為&#xff1a;‘forRoot()’app-route.module.ts;{ path:,redirectTo:/login,pathMatch:full } 當路由為空的時候&#xff0c;會重定向到/login路由&#xff0c;必須加上pathMatch:full 1 import { Rou…

nodeJs 操作數據庫

首先在node中下載mysql包 npm install mysql 連接數據庫 var mysql require(mysql); var con mysql.createConnection({host : localhost,user : root,password : root,database : blog });開啟鏈接 con.connect();執行增刪改查 不同功能創建不同的sql語句即可…

shell字體顏色應用

輸出特效格式控制&#xff1a; \033[0m 關閉所有屬性 \033[1m 設置高亮度 \03[4m 下劃線 \033[5m 閃爍 \033[7m 反顯 \033[8m 消隱 \033[30m -- \033[37m 設置前景色 \033[40m -- \033[47m 設置背景色 光標位置等的格式控制&#xff1a; …

Spring Boot 統一結果封裝

ResultVo, 返回結果對象 Data public class ResultVo<T> {private Integer code;private String message;private T data; }ResultVoUtil, 封裝返回結果 public class ResultVoUtil {public static<T> ResultVo<T> sucess(T data) {ResultVo<T> result…

總結面試題——Javascript

文章目錄1.閉包2.作用域鏈3.JavaScript的原型 原型鏈 有什么特點4.事件代理5.Javascript如何實現繼承6.this對象7.事件模型8.new操作符9.ajax原理10.解決跨域問題11.模塊化開發怎么做12.異步加載js的方式有哪些13.會造成內存泄漏的操作14.XML和JSON的區別15.webpack16.AMD和Com…

js實現替換指定字符后面的內容(包括指定字符)

href 223d啥啥啥d dds word sss 1233;var indexOf href.indexOf(word);len href.substring(indexOf,href.length);&#xff08;包括指定字符串&#xff09; var newHref href.replace(len,替換內容);轉載于:https://www.cnblogs.com/-lin/p/10172503.html

OAuth2.0 知多少

OAuth2.0 知多少 原文:OAuth2.0 知多少1. 引言 周末逛簡書&#xff0c;看了一篇寫的極好的文章&#xff0c;點擊大紅心點贊&#xff0c;就直接給我跳轉到登錄界面了&#xff0c;原來點贊是需要登錄的。 可是沒有我并沒有簡書賬號&#xff0c;一直使用的QQ的集成登錄。下面有一排…

五分鐘帶你摸透 Vue組件及組件通訊

一.組件化開發 組件 (Component) 是 Vue.js 強大的功能之一。組件可以擴展 HTML 元素&#xff0c;封裝可重用的代 碼。在較高層面上&#xff0c;組件是自定義元素&#xff0c;Vue.js 的編譯器為它添加特殊功能。在vue中都是組件化開發的&#xff0c;組件化開發就是把一個完整的…