最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

教程揭秘 | 動力節(jié)點內(nèi)部Java零基礎教學文檔第三篇:JDBC

2023-10-27 09:54 作者:動力節(jié)點  | 我要投稿

接上期后續(xù)

本期分享第三章節(jié)-JDBC

已經(jīng)分享兩章了,大家都跟上了嗎?

跟上的我就不得不說真厲害~

沒跟上的要加油了!

但時間還久,后面要學還有很多~

大家需保持耐心慢慢來

爭取你們學習的速度!

跟上我更新的速度哦~?

今日新篇章

【JDBC】

主要內(nèi)容

1.?JDBC概述

2.?使用JDBC完成添加操作

3.?使用JDBC完成更新和刪除

4.?DBUtils的簡單封裝

5.?使用JDBC完成查詢

6.?使用JDBC完成分頁查詢

7.?常用接口詳解

8.?JDBC批處理

9.?SQL注入問題

10.?事務處理解決轉(zhuǎn)賬問題

11.?連接池

12.?使用反射對DBUtils再次的封裝

13.?BaseDAO的封裝

學習目標

1.?JDBC概述

1.1?什么是JDBC

JDBC(Java DataBase Connectivity)就是Java數(shù)據(jù)庫連接,說白了就是用Java語言來操作數(shù)據(jù)庫。原來我們操作數(shù)據(jù)庫是在控制臺使用SQL語句來操作數(shù)據(jù)庫,JDBC是用Java語言向數(shù)據(jù)庫發(fā)送SQL語句。


1.2?JDBC的原理

早期SUN公司的天才們想編寫一套可以連接天下所有數(shù)據(jù)庫的API,但是當他們剛剛開始時就發(fā)現(xiàn)這是不可完成的任務,因為各個廠商的數(shù)據(jù)庫服務器差異太大了。后來SUN開始與數(shù)據(jù)庫廠商們討論,最終得出的結(jié)論是,由SUN提供一套訪問數(shù)據(jù)庫的規(guī)范(就是一組接口),并提供連接數(shù)據(jù)庫的協(xié)議標準,然后各個數(shù)據(jù)庫廠商會遵循SUN的規(guī)范提供一套訪問自己公司的數(shù)據(jù)庫服務器的API出現(xiàn)。SUN提供的規(guī)范命名為JDBC,而各個廠商提供的,遵循了JDBC規(guī)范的,可以訪問自己數(shù)據(jù)庫的API被稱之為驅(qū)動!


JDBC是接口,而JDBC驅(qū)動才是接口的實現(xiàn),沒有驅(qū)動無法完成數(shù)據(jù)庫連接!每個數(shù)據(jù)庫廠商都有自己的驅(qū)動,用來連接自己公司的數(shù)據(jù)庫。

當然還有第三方公司專門為某一數(shù)據(jù)庫提供驅(qū)動,這樣的驅(qū)動往往不是開源免費的!

1.3?程序員,JDBC,JDBC驅(qū)動的關系及說明

1.3.1?JDBC API

提供者:Sun公司

內(nèi)容:供程序員調(diào)用的接口與類,集成在java.sql和javax.sql包中,如

DriverManager類 ??作用:管理各種不同的JDBC驅(qū)動

Connection接口 ?

Statement接口 ????

ResultSet接口

1.3.2?JDBC 驅(qū)動

提供者:數(shù)據(jù)庫廠商

作用:負責連接各種不同的數(shù)據(jù)庫

1.3.3?Java程序員

?????????JDBC對Java程序員而言是API,對實現(xiàn)與數(shù)據(jù)庫連接的服務提供商而言是接口模型。

1.3.4?三方關系

SUN公司是規(guī)范制定者,制定了規(guī)范JDBC(連接數(shù)據(jù)庫規(guī)范)

數(shù)據(jù)庫廠商微軟、甲骨文等分別提供實現(xiàn)JDBC接口的驅(qū)動jar包

程序員學習JDBC規(guī)范來應用這些jar包里的類。


1.4?總結(jié)

簡單地說,JDBC 可做三件事:與數(shù)據(jù)庫建立連接、發(fā)送 操作數(shù)據(jù)庫的語句并處理結(jié)果。


DriverManager :依據(jù)數(shù)據(jù)庫的不同,管理JDBC驅(qū)動

Connection :負責連接數(shù)據(jù)庫并擔任傳送數(shù)據(jù)的任務 ?

Statement :由 Connection 產(chǎn)生、負責發(fā)送執(zhí)行SQL語句

ResultSet:負責保存Statement執(zhí)行后所產(chǎn)生的查詢結(jié)果

2.?JDBC操作數(shù)據(jù)庫的步驟

2.1?總體步驟

1.?加載一個Driver驅(qū)動

2.?創(chuàng)建數(shù)據(jù)庫連接(Connection)

3.?創(chuàng)建SQL命令發(fā)送器Statement

4.?創(chuàng)建SQL

5.?通過Statement發(fā)送SQL命令并得到結(jié)果

6.?處理SQL結(jié)果(select語句)

7.?關閉數(shù)據(jù)庫資源

ResultSet

Statement

Connection

2.2?詳細步驟

2.2.1?加載驅(qū)動

加載JDBC驅(qū)動是通過調(diào)用方法java.lang.Class.forName(),下面列出常用的幾種數(shù)據(jù)庫驅(qū)動程序加載語句的形式 :

Class.forName(“oracle.JDBC.driver.OracleDriver”);//使用Oracle的JDBC驅(qū)動程序

Class.forName(“com.microsoft.JDBC.sqlserver.SQLServerDriver”);//使用SQL Server的JDBC驅(qū)動程序

Class.forName(“com.ibm.db2.JDBC.app.DB2Driver”);//使用DB2的JDBC驅(qū)動程序

Class.forName("com.mysql.jdbc.Driver");//使用MySql的JDBC驅(qū)動程序

2.2.2?創(chuàng)建數(shù)據(jù)庫連接

