本人目前是某211的大二在校生,熱衷於「倒騰」關於Java Web。感受接觸到的東西越多,越以爲對於之前學過的知識的力不從心,恰好遇上五一假期,開了一個關於本身的小菜鳥博客來記錄並總結以往學過的知識。今天,咱們來談談JDBC。java
JDBC全稱爲::Java Data Base Connectivity,它是能夠執行SQL語句的Java API。mysql
換句話說:JDBC實際上是官方(sun公司)定義的一套操做全部關係型數據庫的規則,即接口。各個數據庫廠商去實現這套接口,提供數據庫驅動jar包。咱們可使用這套接口(JDBC)編程,真正執行的代碼是驅動jar包中的實現類。sql
一、首先,建立一個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 }
對於高版本的數據庫(本人使用的時MySQL 8.XXX版本)須要強制SSL的使用,即便不使用,也須要在定義URL時顯式的指出:useSSL=false
,並且須要指定時區:serverTimezone=UTC
,不然會拋出SQLException。服務器
DriverManager:驅動管理對象app
*功能:框架
註冊驅動:告訴程序該使用哪個數據庫驅動jaride
static void registerDriver(Driver driver)
註冊與給定的驅動程序 DriverManager 。函數
寫代碼使用: Class.forName("com.mysql.cj.jdbc.Driver");
*須要注意的是:mysql 5以後的驅動包能夠省略註冊驅動步驟
。*
獲取數據庫鏈接:
* 方法:
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:密碼
Connection:數據庫鏈接對象,客戶端與數據庫全部的交互都是經過此對象完成。
功能:
1. 獲取執行sql 的對象
Statement createStatement()
PreparedStatement prepareStatement(String sql)
2. 管理事務:
* 開啓事務:
setAutoCommit(boolean autoCommit)
調用該方法設置參數爲false,即開啓事務
* 提交事務:
commit()
* 回滾事務:
rollback()
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)語句
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 }
PreparedStatement:執行sql的對象,繼承Statement對象,功能更強大,使用起來更簡單。
Statement對象編譯SQL語句時,若是SQL語句有變量,就須要使用分隔符來隔開,若是變量很是多,就會使SQL變得很是複雜。PreparedStatement可使用佔位符 ?來簡化sql的編寫
Statement會頻繁編譯SQL。
PreparedStatement可對SQL進行預編譯,提升效率,預編譯的SQL存儲在PreparedStatement對象中
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一些基礎的實現,發現每次書寫JDBC的代碼時,總會有一些重複的步驟,很是的繁瑣,因此爲了方面咱們書寫代碼,能夠開發一個JDBC的實現類,實現相同的效果。
一、首先咱們想要獲取鏈接對象,可是不想經過傳遞參數的方法,由於這樣也很麻煩,爲了保證工具類的通用性,咱們使用配置文件的方式,配置一個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 }
1. 事務是做爲單個邏輯工做單元執行的一系列操做。
2. 一個邏輯工做單元必須有四個屬性,稱爲原子性、一致性、隔離性和持久性 (ACID) 屬性,只有這樣才能成爲一個事務(要麼同時成功,要麼同時失敗)
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 }
數據庫定義了4個隔離級別:
分別對應Connection類中的4個常量
其實就是一個容器(集合),存放數據庫鏈接的容器。
當系統初始化好後,容器被建立,容器中會申請一些鏈接對象,當用戶來訪問數據庫時,從容器中獲取鏈接對象,用戶訪問完以後,會將鏈接對象歸還給容器。
與大二這學期學習的操做系統中線程池有着差很少的含義。
• 數據庫的鏈接的創建和關閉是很是消耗資源的
• 頻繁地打開、關閉鏈接形成系統性能低下
一、首先須要導入相應的jar包
二、定義配置文件:
* 名稱: c3p0.properties 或者 c3p0-config.xml
* 路徑:直接將文件放在根目錄下便可。
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&characterEncoding=utf8&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
數據庫鏈接池實現技術,由阿里巴巴提供的
步驟:
定義配置文件:
* 是properties形式的
* 能夠叫任意名稱,能夠放在任意目錄下
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 }
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 }
Spring框架對JDBC的簡單封裝。提供了一個JDBCTemplate對象簡化JDBC的開發
* 步驟:
JdbcTemplate template = new JdbcTemplate(ds);
* update():執行DML語句。增、刪、改語句
* queryForMap():查詢結果將結果集封裝爲map集合,將列名做爲key,將值做爲value 將這條記錄封裝爲一個map集合
* 注意:這個方法查詢的結果集長度只能是1
* queryForList():查詢結果將結果集封裝爲list集合
* 注意:將每一條記錄封裝爲一個Map集合,再將Map集合裝載到 List集合中
*query():查詢結果,將結果封裝爲JavaBean對象
query的參數:RowMapper
* 通常咱們使用BeanPropertyRowMapper實現類。能夠完成數據到 JavaBean的自動封裝
*new BeanPropertyRowMapper<類型>(類型.class)
* queryForObject:查詢結果,將結果封裝爲對象
* 通常用於聚合函數的查詢