小菜鳥的自學「倒騰」之路(一)---回顧JDBC

小菜鳥的自學「倒騰」之路(一)

---回顧JDBC

 

前言

1.初衷

本人目前是某211的大二在校生,熱衷於「倒騰」關於Java Web。感受接觸到的東西越多,越以爲對於之前學過的知識的力不從心,恰好遇上五一假期,開了一個關於本身的小菜鳥博客來記錄並總結以往學過的知識。今天,咱們來談談JDBC。java

2.什麼是JDBC

JDBC全稱爲::Java Data Base Connectivity,它是能夠執行SQL語句的Java API。mysql

換句話說:JDBC實際上是官方(sun公司)定義的一套操做全部關係型數據庫的規則,即接口。各個數據庫廠商去實現這套接口,提供數據庫驅動jar包。咱們可使用這套接口(JDBC)編程,真正執行的代碼是驅動jar包中的實現類。sql

3.爲何要用到JDBC

  • 市面上有很是多的數據庫,原本咱們是須要根據不一樣的數據庫學習不一樣的API,sun公司爲了簡化這個操做,定義了JDBC API【接口】
  • 對於咱們來講,用Java操做數據庫都是經過JDBC API【接口】,使用不一樣數據庫,只要使用不一樣數據庫廠商提升的操做程序便可
  • 這大大簡化了咱們的學習成本,提升了學習效率

4.基本操做步驟

  1. 導入驅動jar包
  2. 註冊驅動
  3. 獲取數據庫鏈接對象Connection
  4. 定義要執行的sql語句
  5. 獲取執行sql語句的對象Statement
  6. 執行sql,接受返回的結果
  7. 處理結果
  8. 釋放資源

5.代碼實現

一、首先,建立一個lib目錄,裏面導入驅動資源jar包數據庫

二、編程

 1  /**
 2  2      * 示例:執行update操做
 3  3      */
 4  4     public static void main(String[] args) {
 5  5         String driver="com.mysql.cj.jdbc.Driver";
 6  6         String url="jdbc:mysql://127.0.0.1:3306/spj?&useSSL=false&serverTimezone=UTC";
 7  7         String user="root";//mysql用戶名
 8  8         String password="123456";//密碼
 9  9         Statement stat =null;//初始化
10 10         Connection conn =null;//初始化
11 11         try {
12 12             //註冊驅動
13 13             Class.forName(driver);
14 14             //獲取數據庫鏈接對象
15 15             conn= DriverManager.getConnection(url, user,                 password);
16 16             //定義要執行的sql語句
17 17             String sql="update user set username = 'ycj'                 where id=1";
18 18             //獲取執行sql的對象 Statement
19 19             stat=conn.createStatement();
20 20             int i = stat.executeUpdate(sql);//影響到的行數
21 21             System.out.println(i);
22 22             if(i>0)
23 23                 System.out.println("sucessful");
24 24             else
25 25                 System.out.println("Fail");
26 26         } catch (ClassNotFoundException e) {
27 27             e.printStackTrace();
28 28         }catch (SQLException e)
29 29         {
30 30           e.printStackTrace();
31 31         }finally {
32 32             if(stat!=null) {
33 33                 try {
34 34                     stat.close();
35 35                 } catch (SQLException e) {
36 36                     e.printStackTrace();
37 37                 }
38 38             }
39 39             if(conn!=null) {
40 40                 try {
41 41                     conn.close();
42 42                 } catch (SQLException e) {
43 43                     e.printStackTrace();
44 44                 }
45 45             }
46 46         }
47 47 }
View Code

6.注意問題

對於高版本的數據庫(本人使用的時MySQL 8.XXX版本)須要強制SSL的使用,即便不使用,也須要在定義URL時顯式的指出:useSSL=false ,並且須要指定時區:serverTimezone=UTC ,不然會拋出SQLException。服務器

詳解各個對象