與數(shù)據(jù)庫建立連接的方法是調(diào)用DriverManager.getConnection(String url, String user, String password )方法

Connection conn=null;

String url="jdbc:mysql://localhost:3306/whpowernode?useUnicode=true&useSSL=false&charsetUnicode=UTF8";

String user=“root";

String password=“123456";

conn = DriverManager.getConnection(url, user, password);

2.2.3?創(chuàng)建Statement并發(fā)送命令

Statement對象用于將 SQL 語句發(fā)送到數(shù)據(jù)庫中,或者理解為執(zhí)行sql語句

有三種 Statement對象:

Statement:用于執(zhí)行不帶參數(shù)的簡單SQL語句;

PreparedStatement(從 Statement 繼承):用于執(zhí)行帶或不帶參數(shù)的預編譯SQL語句;

CallableStatement(從PreparedStatement 繼承):用于執(zhí)行數(shù)據(jù)庫存儲過程的調(diào)用。


2.2.4?處理ResultSet結(jié)果

ResultSet對象是executeQuery()方法的返回值,它被稱為結(jié)果集,它代表符合SQL語句條件的所有行,并且它通過一套getXXX方法(這些get方法可以訪問當前行中的不同列)提供了對這些行中數(shù)據(jù)的訪問。

ResultSet里的數(shù)據(jù)一行一行排列,每行有多個字段,且有一個記錄指針,指針所指的數(shù)據(jù)行叫做當前數(shù)據(jù)行,我們只能來操作當前的數(shù)據(jù)行。我們?nèi)绻胍〉媚骋粭l記錄,就要使用ResultSet的next()方法 ,如果我們想要得到ResultSet里的所有記錄,就應該使用while循環(huán)。

ResultSet對象自動維護指向當前數(shù)據(jù)行的游標。每調(diào)用一次next()方法,游標向下移動一行。

初始狀態(tài)下記錄指針指向第一條記錄的前面,通過next()方法指向第一條記錄。循環(huán)完畢后指向最后一條記錄的后面。


2.2.5?關閉數(shù)據(jù)庫資源

作為一種好的編程風格,應在不需要Statement對象和Connection對象時顯式地關閉它們。關閉Statement對象和Connection對象的語法形式為:

public void close() throws SQLException

用戶不必關閉ResultSet。當它的 Statement 關閉、重新執(zhí)行或用于從多結(jié)果序列中獲取下一個結(jié)果時,該ResultSet將被自動關閉。

注意:要按先ResultSet結(jié)果集,后Statement,最后Connection的順序關閉資源,因為Statement和ResultSet是需要連接是才可以使用的,所以在使用結(jié)束之后有可能其他的Statement還需要連接,所以不能先關閉Connection。

3.?準備工作

3.1?創(chuàng)建數(shù)據(jù)并創(chuàng)建student表


3.2?創(chuàng)建項目


3.3?創(chuàng)建lib目錄并引入MYSQL驅(qū)動包


3.4?把lib包引入項目環(huán)境



4.?使用JDBC完成添加操作

4.1?步驟

??加載MySQL的JDBC驅(qū)動

??建立數(shù)據(jù)的連接

??創(chuàng)建SQL命令的發(fā)送器

??編寫SQL

??使用SQL命令發(fā)送器發(fā)送SQL命令并得到結(jié)果

??處理結(jié)果

??關閉數(shù)據(jù)庫資源

4.2?代碼

package com.bjpowernode.jdbc;

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

public class Test01Add {
????// 驅(qū)動器路徑
????private static final String DRIVER = "com.mysql.jdbc.Driver";
????//連接數(shù)據(jù)庫地址
????private static final String URL = "jdbc:mysql://localhost:3306/whpowernode?useUnicode=true&useSSL=false&characterEncoding=UTF8";
????//數(shù)據(jù)庫用戶名
????private static final String USER_NAME = "root";
????//數(shù)據(jù)庫密碼
????private static final String USER_PASSWORD = "123456";
????public static void main(String[] args) throws ClassNotFoundException, SQLException {
????????// 加載JDBC訪問Oracle的驅(qū)動
????????Class.forName(DRIVER);
????????// 建立和數(shù)據(jù)庫的連接
????????Connection conn = DriverManager.getConnection(URL, USER_NAME, USER_PASSWORD);
????????// 創(chuàng)建SQL命令發(fā)送器
????????Statement stmt = conn.createStatement();
????????// 使用SQL命令發(fā)送器發(fā)送SQL命令并得到結(jié)果
????????String sql = "insert into student values(1,'小剛',32,'男','湖北省武漢市')";
????????int n = stmt.executeUpdate(sql);
????????// 處理結(jié)果
????????if (n > 0) {
????????????System.out.println("添加成功");
????????} else {
????????????System.out.println("添加失敗");
????????}
????????// 關閉數(shù)據(jù)庫資源
????????stmt.close();
????????conn.close();
????}
}

4.3?URL詳解

4.3.1?為什么要定義URL

Java和MySQL是廠商的,Java程序和MySQL數(shù)據(jù)庫此時不在同一個進程下,此時Java程序需要向MySQL發(fā)送請求。

4.3.2?如何發(fā)送請求呢?

jdbc:mysql://localhost:3306/whpowernode?useUnicode=true&useSSL=false&characterEncoding=UTF-8

使用URL的方式發(fā)送

jdbc 主協(xié)議

mysql 子協(xié)議

localhost MySQL服務器的地址,如果服務器就是我自己的主機,那么定義localhost就可以了

3306 MySQL服務器的端口號

whpowernode MySQL數(shù)據(jù)庫服務器的數(shù)據(jù)庫名稱

useUnicode=true ?Java和MySQL交互使用Unicode編碼

useSSL=false Java和MySQL交互不使用安全層協(xié)議

characterEncoding=UTF-8 Java和MySQL交互的編碼方式為UTF-8 ?【如果不設置會有亂碼的】

4.4?查看數(shù)據(jù)庫


4.4.1?一個URL由哪些部分組成

