Java学习笔记之JDBC和连接池
文章目錄
- 一、JDBC概述
- 二、JDBC使用
- 1.JDBC驅動的注冊
- 2.JDBC與數據庫建立連接
- 3.Statement發送sql語句對象
- 4.Result結果集對象
- 5.Statement的不足以及PreparedStatement
- 5.1 SQL注入分析
- 5.2 PreparedStatement
- 6.PreparedStatement和Statement的對比
- 7.JDBC事務的處理
- 8.JDBC連接工具類
- 三、連接池
- 1.C3P0連接池
- 2.DRUID連接池
- 3.連接池工具類
一、JDBC概述
jdbc是什么?
英文全稱:Java Database ConnectivIty
中文名稱:Java數據庫連接技術
作用:
使用Java代碼與數據庫建立連接,并對數據庫執行操作
JDBC的組成:
由官方定義的接口(規范)組成:接口的實現類由數據庫廠商提供:(數據庫驅動)
數據庫驅動:包含實現操作數據庫接口的類
JDBC的好處:
代碼不依賴與任何數據庫
只需要修改少量配置就可以方便切換到其他廠商的數據庫
JDBC核心類和接口:
| DriverManager 工具類 | 1.注冊數據庫驅動 2.獲得連接對象 |
| Connection 接口 | 連接對象 作用:與數據庫建立連接并形成數據通道 |
| Statement 接口 | SQL語句發送對象 作用:將SQL語句發送給數據庫執行并獲得執行結果 |
| ResultSet 接口 | 結果集對象 作用:用來封裝滿足查詢條件的記錄信息 |
| Driver 接口 | 數據庫驅動對象 |
二、JDBC使用
步驟:
1.注冊驅動
2.建立連接
3.獲得sql語句發送對象
4.執行sql語句
5.獲得執行結果
6.關閉連接,釋放資源
1.JDBC驅動的注冊
注冊數據庫驅動的兩種方式:
public static void main(String[] args) throws Exception{//方式1:存在問題:驅動會被注冊兩次//創建驅動對象(Driver是mysql廠商提供Driver接口的實現類)Driver driver = new Driver();//注冊驅動DriverManager.registerDriver(driver);//方式二:利用反射觸發Driver實現類的加載實現驅動注冊Class.forName("com.mysql.jdbc.Driver"); }| static registerDriver(Driver driver) | 驅動會注冊兩次 |
| Class.forName(“com.mysql.jdbc.Driver”) | 只會注冊一次 |
2.JDBC與數據庫建立連接
與數據庫建立連接:
數據庫連接字符串格式:完整格式:JDBC協議:子協議://數據庫服務器地址:端口號/數據庫名? JDBC協議:固定值:jdbc? 子協議:一般是數據庫廠商的名字,比如mysql、oracle省略格式:JDBC協議:子協議:/// 數據庫名? 前提:操作的是本機的數據庫,且端口號是3306| static Connection getConnetion( String url, String username, String password) | 獲得連接對象 url:連接字符串 username:用戶名 password:密碼 |
| static Connection getConnection( String url, Properties info) | 獲得連接對象 |
配置文件內容:
user=root password=1234563.Statement發送sql語句對象
作用:
將SQL語句發送給數據庫執行并獲取結果
創建方式:
通過連接對象的方法獲得( Statement createStatement() )
| boolean execute(String sql) | 可以執行任意SQL語句 一般用來執行DDL語句:創庫或創表 |
| int executeUpdate(String sql) | 用于執行增刪改語句:返回影響的行數 只要不是查詢都稱為更新操作 |
| ResultSet executeQuery(String sql) | 用于執行查詢語句 |
4.Result結果集對象
作用:
封裝滿足查詢條件的記錄信息
獲得ResultSet對象:
通過Statement對象的方法獲取( ResultSet executeQuery(String sql) )
| boolean next() | 將指針下移一行并判斷當前位置是否有記錄 有則返回true,否則返回false |
| Xxx getXxx(列號或列名) | 根據列號或列名獲得當前行指定列的數據 |
5.Statement的不足以及PreparedStatement
5.1 SQL注入分析
Statement的不足:
容易被sql注入,因為statement的執行方式是先把sql語句寫好了之后再執行
由于傳入的字符串有可能導致sql語句的內容發生變化,所以容易被sql注入
代碼樣例:
package JDBCConnection;import java.sql.*; import java.util.Scanner;public class login {public static void main(String[] args) throws Exception {//jdbc連接工具類直接獲得連接對象Connection connect = getConnect.getConnect();//創建statement對象Statement stmt = connect.createStatement();//創建scanner獲得數據Scanner sc = new Scanner(System.in);System.out.println("請輸入用戶名:");String username = sc.nextLine();System.out.println("請輸入密碼:");String password = sc.nextLine();//編寫sql語句String sql = "select * from personal where username='" + username + "' and password='" + password + "'";//執行sql語句并獲得結果集ResultSet rs = stmt.executeQuery(sql);//判斷是否登錄成功if (rs.next()) {System.out.println("登錄成功");} else {System.out.println("登陸失敗");}}}不足分析:
上面的代碼起來沒有什么問題,但是由于你不能控制用戶輸入的信息
那么他在登錄的時候就可能輸入這樣的信息a’ or ‘1’='1
這樣操作之后,sql語句就變成了下面這樣的:
select * from personal where username=‘xxx’ and password=‘a’ or ‘1’=‘1’;
這樣無論他輸入的是什么,存不存在,都會判定為登錄成功
優化方案:
使用PreparedStatement來執行sql語句;
5.2 PreparedStatement
概述:
PreparedStatemet預編譯處理,是Statement的子類,和Statement一樣,都是用來發送sql語句的
創建方式:
//在編寫格式上,預編譯對象不需要把參數寫入進去,而是使用通配符?來代替 PreparedStatement pstmt = conn.prepareStatement(sql); //下一步,就是調用預編譯對象的設置方法來把參數設置好,然后調用和父類一樣的執行方法執行即可 //由于不需要直接把參數寫進sql語句,而且預編譯預編譯,會在輸入sql獲得對象之后先對sql語句做預編譯 //然后再輸入參數,所以可以避免sql注入| int executeUpdate(); | 執行DML語句 返回影響的行數 |
| ResultSet executeQuery(); | 執行DQL語句 返回滿足查詢條件的結果集對象 |
6.PreparedStatement和Statement的對比
相同點:
都可以對數據庫執行增刪改查操作
不同點:
1.PrepartedStatement有預編譯功能,Statement沒有預編譯功能
2.PrepartedStatement有緩存的功能,緩存的是sql語句編譯的結果,Statement沒有緩存功能
3.PrepartedStatement沒有sql注入,Statement有sql注入,前者更安全,后者不安全
7.JDBC事務的處理
| 開啟事務 | 連接對象.setAutoCommit(boolean b) 作用:設置是否自動提交事務 默認值是true即自動提交事務 需要開啟事物的話需要在獲得連接之后先關閉在發送sql |
| 回滾 | 連接對象.rollback(); 作用:用來執行sql語句中的回滾 |
| 提交事務 | 連接對象.commit() 作用:提交事務 |
8.JDBC連接工具類
package JDBCConnection;import java.sql.*; import java.util.Properties;public class jdbcUtils {//靜態代碼塊,用來注冊驅動,因為驅動只需要注冊一次static {try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}}public static Connection getConnection() {try {//通過寫好的配置信息來連接數據庫return DriverManager.getConnection("jdbc:mysql://localhost:3306/personal","root", "123456");} catch (Exception e) {throw new RuntimeException(e);}}public static Connection getConnection(String path) {try {//讀取配置文件來連接數據庫Properties properties = new Properties();properties.load(Class.class.getResourceAsStream(path));return DriverManager.getConnection("jdbc:mysql://localhost:3306/personal",properties);} catch (Exception e) {throw new RuntimeException(e);}}//關閉所有數據庫相關的資源//因為prepartedstatement是statement的子類,所以也可以直接關閉public static void Close(Connection conn, Statement stmt, ResultSet rs) {//判斷傳入的組件是否為空,不為空則關閉if (rs != null) {try {rs.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (stmt != null) {try {stmt.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}//調用上面的方法public static void Close(Connection conn, Statement stmt) {Close(conn, stmt, null);} }三、連接池
概述:
連接池就是一個負責創建和管理連接對象的容器(集合)
使用連接池的原因:
和線程池的理由一樣,都是為了提高效率。因為頻繁的創建和銷毀連接是很消耗資源的。
使用連接池可以減少頻繁和銷毀連接帶來的系統資源損耗,從而提高訪問數據庫的效率
連接池的核心思想:
連接復用
連接池規范:
DataSource
常用連接池:
C3P0連接池
DRUID連接池
1.C3P0連接池
配置文件:
<!--這里要注意,這個文件會自動讀取,所以需要命名為c3p0-config.xml并且放到src目錄下--> <c3p0-config><!-- 使用默認的配置讀取連接池對象 --><default-config><!-- 連接參數 --><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property><property name="user">root</property><property name="password">root</property><!-- 連接池參數 --><property name="initialPoolSize">5</property><property name="maxPoolSize">10</property><property name="checkoutTimeout">2000</property><property name="maxIdleTime">1000</property></default-config><named-config name="pkxingc3p0"> <!-- 連接參數 --><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property><property name="user">root</property><property name="password">root</property><!-- 連接池參數 --><property name="initialPoolSize">5</property><property name="maxPoolSize">15</property><property name="checkoutTimeout">2000</property><property name="maxIdleTime">1000</property></named-config> </c3p0-config>連接池常用方法:
| ComboPooledDataSource() | 使用默認的配置default-config創建數據源對象 |
| ComboPooledDataSource(命名配置) | 使用命名的配置named-config創建數據源對象 |
配置信息詳解:
| driverClass | 注冊jdbc的字符串 |
| jdbcUrl | mysql服務器地址 |
| user | 用戶名 |
| password | 密碼 |
| initialPoolSize | 初始化連接數 |
| maxPoolSize | 最大連接數 |
| checkoutTimeout | 最大等待時間 |
| maxIdTime | 最大空閑時間 |
代碼樣例:
public void C3P0() throws Exception {//使用默認配置方式DataSource ds = new ComboPooledDataSource();//選擇命名配置 // DataSource ds = new ComboPooledDataSource("ps");for (int i = 0; i < 15; i++) {//獲得連接,但不關閉//如果關閉之后,他不會銷毀而是會回到連接池中Connection connection = ds.getConnection();System.out.println("第" + (i + 1) + "次===>" + connection);}}2.DRUID連接池
配置文件內容:
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/day25 username=root password=root initialSize=5 maxActive=10 maxWait=3000 maxIdle=6 minIdle=3參數內容說明:
| jdbcUrl | 連接數據庫的url:mysql : jdbc:mysql://localhost:3306/druid2 |
| username | 數據庫的用戶名 |
| password | 數據庫的密碼 |
| driverClassName | 驅動類名。根據url自動識別,這一項可配可不配,如果不配置druid會根據url自動 識別dbType,然后選擇相應的driverClassName(建議配置下) |
| initialSize | 初始化時建立物理連接的個數。初始化發生在顯示調用init方法,或者第一次getConnection時 |
| maxActive | 最大連接數量 |
| maxIdle | 已經不再使用,配置了也沒效果 |
| minIdle | 最小連接數量 |
| maxWait | 獲取連接時最大等待時間,單位毫秒。 |
常用方法:
| public static DataSource createDataSource(Properties properties) | 創建連接池對象 |
代碼樣例:
public void DRUID() throws Exception{//讀取配置文件Properties properties = new Properties();properties.load(Class.class.getResourceAsStream("/druid.properties"));//加載配置文件獲得連接池DataSource ds = DruidDataSourceFactory.createDataSource(properties);//從連接池獲得連接Connection connection = ds.getConnection();System.out.println(connection);}3.連接池工具類
DRUID版:
package JDBCConnection;import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties;public class DataPoolUtils {//連接池對象private static DataSource ds = null;//靜態方法,加載連接池static {try {//讀取配置文件Properties properties = new Properties();properties.load(Class.class.getResourceAsStream("/druid.properties"));//獲得連接池ds = DruidDataSourceFactory.createDataSource(properties);} catch (Exception e) {e.printStackTrace();}}public static Connection getConnection() {try {//直接獲得連接return ds.getConnection();} catch (SQLException throwables) {throw new RuntimeException(throwables);}}public static DataSource getDataSource() {return ds;}public static void Close(Connection conn, Statement stmt, ResultSet rs) {if (conn != null) {try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (stmt != null) {try {stmt.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (rs != null) {try {rs.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}public static void Close(Connection conn, Statement stmt) {Close(conn, stmt, null);} }C3P0版:
package JDBCConnection;import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties;public class DataPoolUtils {private static DataSource ds = null;static {try {//其他和上面一樣//只不過創建連接池的時候,C3P0會自動讀取配置文件ds = new ComboPooledDataSource();} catch (Exception e) {e.printStackTrace();}}public static Connection getConnection() {try {return ds.getConnection();} catch (SQLException throwables) {throw new RuntimeException(throwables);}}public static DataSource getDataSource() {return ds;}public static void Close(Connection conn, Statement stmt, ResultSet rs) {if (conn != null) {try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (stmt != null) {try {stmt.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (rs != null) {try {rs.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}public static void Close(Connection conn, Statement stmt) {Close(conn, stmt, null);} }總結
以上是生活随笔為你收集整理的Java学习笔记之JDBC和连接池的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 工业三防手持终端如何选
- 下一篇: C语言——扫雷游戏详解