1.DriverManager對象

DriverManager:驅動管理對象app

*功能:框架

  1. 註冊驅動:告訴程序該使用哪個數據庫驅動jaride

    static void registerDriver(Driver driver)

    註冊與給定的驅動程序 DriverManager 。函數

    寫代碼使用: Class.forName("com.mysql.cj.jdbc.Driver");

    *須要注意的是:mysql 5以後的驅動包能夠省略註冊驅動步驟。*

  2. 獲取數據庫鏈接:

    * 方法:

    static Connection getConnection(String url, String user, String password)

    * 參數:

    * url:指定鏈接的路徑

    * 語法:jdbc:mysql://ip地址(域名):端口號/數據庫名稱

     * 例子:jdbc:mysql://localhost:3306/spj

     * 細節:若是鏈接的是本機mysql服務器,而且mysql服務默認端口是3306,則url能夠簡寫爲:jdbc:mysql:///數據庫名稱

    * user:用戶名

     * password:密碼

 

2.Connection對象

Connection:數據庫鏈接對象,客戶端與數據庫全部的交互都是經過此對象完成

 功能:

  1. 獲取執行sql 的對象

Statement createStatement()
PreparedStatement prepareStatement(String sql)

  2. 管理事務:

  * 開啓事務:

  setAutoCommit(boolean autoCommit)

  調用該方法設置參數爲false,即開啓事務

  * 提交事務:

  commit()

  * 回滾事務:

  rollback()

3.Statement對象

Statement:執行sql的對象

執行sql的方法:

1.

boolean execute(String sql)

能夠執行任意的sql 瞭解

2.

int executeUpdate(String sql)

執行DML(insert、update、delete)語句、DDL(create,alter、drop)語句

* 返回值:影響的行數,能夠經過這個影響的行數判斷DML語句是否執行成功

返回值>0的則執行成功,反之,則失敗。

3.

ResultSet executeQuery(String sql)

執行DQL(select)語句

4.ResultSet對象

ResultSet:結果集對象,封裝查詢結果,當Statement對象執行executeQuery()時,會返回一個ResultSet對象。

方法:

* boolean next(): 遊標向下移動一行,判斷當前行是不是最後一行末尾(是否有數據),若是是,則返回false,若是不是則返回true

* getXxx(參數):獲取數據

   * Xxx:表明數據類型 如: int getInt() , String getString()

   * 參數:

      1. int:表明列的編號,從1開始 如: getString(1)

      2. String:表明列名稱。 如: getDouble("balance")

注意:

* 使用步驟:

  1. 遊標向下移動一行

  2. 判斷是否有數據

  3. 獲取數據

 1 /**
 2      *Result的使用
 3      */    
 4 public static void main(String[] args) {
 5         String driver = "com.mysql.cj.jdbc.Driver";
 6         String url = "jdbc:mysql://127.0.0.1:3306/spj?&useSSL=false&serverTimezone=UTC";
 7         String user = "root";
 8         String password = "123456";
 9         Statement stat = null;
10         Connection conn = null;
11         ResultSet rs =null;
12         try {
13             Class.forName(driver);
14             conn = DriverManager.getConnection(url, user, password);
15             String sql = "select * from s";
16             stat = conn.createStatement();
17              rs = stat.executeQuery(sql);
18             
19             //循環遍歷,打印出表中的每個數據
20             while(rs.next())
21             {
22                 String sno = rs.getString("sno");
23                 String sname = rs.getString("Sname");
24                 int status = rs.getInt("STATUS");
25                 System.out.println(sno+"---"+sname+"---"+status);
26             }
27 
28         } catch (ClassNotFoundException | SQLException e) {
29             e.printStackTrace();
30         } finally {
31             if (rs != null) {
32                 try {
33                     rs.close();
34                 } catch (SQLException e) {
35                     e.printStackTrace();
36                 }
37             }
38             if (stat != null) {
39                 try {
40                     stat.close();
41                 } catch (SQLException e) {
42                     e.printStackTrace();
43                 }
44             }
45             if (conn != null) {
46                 try {
47                     conn.close();
48                 } catch (SQLException e) {
49                     e.printStackTrace();
50                 }
51             }
52         }
53     }

 