??協(xié)議://服務器主機:端口/服務器路徑?查詢參數(shù)

??協(xié)議 jdbc:mysql:

??服務器主機 localhost

??端口 3306

??服務器路徑 whpowernode

??參數(shù)useUnicode=true&useSSL=false&characterEncoding=UTF8

5.?使用JDBC完成更新和刪除

5.1?步驟

??加載MySQL的JDBC驅(qū)動

??建立數(shù)據(jù)的連接

??創(chuàng)建SQL命令的發(fā)送器

??編寫SQL

??使用SQL命令發(fā)送器發(fā)送SQL命令并得到結(jié)果

??處理結(jié)果

??關閉數(shù)據(jù)庫資源

5.2?修改代碼

package com.bjpowernode.jdbc;

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

public class Test02Update {
????// 驅(qū)動器路徑
????private static final String DRIVER = "com.mysql.jdbc.Driver";
????//連接數(shù)據(jù)庫地址
????private static final String URL = "jdbc:mysql://localhost:3306/whpowernode?useUnicode=true&useSSL=false&characterEncoding=UTF8";
????//數(shù)據(jù)庫用戶名
????private static final String USER_NAME = "root";
????//數(shù)據(jù)庫密碼
????private static final String USER_PASSWORD = "123456";
????public static void main(String[] args) throws ClassNotFoundException, SQLException {
????????// 加載Oracle的JDBC驅(qū)動
????????Class.forName(DRIVER);
????????// 建立數(shù)據(jù)的連接
????????Connection conn=DriverManager.getConnection(URL, USER_NAME, USER_PASSWORD);
????????// 創(chuàng)建SQL命令的發(fā)送器
????????Statement stat=conn.createStatement();
????????// 編寫SQL
????????String sql="update student set name='小明',age=23,sex='女',address='武漢' where id=1";
????????// 使用SQL命令發(fā)送器發(fā)送SQL命令并得到結(jié)果
????????int res=stat.executeUpdate(sql);
????????// 處理結(jié)果
????????if(res>0){
????????????System.out.println("修改成功");
????????}
????????else{
????????????System.out.println("處理失敗");
????????}
????????// 關閉數(shù)據(jù)庫資源
????????stat.close();
????????conn.close();
????}
}

5.3?刪除代碼

package com.bjpowernode.jdbc;

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

public class Test03Delete {
????// 驅(qū)動器路徑
????private static final String DRIVER = "com.mysql.jdbc.Driver";
????//連接數(shù)據(jù)庫地址
????private static final String URL = "jdbc:mysql://localhost:3306/whpowernode?useUnicode=true&useSSL=false&characterEncoding=UTF8";
????//數(shù)據(jù)庫用戶名
????private static final String USER_NAME = "root";
????//數(shù)據(jù)庫密碼
????private static final String USER_PASSWORD = "123456";
????public static void main(String[] args) throws ClassNotFoundException, SQLException {
????????// 加載Oracle的JDBC驅(qū)動
????????Class.forName(DRIVER);
????????// 建立數(shù)據(jù)的連接
????????Connection conn=DriverManager.getConnection(URL, USER_NAME, USER_PASSWORD);
????????// 創(chuàng)建SQL命令的發(fā)送器
????????Statement stat=conn.createStatement();
????????// 編寫SQL
????????String sql="delete from student where id=1";
????????// 使用SQL命令發(fā)送器發(fā)送SQL命令并得到結(jié)果
????????int res=stat.executeUpdate(sql);
????????// 處理結(jié)果
????????if(res>0){
????????????System.out.println("刪除成功");
????????}
????????else{
????????????System.out.println("刪除失敗");
????????}
????????// 關閉數(shù)據(jù)庫資源
????????stat.close();
????????conn.close();
????}
}

6.?DBUtils的簡單封裝

6.1?為什么要封裝

從我們上面的代碼大家可以看到,每一次寫我們創(chuàng)建一個連接,創(chuàng)建一個發(fā)送SQL的對象,最后還要關閉,那么我們可以考慮把這重復的代碼提取出來!

6.2?創(chuàng)建DBUtils封裝代碼

package com.bjpowernode.utils;

import java.io.Closeable;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBUtils {
????// 驅(qū)動器路徑
????private static final String DRIVER = "com.mysql.jdbc.Driver";
????// 連接數(shù)據(jù)庫地址
????private static final String URL = "jdbc:mysql://localhost:3306/whpowernode?useUnicode=true&useSSL=false&characterEncoding=UTF8";
????// 數(shù)據(jù)庫用戶名
????private static final String USER_NAME = "root";
????// 數(shù)據(jù)庫密碼
????private static final String USER_PASSWORD = "123456";

????/**
?????* 靜態(tài)加載驅(qū)動程序
?????*/
????static {
????????try {
????????????Class.forName(DRIVER);
????????} catch (ClassNotFoundException e) {
????????????e.printStackTrace();
????????}
????}
????/**
?????* @return 連接對象
?????*/
????public static Connection getConn() {
????????try {
????????????return ?DriverManager.getConnection(URL, USER_NAME, USER_PASSWORD);
????????} catch (SQLException e) {
????????????e.printStackTrace();
????????????System.out.println("創(chuàng)建連接對象異常");
????????}
????????return null;
????}

????/**
?????* 關閉資源
?????*/
????public static void close(AutoCloseable closeable) {
????????try {
????????????if (closeable != null) {
????????????????closeable.close();
????????????}
????????} catch (Exception e) {
????????????e.printStackTrace();
????????}
????}
}

6.3?創(chuàng)建上面的工具類對象前面的代碼進行改造

package com.bjpowernode.jdbc;

import com.bjpowernode.utils.DBUtils;

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

public class Test01Add {
????public static void main(String[] args) throws ClassNotFoundException, SQLException {
????????Connection conn = DBUtils.getConn();
????????// 創(chuàng)建SQL命令發(fā)送器
????????Statement stmt = conn.createStatement();
????????// 使用SQL命令發(fā)送器發(fā)送SQL命令并得到結(jié)果
????????String sql = "insert into student values(1,'小剛',32,'男','湖北省武漢市')";
????????int n = stmt.executeUpdate(sql);
????????// 處理結(jié)果
????????if (n > 0) {
????????????System.out.println("添加成功");
????????} else {
????????????System.out.println("添加失敗");
????????}
????????// 關閉數(shù)據(jù)庫資源
????????DBUtils.close(stmt);
????????DBUtils.close(conn);
????}
}

?

7.?使用JDBC完成查詢

7.1?循環(huán)向student表里面插入20條數(shù)

package com.bjpowernode.jdbc;

import com.bjpowernode.utils.DBUtils;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Random;

public class Test01Add20 {
????public static void main(String[] args) throws ClassNotFoundException, SQLException {
????????Connection conn = DBUtils.getConn();
????????// 創(chuàng)建SQL命令發(fā)送器
????????Statement stmt = conn.createStatement();
????????// 使用SQL命令發(fā)送器發(fā)送SQL命令并得到結(jié)果
????????Random random=new Random();
????????for (int i = 1; i <=20 ; i++) {
????????????Integer id=i;
????????????String name="小明"+i;
????????????int age=random.nextInt(100);
????????????String sex=random.nextBoolean()?"男":"女";
????????????String address="武漢"+i;

????????????String sql = "insert into student values("+i+",'"+name+"',"+age+",'"+sex+"','"+address+"')";
????????????int n = stmt.executeUpdate(sql);
????????????// 處理結(jié)果
????????????if (n > 0) {
????????????????System.out.println("添加成功");
????????????} else {
????????????????System.out.println("添加失敗");
????????????}
????????}
????????// 關閉數(shù)據(jù)庫資源
????????DBUtils.close(stmt);
????????DBUtils.close(conn);
????}
}

7.2?查詢

package com.bjpowernode.jdbc;

import com.bjpowernode.utils.DBUtils;

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

public class Test04Query {
????public static void main(String[] args) throws ClassNotFoundException, SQLException {
????????Connection conn = DBUtils.getConn();
????????// 創(chuàng)建SQL命令發(fā)送器
????????Statement stmt = conn.createStatement();
????????// 編寫SQL
????????String sql="select *?from student";
????????// 使用SQL命令發(fā)送器發(fā)送SQL命令并得到結(jié)果
????????ResultSet rs=stmt.executeQuery(sql);
????????// 處理結(jié)果
????????while(rs.next()){
????????????int id=rs.getInt(1);
????????????String name=rs.getString(2);
????????????int age=rs.getInt(3);
????????????String sex=rs.getString(4);
????????????String address=rs.getString(5);
????????????System.out.println(id+" ?"+name+" ?"+age+" ??"+sex+" ??"+address);
????????}
????????// 關閉數(shù)據(jù)庫資源
????????DBUtils.close(rs);
????????DBUtils.close(stmt);
????????DBUtils.close(conn);
????}
}

8.?使用JDBC完成分頁查詢

package com.bjpowernode.jdbc;

import com.bjpowernode.utils.DBUtils;

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

public class Test05QueryForPage {
????public static void main(String[] args) throws ClassNotFoundException, SQLException {
????????Connection conn = DBUtils.getConn();
????????// 創(chuàng)建SQL命令發(fā)送器
????????Statement stmt = conn.createStatement();
????????int pageNum=2; //頁碼
????????int pageSize=5;//每頁顯示的條數(shù)
????????// 編寫SQL
????????String sql="select *?from student limit?"+(pageNum-1)*pageSize+","+pageSize;
????????// 使用SQL命令發(fā)送器發(fā)送SQL命令并得到結(jié)果
????????ResultSet rs=stmt.executeQuery(sql);
????????// 處理結(jié)果
????????while(rs.next()){
????????????int id=rs.getInt(1);
????????????String name=rs.getString(2);
????????????int age=rs.getInt(3);
????????????String sex=rs.getString(4);
????????????String address=rs.getString(5);
????????????System.out.println(id+" ?"+name+" ?"+age+" ??"+sex+" ??"+address);
????????}
????????// 關閉數(shù)據(jù)庫資源
????????DBUtils.close(rs);
????????DBUtils.close(stmt);
????????DBUtils.close(conn);
????}
}

9.?常用接口詳解

9.1?DriverManager

用于管理JDBC驅(qū)動的服務類。程序中使用該類的的主要功能是獲取Connection對象,該類包含如下方法:

public static Connection getConnection(String url, String user, String password) throws SQLException

該方法獲得url對應數(shù)據(jù)庫的連接;

9.2?Connection

代表數(shù)據(jù)庫連接對象,每個Connection代表一個物理連接會話。要想訪問數(shù)據(jù)庫,必須先得到數(shù)據(jù)庫連接。該接口的常用方法如下:

Statement createStatement() throws SQLException; 該方法返回一個Statement對象;

PreparedStatement prepareStatement(String sql)throws SQLException;該方法返回預編譯的Statement對象,即將SQL語句提交到數(shù)據(jù)庫進行預編譯;

CallableStatement prepareCall(String sql) throws SQLException;

該方法返回CallableStatement對象,該對象用于調(diào)用存儲過程。

上面上個方法都返回用于執(zhí)行sql語句的Statement對象,PreparedStatement和CallableStatement是Statement的子類,只有獲得了Statement之后才可以執(zhí)行sql語句;

除此之外,Connection還有如下幾個用于控制事務的方法。

Savepoint setSavepoint() throws SQLException;創(chuàng)建一個保存點;

Savepoint setSavepoint(String name) throws SQLException;以指定名字來創(chuàng)建一個保存點;

void setTransactionIsolation(int level) throws SQLException;設置事務的隔離級別;

void rollback() throws SQLException;回滾事務;

void rollback(Savepoint savepoint) throws SQLException;將事務回滾到指定的保存點;