5.PreparedStatement對象

PreparedStatement:執行sql的對象,繼承Statement對象,功能更強大,使用起來更簡單。

  1. Statement對象編譯SQL語句時,若是SQL語句有變量,就須要使用分隔符來隔開,若是變量很是多,就會使SQL變得很是複雜。PreparedStatement可使用佔位符 ?來簡化sql的編寫

  2. Statement會頻繁編譯SQL。

    PreparedStatement可對SQL進行預編譯,提升效率,預編譯的SQL存儲在PreparedStatement對象中

  3. PreparedStatement能夠防止sql注入問題。【Statement經過分隔符'++',編寫永等式,能夠不須要密碼就進入數據庫】

那咱們如何使用PreparedStatement呢?

咱們以一個令用戶輸入用戶名和密碼的案例來演示一下,數據庫已經存儲好了一些用戶名和密碼的鍵值對。

 1 public boolean login(String username, String password) {
 2         if (username == null || password == null) {
 3             return false;
 4         }
 5         //鏈接數據庫判斷是否登陸成功
 6         Connection conn = null;
 7         PreparedStatement stmt = null;
 8         ResultSet rs = null;
 9 
10         try {
11             conn = Demo01JdbcUtils.getConnection();//使用工具類
12             String sql = "select * from user where username             = ? and password =? ";
13             stmt = conn.prepareStatement(sql);
14             stmt.setString(1,username);
15             stmt.setString(2,password);
16             rs = stmt.executeQuery();
17             return rs.next();//若是有下一行,返回true
18 
19         } catch (SQLException e) {
20             e.printStackTrace();
21         } finally {
22             Demo01JdbcUtils.close(rs, stmt, conn);//使用工具類
23         }
24         return false;
25     }
26  

 

能夠看到除了定義sql語句時使用了佔位符,以及給佔位符變量賦值之外,其餘操做都是同樣的。(工具類咱們以後再說)

定義sql

\ * 注意:sql的參數使用?做爲佔位符。

如:select * from user where username = ? and password = ?;

給?賦值:

   * 方法: setXxx(參數1,參數2) Xxx表明數據類型

   * 參數1:?的位置編號 從1 開始

   * 參數2:?的值

JDBC工具類

1.目的

咱們瞭解了關於JDBC一些基礎的實現,發現每次書寫JDBC的代碼時,總會有一些重複的步驟,很是的繁瑣,因此爲了方面咱們書寫代碼,能夠開發一個JDBC的實現類,實現相同的效果。

2.代碼實現

一、首先咱們想要獲取鏈接對象,可是不想經過傳遞參數的方法,由於這樣也很麻煩,爲了保證工具類的通用性,咱們使用配置文件的方式,配置一個jdbc.properties文件,裏面放入一些固定的配置,之後只須要修改裏面的數據庫名稱就好。

url = jdbc:mysql://127.0.0.1:3306/spj?&useSSL=false&serverTimezone=UTC
user = root
password = 123456
driver = com.mysql.cj.jdbc.Driver

 

二、

 1 import java.io.FileReader;
 2 import java.io.IOException;
 3 import java.net.URL;
 4 import java.sql.*;
 5 import java.util.Properties;
 6 
 7 /*
 8     JDBC工具類
 9  */