void setAutoCommit(boolean autoCommit) throws SQLException;關閉自動提交,打開事務;

void commit() throws SQLException;提交事務;

9.3?Statement

用于執(zhí)行sql語句的工具接口。該對象既可以執(zhí)行DDL,DCL語句,也可以用于執(zhí)行DML語句,還可以用于執(zhí)行sql查詢。當執(zhí)行sql查詢時,返回查詢到的結(jié)果集。它的常用方法如下:

ResultSet executeQuery(String sql) throws SQLException;該方法用于執(zhí)行查詢語句,并返回查詢結(jié)果對應ResultSet對象。該方法只能用于執(zhí)行查詢語句。

int executeUpdate(String sql) throws SQLException;該方法用于執(zhí)行DML語句,并返回受影響的行數(shù);該方法也可用于執(zhí)行DDL語句,執(zhí)行DDL語句將返回0;

boolean execute(String sql) throws SQLException;改方法可以執(zhí)行任何sql語句。如果執(zhí)行后第一個結(jié)果為ResultSet對象,則返回true;如果執(zhí)行后第一個結(jié)果為受影響的行數(shù)或沒有任何結(jié)果,則返回false;

9.4?PreparedStatement

預編譯的Statement對象,PreparedStatement是Statement的子接口,它允許數(shù)據(jù)庫預編譯sql語句(這些sql語句通常帶有參數(shù)),以后每次只改變sql命令的參數(shù),避免數(shù)據(jù)庫每次都需要編譯sql語句,無需再傳入sql語句,

只要為預編譯的sql語句傳入?yún)?shù)值即可。所以它比Statement多了如下方法:

void setXxx(int parameterIndex, Xxx value):該方法根據(jù)傳入?yún)?shù)值的類型不同,需要使用不同的方法。傳入的值根據(jù)索引傳給sql語句中指定位置的參數(shù)。

9.5?ResultSet

結(jié)果集對象。該對象包含訪問查詢結(jié)果的方法,ResultSet可以通過列索引或列名獲得列數(shù)據(jù)。它包含了如下常用方法來移動記錄指針。

void close() throws SQLException;釋放ResultSet對象;

boolean absolute( int row ) throws SQLException;將結(jié)果集的記錄指針移動到第row行,如果row是負數(shù),則移動到倒數(shù)第row行,如果移動后的記錄指針指向一條有效記錄,則該方法返回true;

boolean next() throws SQLException;將結(jié)果集的記錄指針定位到下一行,如果移動后的記錄指針指向一條有效的記錄,則該方法返回true;

boolean last() throws SQLException;將結(jié)果集的記錄指針定位到最后一行,如果移動后的記錄指針指向一條有效的記錄,則該方法返回true;

?

10.?SQL注入問題

10.1?問題引入

10.1.1?創(chuàng)建sys_user表并初始化數(shù)據(jù)



10.1.2?編寫代碼實現(xiàn)登陸

package com.bjpowernode.jdbc;

import com.bjpowernode.utils.DBUtils;

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

public class Test06Login {
????public static void main(String[] args) throws ClassNotFoundException, SQLException {
????????Connection conn = DBUtils.getConn();
????????// 創(chuàng)建SQL命令發(fā)送器
????????Statement stmt = conn.createStatement();
????????//從鍵盤輸入
????????Scanner scanner=new Scanner(System.in);
????????System.out.println("請輸入用戶名:");
????????String username = scanner.nextLine();
????????System.out.println("請輸入密碼:");
????????String password=scanner.nextLine();
????????// 編寫SQL
????????String sql="select *?from sys_user where username='"+username+"' and password='"+password+"'";
????????// 使用SQL命令發(fā)送器發(fā)送SQL命令并得到結(jié)果
????????ResultSet rs=stmt.executeQuery(sql);
????????System.out.println(sql);
????????// 處理結(jié)果
????????if(rs.next()){
????????????System.out.println("登陸成功");
????????????int id=rs.getInt(1);
????????????String name=rs.getString(2);
????????????String pwd=rs.getString(3);
????????????System.out.println(id+" ?"+name+" ?"+pwd);
????????}
????????// 關閉數(shù)據(jù)庫資源
????????DBUtils.close(rs);
????????DBUtils.close(stmt);
????????DBUtils.close(conn);
????}
}

10.1.3?測試登陸

10.2?解決辦法【使用PreparedStatement】

10.2.1?技術(shù)原理

該 PreparedStatement接口繼承Statement,并與之在兩方面有所不同:

PreparedStatement 實例包含已編譯的 SQL 語句。這就是使語句“準備好”。包含于 PreparedStatement 對象中的 SQL 語句可具有一個或多個 IN 參數(shù)。IN參數(shù)的值在 SQL 語句創(chuàng)建時未被指定。相反的,該語句為每個 IN 參數(shù)保留一個問號(“?”)作為占位符。每個問號的值必須在該語句執(zhí)行之前,通過適當?shù)膕etXXX 方法來提供。

由于 PreparedStatement 對象已預編譯過,所以其執(zhí)行速度要快于 Statement 對象。因此,多次執(zhí)行的 SQL 語句經(jīng)常創(chuàng)建為 PreparedStatement 對象,以提高效率。

作為 Statement 的子類,PreparedStatement 繼承了 Statement 的所有功能。另外它還添加了一整套方法,用于設置發(fā)送給數(shù)據(jù)庫以取代 IN 參數(shù)占位符的值。同時,三種方法 execute、 executeQuery 和 executeUpdate 已被更改以使之不再需要參數(shù)。這些方法的 Statement 形式(接受 SQL 語句參數(shù)的形式)不應該用于 PreparedStatement 對象。

?

10.2.2?創(chuàng)建對象

以下的代碼段(其中 con 是 Connection 對象)創(chuàng)建包含帶兩個 IN 參數(shù)占位符的 SQL 語句的 PreparedStatement 對象:

PreparedStatement pstmt = con.prepareStatement("UPDATE table4 SET m = ? WHERE x = ?");