10 public class Demo01JdbcUtils {
11     private static String url;
12     private static String password;
13     private static String user;
14     private static String driver;
15 
16     /**
17      * 文件的讀取,只須要讀取一次便可拿到這些值,使用靜態代碼塊。
18      */
19     static {
20         try {
21             Properties pro=new Properties();
22             //獲取src路徑下的文件方式: 使用ClassLoader 類加載器
23 
24             ClassLoader classLoader = Demo01JdbcUtils.class.getClassLoader();
25             URL res = classLoader.getResource("jdbc.properties");
26             String path=res.getPath();
27             System.out.println(path);
28 
29 
30             pro.load(new FileReader(path));
31             url=pro.getProperty("url");
32             user=pro.getProperty("user");
33             password=pro.getProperty("password");
34             driver=pro.getProperty("driver");
35 
36             Class.forName(driver);
37         } catch (IOException e) {
38             e.printStackTrace();
39         } catch (ClassNotFoundException e) {
40             e.printStackTrace();
41         }
42     }
43 
44     /**
45      * 獲取鏈接
46      * @return 鏈接對象
47      */
48     public static Connection getConnection() throws SQLException {
49         return DriverManager.getConnection(url,user,password);
50     }
51 
52     /**
53      * 釋放資源
54      * @param stat
55      * @param conn
56      */
57     public static void close(Statement stat,Connection conn)
58     {
59         if (stat != null) {
60             try {
61                 stat.close();
62             } catch (SQLException e) {
63                 e.printStackTrace();
64             }
65         }
66         if (conn != null) {
67             try {
68                 conn.close();
69             } catch (SQLException e) {
70                 e.printStackTrace();
71             }
72         }
73     }
74     public static void close(ResultSet rs,Statement stat,Connection conn)
75     {
76         if (stat != null) {
77             try {
78                 stat.close();
79             } catch (SQLException e) {
80                 e.printStackTrace();
81             }
82         }
83         if (conn != null) {
84             try {
85                 conn.close();
86             } catch (SQLException e) {
87                 e.printStackTrace();
88             }
89         }
90         if (rs != null) {
91             try {
92                 rs.close();
93             } catch (SQLException e) {
94                 e.printStackTrace();
95             }
96         }
97     }
98    
99     }
View Code

 

JDBC對事務的操做

1.事務

  1. 事務是做爲單個邏輯工做單元執行的一系列操做

  2. 一個邏輯工做單元必須有四個屬性,稱爲原子性、一致性、隔離性和持久性 (ACID) 屬性,只有這樣才能成爲一個事務(要麼同時成功,要麼同時失敗)

2.操做

2.1 使用Connection對象管理事務

Connection類中提供了3個事務處理方法:

• setAutoCommit(Boolean autoCommit):設置是否自動提交事務,默認爲自動提交,即爲true,經過設置false禁止自動提交事務,在執行sql以前使用此方法;

• commit():提交事務,當全部sql都執行完提交事務;

• rollback():回滾事務,在catch中回滾事務.

 1 public static void main(String[] args) {
 2         Connection conn = null;
 3 
 4         PreparedStatement stmt1 = null;
 5         PreparedStatement stmt2 = null;
 6         ResultSet rs = null;
 7         try {
 8             conn= Demo01JdbcUtils.getConnection();
 9             //開啓事務
10             conn.setAutoCommit(false);
11 
12             String sql1="update s set STATUS = STATUS -? where sno=?";
13             String sql2="update s set STATUS = STATUS +? where sno=?";
14             stmt1=conn.prepareStatement(sql1);
15             stmt2=conn.prepareStatement(sql2);
16             stmt1.setInt(1,20);
17             stmt1.setString(2,"s1");
18             stmt2.setInt(1,30);
19             stmt2.setString(2,"s2");
20             stmt1.executeUpdate();
21             //手動製造異常
22             int i=3/0;
23             stmt2.executeUpdate();
24 
25             conn.commit();
26             
27         } catch (Exception e) {
28             try {
29                 if(conn!=null)
30                 conn.rollback();
31             } catch (SQLException throwables) {
32                 throwables.printStackTrace();
33             }
34             e.printStackTrace();
35         }finally {
36             Demo01JdbcUtils.close(stmt1,conn);
37             Demo01JdbcUtils.close(stmt2,null);
38         }
39     }

 

 