pstmt 對象包含語句 "UPDATE table4 SET m = ? WHERE x = ?",它已發(fā)送給DBMS,并為執(zhí)行作好了準備。

?

10.2.3?傳遞參數(shù)

在執(zhí)行 PreparedStatement 對象之前,必須設置每個 ? 參數(shù)的值。這可通過調(diào)用 setXXX 方法來完成,其中 XXX 是與該參數(shù)相應的類型。例如,如果參數(shù)具有Java 類型 long,則使用的方法就是 setLong。setXXX 方法的第一個參數(shù)是要設置的參數(shù)的序數(shù)位置,第二個參數(shù)是設置給該參數(shù)的值。例如,以下代碼將第一個參數(shù)設為 123456789,第二個參數(shù)設為 100000000:

pstmt.setLong(1, 123456789);

pstmt.setLong(2, 100000000);

一旦設置了給定語句的參數(shù)值,就可用它多次執(zhí)行該語句,直到調(diào)用clearParameters 方法清除它為止。在連接的缺省模式下(啟用自動提交),當語句完成時將自動提交或還原該語句。

如果基本數(shù)據(jù)庫和驅(qū)動程序在語句提交之后仍保持這些語句的打開狀態(tài),則同一個 PreparedStatement 可執(zhí)行多次。如果這一點不成立,那么試圖通過使用PreparedStatement 對象代替 Statement 對象來提高性能是沒有意義的。

?

10.2.4?修改代碼

package com.bjpowernode.jdbc;

import com.bjpowernode.utils.DBUtils;

import java.sql.*;
import java.util.Scanner;

public class Test07Login {
????public static void main(String[] args) throws ClassNotFoundException, SQLException {
????????//從鍵盤輸入
????????Scanner scanner=new Scanner(System.in);
????????System.out.println("請輸入用戶名:");
????????String username = scanner.nextLine();
????????System.out.println("請輸入密碼:");
????????String password=scanner.nextLine();
????????Connection conn = DBUtils.getConn();
????????// 編寫SQL
????????String sql="select *?from sys_user where username=? and password=? ";
????????System.out.println(sql);
????????// 創(chuàng)建SQL命令發(fā)送器
????????PreparedStatement pstmt = conn.prepareStatement(sql);
????????pstmt.setString(1,username);
????????pstmt.setString(2,password);
????????// 使用SQL命令發(fā)送器發(fā)送SQL命令并得到結(jié)果
????????ResultSet rs=pstmt.executeQuery();
????????// 處理結(jié)果
????????if(rs.next()){
????????????System.out.println("登陸成功");
????????????int id=rs.getInt(1);
????????????String name=rs.getString(2);
????????????String pwd=rs.getString(3);
????????????System.out.println(id+" ?"+name+" ?"+pwd);
????????}
????????// 關閉數(shù)據(jù)庫資源
????????DBUtils.close(rs);
????????DBUtils.close(pstmt);
????????DBUtils.close(conn);
????}
}

10.2.5?再次測試


11.?1事務處理解決轉(zhuǎn)賬問題

11.1?什么是事務

是數(shù)據(jù)庫操作的最小工作單元,是作為單個邏輯工作單元執(zhí)行的一系列操作;這些操作作為一個整體一起向系統(tǒng)提交,要么都執(zhí)行、要么都不執(zhí)行;事務是一組不可再分割的操作集合(工作邏輯單元)

11.2?事務的四大特性:

11.2.1?原子性

事務是數(shù)據(jù)庫的邏輯工作單位,事務中包含的各操作要么都做,要么都不做

11.2.2?一致性

事 務執(zhí)行的結(jié)果必須是使數(shù)據(jù)庫從一個一致性狀態(tài)變到另一個一致性狀態(tài)。因此當數(shù)據(jù)庫只包含成功事務提交的結(jié)果時,就說數(shù)據(jù)庫處于一致性狀態(tài)。如果數(shù)據(jù)庫系統(tǒng) 運行中發(fā)生故障,有些事務尚未完成就被迫中斷,這些未完成事務對數(shù)據(jù)庫所做的修改有一部分已寫入物理數(shù)據(jù)庫,這時數(shù)據(jù)庫就處于一種不正確的狀態(tài),或者說是 不一致的狀態(tài)。

11.2.3?隔離性

一個事務的執(zhí)行不能其它事務干擾。即一個事務內(nèi)部的操作及使用的數(shù)據(jù)對其它并發(fā)事務是隔離的,并發(fā)執(zhí)行的各個事務之間不能互相干擾。

11.2.4?持久性

也稱永久性,指一個事務一旦提交,它對數(shù)據(jù)庫中的數(shù)據(jù)的改變就應該是永久性的。接下來的其它操作或故障不應該對其執(zhí)行結(jié)果有任何影響。

11.3?需求描述

完成轉(zhuǎn)賬操作

要求,兩次數(shù)據(jù)庫操作,要么全成功。要么全失敗

11.4?準備工作

11.4.1?創(chuàng)建表

CREATE TABLE account

(

????aid INT PRIMARY KEY AUTO_INCREMENT,

????aname VARCHAR(30) NOT NULL,

????amount ?DECIMAL(10,2) NOT NULL

);

11.4.2?初始化數(shù)據(jù)

11.5?代碼實現(xiàn)

package com.bjpowernode.jdbc;

import com.bjpowernode.utils.DBUtils;

import java.sql.*;
import java.util.Scanner;