2.2 事務的隔離級別

數據庫定義了4個隔離級別:

  1. Serializable【可避免髒讀,不可重複讀,虛讀】
  1. Repeatable read【可避免髒讀,不可重複讀】
  1. Read committed【可避免髒讀】
  1. Read uncommitted【級別最低,什麼都避免不了】

分別對應Connection類中的4個常量

  1. TRANSACTION*READ*UNCOMMITTED
  1. TRANSACTION*READ*COMMITTED
  1. TRANSACTION*REPEATABLE*READ
  1. TRANSACTION_SERIALIZABLE

數據庫鏈接池

1.什麼是數據庫鏈接池

其實就是一個容器(集合),存放數據庫鏈接的容器。

當系統初始化好後,容器被建立,容器中會申請一些鏈接對象,當用戶來訪問數據庫時,從容器中獲取鏈接對象,用戶訪問完以後,會將鏈接對象歸還給容器。

與大二這學期學習的操做系統中線程池有着差很少的含義。

2.爲何要使用數據庫鏈接池

• 數據庫的鏈接的創建和關閉是很是消耗資源的

• 頻繁地打開、關閉鏈接形成系統性能低下

3.C3P0

一、首先須要導入相應的jar包

二、定義配置文件:

* 名稱: c3p0.properties 或者 c3p0-config.xml

* 路徑:直接將文件放在根目錄下便可。

  1. 建立核心對象 數據庫鏈接池對象 ComboPooledDataSource
  1. 獲取鏈接: getConnection
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <c3p0-config>
 3     <!-- 默認鏈接池-->
 4     <default-config>
 5         <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
 6         <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/spj?useSSL=true&amp;characterEncoding=utf8&amp;serverTimezone=UTC</property>
 7         <property name="user">root</property>
 8         <property name="password">123456</property>
 9         <property name="initialPoolSize">5</property>
10         <property name="maxPoolSize">20</property>
11     </default-config>
12 /*
13     默認鏈接池最大容量是20
14 */

 

 1 public static void main(String[] args) throws SQLException {
 2 
 3         DataSource ds=new ComboPooledDataSource();//使用默認配置
 4 
 5         for(int i=1;i<=21;i++)
 6         {
 7             Connection coon=ds.getConnection();
 8             System.out.println(i+":"+coon);
 9            //第五個使用完歸還鏈接池
10             if(i==5)
11                 coon.close();
12         }
13     }
14  
 

4.Druid

數據庫鏈接池實現技術,由阿里巴巴提供的

步驟:

  1. 導入jar包 druid-1.0.9.jar
  1. 定義配置文件:

    * 是properties形式的

    * 能夠叫任意名稱,能夠放在任意目錄下

  1. 加載配置文件。Properties
  1. 獲取數據庫鏈接池對象:經過工廠類來獲取 DruidDataSourceFactory
  1. 獲取鏈接:getConnection
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/spj?&useSSL=false&serverTimezone=UTC
username=root
password=123456
initialSize=5
maxActive=10
maxWait=3000
 1 public static void main(String[] args) throws Exception {
 2 
 3        //加載配置文件
 4         Properties pro=new Properties();
 5         InputStream resourceAsStream = Demo01Druid.class.getClassLoader().getResourceAsStream("druid.properties");
 6         pro.load(resourceAsStream);
 7         //獲取鏈接池對象
 8         DataSource ds = DruidDataSourceFactory.createDataSource(pro);
 9         //獲取鏈接
10         Connection conn=ds.getConnection();
11         System.out.println(conn);
12 
13     }

 

 

5.開發鏈接池工具類

 

 1 import Demo02Druid.Demo01Druid;
 2  2 import com.alibaba.druid.pool.DruidDataSourceFactory;
 3  3 
 4  4 import javax.sql.DataSource;
 5  5 import java.io.IOException;
 6  6 import java.io.InputStream;
 7  7 import java.sql.Connection;
 8  8 import java.sql.ResultSet;
 9  9 import java.sql.SQLException;
10 10 import java.sql.Statement;
11 11 import java.util.Properties;
12 12 
13 13 /*
14 14     Druid鏈接池的工具類
15 15 
16 16  */
17 17 public class JDBCUtils {
18 18     //一、定義成員變量
19 19     private static DataSource ds;
20 20     static {
21 21 
22 22         try {
23 23             //加載配置文件
24 24             Properties pro=new Properties();
25 25             InputStream resourceAsStream = Demo01Druid.class.getClassLoader().getResourceAsStream("druid.properties");
26 26             pro.load(resourceAsStream);
27 27             //獲取鏈接池對象
28 28              ds = DruidDataSourceFactory.createDataSource(pro);
29 29 
30 30         } catch (IOException e) {
31 31             e.printStackTrace();
32 32         } catch (Exception e) {
33 33             e.printStackTrace();
34 34         }
35 35     }
36 36     /**
37 37      * 獲取鏈接
38 38      */
39 39     public static Connection geConnection() throws SQLException {
40 40         return ds.getConnection();
41 41     }
42 42     /**
43 43      * 釋放資源
44 44      */
45 45     public static void close(Statement stat,Connection conn)
46 46     {
47 47         if (stat != null) {
48 48             try {
49 49                 stat.close();
50 50             } catch (SQLException e) {
51 51                 e.printStackTrace();
52 52             }
53 53         }
54 54         if (conn != null) {
55 55             try {
56 56                 conn.close();
57 57             } catch (SQLException e) {
58 58                 e.printStackTrace();
59 59             }
60 60         }
61 61     }
62 62     public static void close(ResultSet rs, Statement stat, Connection conn)
63 63     {
64 64         if (stat != null) {
65 65             try {
66 66                 stat.close();
67 67             } catch (SQLException e) {
68 68                 e.printStackTrace();
69 69             }
70 70         }
71 71         if (conn != null) {
72 72             try {
73 73                 conn.close();
74 74             } catch (SQLException e) {
75 75                 e.printStackTrace();
76 76             }
77 77         }
78 78         if (rs != null) {
79 79             try {
80 80                 rs.close();
81 81             } catch (SQLException e) {
82 82                 e.printStackTrace();
83 83             }
84 84         }
85 85     }
86 86     /**
87 87      * 獲取鏈接池方法
88 88      */
89 89     public static  DataSource getDataSource()
90 90     {
91 91         return ds;
92 92     }
View Code

 

6.JDBCTemplate

Spring框架對JDBC的簡單封裝。提供了一個JDBCTemplate對象簡化JDBC的開發

* 步驟:

  1. 導入jar包
  1. 建立JdbcTemplate對象。依賴於數據源DataSource
JdbcTemplate template = new JdbcTemplate(ds);
  1. 調用JdbcTemplate的方法來完成CRUD的操做

* update():執行DML語句。增、刪、改語句

* queryForMap():查詢結果將結果集封裝爲map集合,將列名做爲key,將值做爲value 將這條記錄封裝爲一個map集合

      * 注意:這個方法查詢的結果集長度只能是1

* queryForList():查詢結果將結果集封裝爲list集合

      * 注意:將每一條記錄封裝爲一個Map集合,再將Map集合裝載到 List集合中

*query():查詢結果,將結果封裝爲JavaBean對象

    query的參數:RowMapper

    * 通常咱們使用BeanPropertyRowMapper實現類。能夠完成數據到 JavaBean的自動封裝

    *new BeanPropertyRowMapper<類型>(類型.class)

* queryForObject:查詢結果,將結果封裝爲對象

       * 通常用於聚合函數的查詢

相關文章
相關標籤/搜索