public class Test08Transaction {
????public static void main(String[] args) {
????????//聲明連接對象
????????Connection conn=null;
????????//聲明發(fā)送SQL的接口對象
????????Statement stmt=null;
????????try {
????????????//創(chuàng)建連接對象
????????????conn = DBUtils.getConn();
????????????// 關閉自動提交事務
????????????conn.setAutoCommit(false);
????????????// 編寫SQL
????????????String sql1 = "update account set amount = amount-1000 where aid=1";
????????????String sql2 = "update account set amount = amount+1000 where aid=2";
????????????// 創(chuàng)建SQL命令發(fā)送器
????????????stmt = conn.createStatement();
????????????stmt.executeUpdate(sql1);
????????????stmt.executeUpdate(sql2);
????????????????????}catch (Exception e){
????????????e.printStackTrace();
????????????try {
????????????????conn.rollback();
????????????} catch (SQLException e1) {
????????????????e1.printStackTrace();
????????????}
????????}finally {

conn.commit();

????????????// 關閉數(shù)據(jù)庫資源
????????????DBUtils.close(stmt);
????????????DBUtils.close(conn);
????????}

????}
}

?

11.6?測試

在兩個執(zhí)行的sql中間模擬異常,看事務是否會提交

?

?

12.?JDBC批處理

12.1?什么是批處理

批處理是建立一次連接(創(chuàng)建一個Connection對象)的情況下批量執(zhí)行多個DML語句,這些DML語句要么全部成功要么全部失敗。如何確保全部成功or全部失敗呢?在JDBC中開啟事務,使用事務管理DML語句。

12.2?需求描述及操作步驟

使用批處理根據(jù)id批量的刪除student表中的數(shù)據(jù)

1 定義SQL配置文件

2 創(chuàng)建Connection對象

3 創(chuàng)建PreparedStatement對象

4 將提交方式設置為手動提交,開啟事務

5 設置占位符

6 將占位符添加到批處理中(相當于收集若干個本子,放入包包中)

7 執(zhí)行批處理

8 提交事務

9 如果批處理失敗,在catch塊中回滾事務

10 關閉資源

12.3?案列代碼

package com.bjpowernode.jdbc;

import com.bjpowernode.utils.DBUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.List;

public class Test09Batch {
????public static void main(String[] args) {
????????//模擬要刪除的數(shù)據(jù)
????????List<Integer> ids= Arrays.asList(1,2,3,4,5);
????????//聲明連接對象
????????Connection conn=null;
????????//聲明發(fā)送SQL的接口對象
????????PreparedStatement pstmt=null;
????????try {
????????????//創(chuàng)建連接對象
????????????conn = DBUtils.getConn();
????????????// 關閉自動提交事務
????????????conn.setAutoCommit(false);
????????????// 編寫SQL
????????????String sql = "delete from student where id = ?;";
????????????// 創(chuàng)建SQL命令發(fā)送器
????????????pstmt = conn.prepareStatement(sql);
????????????for (Integer id : ids) {
????????????????pstmt.setInt(1,id);
????????????????pstmt.addBatch();
????????????}
????????????int[] rows = pstmt.executeBatch();
????????????System.out.println("受影響的行數(shù)為:"+Arrays.toString(rows));
????????????conn.commit();
????????}catch (Exception e){
????????????e.printStackTrace();
????????????try {
????????????????conn.rollback();
????????????} catch (SQLException e1) {
????????????????e1.printStackTrace();
????????????}
????????}finally {
????????????// 關閉數(shù)據(jù)庫資源
????????????DBUtils.close(pstmt);
????????????DBUtils.close(conn);
????????}

????}
}

13.?數(shù)據(jù)庫連接池

13.1?什么是連接池

連接池是創(chuàng)建和管理一個連接的緩沖池的技術(shù),這些連接準備好被任何需要它們的線程使用。

連接池是裝有連接的容器,使用連接的話,可以從連接池中進行獲取,使用完成之后將連接歸還給連接池。

13.2?為什么使用連接池

連接對象創(chuàng)建和銷毀是需要耗費時間的,在服務器初始化的時候就初始化一些連接。把這些連接放入到內(nèi)存中,使用的時候可以從內(nèi)存中獲取,使用完成之后將連接放入連接池中。從內(nèi)存中獲取和歸還的效率要遠遠高于創(chuàng)建和銷毀的效率。(提升性能)。

13.3?連接池的工作原理

13.4?市面上有哪些可用的連接池

??c3p0 ?老了

??druid 阿里的

??dbcp 老了

??Hikari ?小日本的,springboot官方推薦的

14.?BaseDAO的封裝難點

14.1?概述 husband------------------------->Husband(List<T> 、T)

對于JDBC市面上有一些封裝的非常好的ORM(對象關系映射)框架,如mybatis ?mybatis plus hibernate,但是我們現(xiàn)在還沒有學到框架,如何自己做模擬一個ORM的框架呢,接下來我們來講解BaseDAO的封裝和使用

?

14.2?代碼

package com.bjpowernode.dao.impl;

import com.bjpowernode.utils.DBUtils;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;


public class BaseDao {

????/**
?????* @param sql ???sql 指令
?????* @param clss ??orm關聯(lián)類
?????* @param params sql中占位符 對應的參數(shù)
?????* @param <T>
?????* @return
?????* @throws Exception
?????*/
????public ?<T> List<T> selectList(String sql, Class<T> clss, Object... params) ?{
????????//創(chuàng)建一個空容器 ?規(guī)避空指針異常問題
????????List<T> data = new ArrayList<>(); // 需要改動
????????//2. 創(chuàng)建連接 使用驅(qū)動管理器 創(chuàng)建連接
????????Connection conn = DBUtils.getConnection();
????????//4. 獲取指令的指令對象
????????PreparedStatement prep = null;
????????ResultSet rs = null;
????????try {
????????????//4. 獲取指令的指令對象
????????????prep = conn.prepareStatement(sql);
????????????//設置預編譯參數(shù)
????????????for (int i = 0; i < params.length; i++) {
????????????????Object param = params[i]; //獲取參數(shù)
????????????????//設置參數(shù)
????????????????prep.setObject(i + 1, param);
????????????}
????????????//5. 執(zhí)行指令
????????????rs = prep.executeQuery();
????????????//獲取結(jié)果的元信息
????????????ResultSetMetaData metaData = rs.getMetaData();
????????????//獲取列數(shù)
????????????int columnCount = metaData.getColumnCount();
????????????//遍歷結(jié)果
????????????while (rs.next()) {
????????????????T t = clss.newInstance();
????????????????for (int i = 0; i < columnCount; i++) {
????????????????????//獲取別名 ?也是屬性名
????????????????????String columnLabel = metaData.getColumnLabel(i + 1);
????????????????????//根據(jù)別名獲取值
????????????????????Object columnValue = rs.getObject(columnLabel);
????????????????????//獲取屬性
????????????????????Field field = clss.getDeclaredField(columnLabel); //需要改動
????????????????????//設置屬性值
????????????????????field.setAccessible(true);
????????????????????field.set(t, columnValue);
????????????????}
????????????????data.add(t);//放入list
????????????}
????????}catch (Exception e){
????????????e.printStackTrace();
????????}finally {
????????????DBUtils.close(conn);
????????????DBUtils.close(prep);
????????????DBUtils.close(rs);
????????}
????????return data;
????}


????/**
?????* 查詢單個對象
?????*
?????* @param sql
?????* @param clss
?????* @param params
?????* @param <T>
?????* @return
?????* @throws Exception
?????*/
????public ?<T> T selectOne(String sql, Class<T> clss, Object... params) ?{
????????List<T> list = selectList(sql, clss, params);
????????if (!list.isEmpty() && list.size() == 1) {
????????????return list.get(0);
????????}
????????return null;
????}

????/**
?????* 通用的更新操作
?????* @param sql
?????* @param params
?????* @return
?????*/
????public ?boolean update(String sql, Object... params) {
????????//1. 獲取連接
????????Connection conn = DBUtils.getConnection();
????????PreparedStatement prep = null;
????????try {
????????????prep = conn.prepareStatement(sql);
????????????//設置預編譯參數(shù)
????????????for (int i = 0; i < params.length; i++) {
????????????????Object param = params[i]; //獲取參數(shù)
????????????????//設置參數(shù)
????????????????prep.setObject(i + 1, param);
????????????}
????????????//執(zhí)行sql指令
????????????int m = prep.executeUpdate();

????????????return m >= 1;
????????} catch (SQLException throwables) {
????????????throwables.printStackTrace();
????????}finally {
????????????DBUtils.close(conn);
????????????DBUtils.close(prep);
????????}
????????return ?false;
????}
}

14.3?使用

package com.bjpowernode.dao.impl;


public class UserDao ?extends BaseDao{
????/**
?????* 根據(jù)用戶名 和 密碼查詢用戶
?????* @param username
?????* @param password
?????* @return
?????*/
????public User selectUser(String username,String password){
????????String sql = "select ?`id`, `username`, `password`, `realname`, `role`, `deleted`, `img`, `create_time` as createTime, `modify_time` as modifyTime, `deleted_time` as deletedTime from user where username = ? and password=?";
????????User user = super.selectOne(sql, User.class, username, password);
????????return user;
????};

????public void updateState(String id, Integer delete) {
????????String sql = "update user set deleted = ??,deleted_time = now() where id = ?";
????????super.update(sql,delete,id);
????}
}

14.4?分頁封裝

14.4.1?創(chuàng)建分頁結(jié)果封裝類PageInfo<T>

package com.bjpowernode.common;

import java.util.List;


public class PageInfo<T> {

????private List<T> data;// 具體的數(shù)據(jù)
????private Long count; //符合條件的數(shù)據(jù)條數(shù)


????public List<T> getData() {
????????return data;
????}

????public void setData(List<T> data) {
????????this.data = data;
????}

????public Long getCount() {
????????return count;
????}

????public void setCount(Long count) {
????????this.count = count;
????}
}

14.4.2?修改BaseDao

/**
?* 分頁的封裝
?* @param sql
?* @param cls
?* @param page
?* @param limit
?* @param <T>
?* @return
?*/
protected <T> PageInfo<T> selectPage(String sql, Class<T> cls, String page, String limit) {
????//查詢符合條件 頁碼數(shù)據(jù)
????Integer pageNo = 0;
????if (Integer.parseInt(page) > 0){
????????pageNo = (Integer.parseInt(page) - 1) * Integer.parseInt(limit);
????}
????String listSql = sql + " limit ?"+pageNo+","+limit;
????//查詢列表數(shù)據(jù)
????List<T> users = selectList(listSql, cls);
????//查詢總數(shù)據(jù)條數(shù)
????Long count = getCount(sql);
????PageInfo<T> pageInfo = new PageInfo<>();
????pageInfo.setData(users);
????pageInfo.setCount(count);
????return pageInfo;
}

/**
?* 查詢總數(shù)據(jù)條數(shù)
?* @param sql
?* @return
?*/
private Long getCount(String sql){
????String countSql = "select count(1) from ("+sql+") rs";
????Connection conn = DBUtils.getConnection();
????PreparedStatement prep = null;
????ResultSet rs = null;
????try {
????????prep = conn.prepareStatement(countSql);
????????rs = prep.executeQuery();
????????rs.next();
????????Long count = rs.getLong(1);
????????return count;

????} catch (SQLException throwables) {
????????throwables.printStackTrace();
????}
????return ?0L;
};

更多干貨我們下期再說!

下期會分享

第四章節(jié)

HTML_CSS_JavaScript

相關知識~

下期見!?


教程揭秘 | 動力節(jié)點內(nèi)部Java零基礎教學文檔第三篇:JDBC的評論 (共 條)

分享到微博請遵守國家法律
广灵县| 云林县| 台北市| 万安县| 双峰县| 大英县| 安阳市| 普兰店市| 定日县| 湖南省| 铁力市| 房山区| 苍溪县| 玛曲县| 县级市| 乐平市| 行唐县| 长沙市| 井研县| 平安县| 罗山县| 尉犁县| 洛宁县| 轮台县| 孟连| 无棣县| 偏关县| 隆安县| 清原| 东明县| 富源县| 卓资县| 濮阳市| 甘洛县| 天等县| 大城县| 宁都县| 陆河县| 加查县| 焉耆| 施秉县|