日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

jdbc就是这么简单

發(fā)布時間:2025/3/20 60 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jdbc就是这么简单 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章有不當(dāng)之處,歡迎指正,如果喜歡微信閱讀,你也可以關(guān)注我的微信公眾號:好好學(xué)java,獲取優(yōu)質(zhì)學(xué)習(xí)資源。

一、JDBC

JAVA Database Connectivity java 數(shù)據(jù)庫連接.

JDBC(Java DataBase Connectivity,java數(shù)據(jù)庫連接)是一種用于執(zhí)行SQL語句的Java API,可以為多種關(guān)系數(shù)據(jù)庫提供統(tǒng)一訪問,它由一組用Java語言編寫的類和接口組成。JDBC提供了一種基準(zhǔn),據(jù)此可以構(gòu)建更高級的工具和接口,使數(shù)據(jù)庫開發(fā)人員能夠編寫數(shù)據(jù)庫應(yīng)用程序,同時,JDBC也是個商標(biāo)名。

二、為什么會出現(xiàn)JDBC

SUN公司提供的一種數(shù)據(jù)庫訪問規(guī)則、規(guī)范, 由于數(shù)據(jù)庫種類較多,并且java語言使用比較廣泛,sun公司就提供了一種規(guī)范,讓其他的數(shù)據(jù)庫提供商去實(shí)現(xiàn)底層的訪問規(guī)則。 我們的java程序只要使用sun公司提供的jdbc驅(qū)動即可。

三、數(shù)據(jù)庫驅(qū)動

我們安裝好數(shù)據(jù)庫之后,我們的應(yīng)用程序也是不能直接使用數(shù)據(jù)庫的,必須要通過相應(yīng)的數(shù)據(jù)庫驅(qū)動程序,通過驅(qū)動程序去和數(shù)據(jù)庫打交道。其實(shí)也就是數(shù)據(jù)庫廠商的JDBC接口實(shí)現(xiàn),即對Connection等接口的實(shí)現(xiàn)類的jar文件。

1.png

四、常用接口

1.Driver接口

Driver接口由數(shù)據(jù)庫廠家提供,作為java開發(fā)人員,只需要使用Driver接口就可以了。在編程中要連接數(shù)據(jù)庫,必須先裝載特定廠商的數(shù)據(jù)庫驅(qū)動程序,不同的數(shù)據(jù)庫有不同的裝載方法。如:

  • 裝載MySql驅(qū)動:Class.forName("com.mysql.jdbc.Driver");

  • 裝載Oracle驅(qū)動:Class.forName("oracle.jdbc.driver.OracleDriver");

2.Connection接口

Connection與特定數(shù)據(jù)庫的連接(會話),在連接上下文中執(zhí)行sql語句并返回結(jié)果。DriverManager.getConnection(url, user, password)方法建立在JDBC URL中定義的數(shù)據(jù)庫Connection連接上。

  • 連接MySql數(shù)據(jù)庫:Connection conn = DriverManager.getConnection("jdbc:mysql://host:port/database", "user", "password");

  • 連接Oracle數(shù)據(jù)庫:Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@host:port:database", "user", "password");

  • 連接SqlServer數(shù)據(jù)庫:Connection conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://host:port; DatabaseName=database", "user", "password");

常用方法:

  • createStatement():創(chuàng)建向數(shù)據(jù)庫發(fā)送sql的statement對象。
  • prepareStatement(sql) :創(chuàng)建向數(shù)據(jù)庫發(fā)送預(yù)編譯sql的PrepareSatement對象。
  • prepareCall(sql):創(chuàng)建執(zhí)行存儲過程的callableStatement對象。
  • setAutoCommit(boolean autoCommit):設(shè)置事務(wù)是否自動提交。
  • commit() :在鏈接上提交事務(wù)。
  • rollback() :在此鏈接上回滾事務(wù)。

3.Statement接口

用于執(zhí)行靜態(tài)SQL語句并返回它所生成結(jié)果的對象。

三種Statement類:

  • Statement:由createStatement創(chuàng)建,用于發(fā)送簡單的SQL語句(不帶參數(shù))。
  • PreparedStatement :繼承自Statement接口,由preparedStatement創(chuàng)建,用于發(fā)送含有一個或多個參數(shù)的SQL語句。PreparedStatement對象比Statement對象的效率更高,并且可以防止SQL注入,所以我們一般都使用PreparedStatement。
  • CallableStatement:繼承自PreparedStatement接口,由方法prepareCall創(chuàng)建,用于調(diào)用存儲過程。

常用Statement方法:

  • execute(String sql):運(yùn)行語句,返回是否有結(jié)果集
  • executeQuery(String sql):運(yùn)行select語句,返回ResultSet結(jié)果集。
  • executeUpdate(String sql):運(yùn)行insert/update/delete操作,返回更新的行數(shù)。
  • addBatch(String sql) :把多條sql語句放到一個批處理中。
  • executeBatch():向數(shù)據(jù)庫發(fā)送一批sql語句執(zhí)行。

4.ResultSet接口

ResultSet提供檢索不同類型字段的方法,常用的有:

  • getString(int index)、getString(String columnName):獲得在數(shù)據(jù)庫里是varchar、char等類型的數(shù)據(jù)對象。
  • getFloat(int index)、getFloat(String columnName):獲得在數(shù)據(jù)庫里是Float類型的數(shù)據(jù)對象。
  • getDate(int index)、getDate(String columnName):獲得在數(shù)據(jù)庫里是Date類型的數(shù)據(jù)。
  • getBoolean(int index)、getBoolean(String columnName):獲得在數(shù)據(jù)庫里是Boolean類型的數(shù)據(jù)。
  • getObject(int index)、getObject(String columnName):獲取在數(shù)據(jù)庫里任意類型的數(shù)據(jù)。

ResultSet還提供了對結(jié)果集進(jìn)行滾動的方法:

  • next():移動到下一行
  • Previous():移動到前一行
  • absolute(int row):移動到指定行
  • beforeFirst():移動resultSet的最前面。
  • afterLast() :移動到resultSet的最后面。

使用后依次關(guān)閉對象及連接:ResultSet → Statement → Connection

五、使用JDBC的基本步驟

1. 注冊驅(qū)動
DriverManager.registerDriver(new?com.mysql.jdbc.Driver());
2. 建立連接
//DriverManager.getConnection("jdbc:mysql://localhost/test?user=SIHAI&password=SIHAI"); //2.?建立連接?參數(shù)一:?協(xié)議?+?訪問的數(shù)據(jù)庫?,?參數(shù)二:?用戶名?,?參數(shù)三:?密碼。conn?=?DriverManager.getConnection("jdbc:mysql://localhost/student",?"root",?"root");
3. 創(chuàng)建statement
//3.?創(chuàng)建statement?,?跟數(shù)據(jù)庫打交道,一定需要這個對象 st?=?conn.createStatement();
4. 執(zhí)行sql ,得到ResultSet
//4.?執(zhí)行查詢?,?得到結(jié)果集 String?sql?=?"select?*?from?t_stu"; rs?=?st.executeQuery(sql);
5. 遍歷結(jié)果集
????????//5.?遍歷查詢每一條記錄while(rs.next()){int?id?=?rs.getInt("id");String?name?=?rs.getString("name");int?age?=?rs.getInt("age");System.out.println("id="+id?+?"===name="+name+"==age="+age);}
6. 釋放資源
????if?(rs?!=?null)?{try?{rs.close();}?catch?(SQLException?sqlEx)?{?}?//?ignore?rs?=?null;}

六、JDBC 工具類構(gòu)建

1. 資源釋放工作的整合
/***?釋放資源*?@param?conn*?@param?st*?@param?rs*/public?static?void?release(Connection?conn?,?Statement?st?,?ResultSet?rs){closeRs(rs);closeSt(st);closeConn(conn);}private?static?void?closeRs(ResultSet?rs){try?{if(rs?!=?null){rs.close();}}?catch?(SQLException?e)?{e.printStackTrace();}finally{rs?=?null;}}private?static?void?closeSt(Statement?st){try?{if(st?!=?null){st.close();}}?catch?(SQLException?e)?{e.printStackTrace();}finally{st?=?null;}}private?static?void?closeConn(Connection?conn){try?{if(conn?!=?null){conn.close();}}?catch?(SQLException?e)?{e.printStackTrace();}finally{conn?=?null;}}
2. 驅(qū)動防二次注冊
/***?獲取連接對象*?@return*/public?static?Connection?getConn(){Connection?conn?=?null;try?{Class.forName(driverClass);//靜態(tài)代碼塊?--->?類加載了,就執(zhí)行。?java.sql.DriverManager.registerDriver(new?Driver());//DriverManager.registerDriver(new?com.mysql.jdbc.Driver());//DriverManager.getConnection("jdbc:mysql://localhost/test?user=monty&password=greatsqldb");//2.?建立連接?參數(shù)一:?協(xié)議?+?訪問的數(shù)據(jù)庫?,?參數(shù)二:?用戶名?,?參數(shù)三:?密碼。conn?=?DriverManager.getConnection(url,?name,?password);}?catch?(Exception?e)?{e.printStackTrace();}return?conn;}
3. 使用properties配置文件
  • 在src底下聲明一個文件 xxx.properties ,里面的內(nèi)容吐下:
?????????driverClass=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost/studentname=rootpassword=root
  • 在工具類里面,使用靜態(tài)代碼塊,讀取屬性
static{try?{//1.?創(chuàng)建一個屬性配置對象Properties?properties?=?new?Properties();InputStream?is?=?new?FileInputStream("jdbc.properties");?//對應(yīng)文件位于工程根目錄//使用類加載器,去讀取src底下的資源文件。?后面在servlet??//對應(yīng)文件位于src目錄底下//InputStream?is?=?JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");//導(dǎo)入輸入流。properties.load(is);//讀取屬性driverClass?=?properties.getProperty("driverClass");url?=?properties.getProperty("url");name?=?properties.getProperty("name");password?=?properties.getProperty("password");}?catch?(Exception?e)?{e.printStackTrace();}}

源代碼如下:

public?class?JDBCUtil?{static?String?driverClass?=?null;static?String?url?=?null;static?String?name?=?null;static?String?password=?null;static{try?{//1.?創(chuàng)建一個屬性配置對象Properties?properties?=?new?Properties();InputStream?is?=?new?FileInputStream("jdbc.properties");//使用類加載器,去讀取src底下的資源文件。?后面在servlet //????????????InputStream?is?=?JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");//導(dǎo)入輸入流。properties.load(is);//讀取屬性driverClass?=?properties.getProperty("driverClass");url?=?properties.getProperty("url");name?=?properties.getProperty("name");password?=?properties.getProperty("password");}?catch?(Exception?e)?{e.printStackTrace();}}/***?獲取連接對象*?@return*/public?static?Connection?getConn(){Connection?conn?=?null;try?{Class.forName(driverClass);//靜態(tài)代碼塊?--->?類加載了,就執(zhí)行。?java.sql.DriverManager.registerDriver(new?Driver());//DriverManager.registerDriver(new?com.mysql.jdbc.Driver());//DriverManager.getConnection("jdbc:mysql://localhost/test?user=monty&password=greatsqldb");//2.?建立連接?參數(shù)一:?協(xié)議?+?訪問的數(shù)據(jù)庫?,?參數(shù)二:?用戶名?,?參數(shù)三:?密碼。conn?=?DriverManager.getConnection(url,?name,?password);}?catch?(Exception?e)?{e.printStackTrace();}return?conn;}/***?釋放資源*?@param?conn*?@param?st*?@param?rs*/public?static?void?release(Connection?conn?,?Statement?st?,?ResultSet?rs){closeRs(rs);closeSt(st);closeConn(conn);}private?static?void?closeRs(ResultSet?rs){try?{if(rs?!=?null){rs.close();}}?catch?(SQLException?e)?{e.printStackTrace();}finally{rs?=?null;}}private?static?void?closeSt(Statement?st){try?{if(st?!=?null){st.close();}}?catch?(SQLException?e)?{e.printStackTrace();}finally{st?=?null;}}private?static?void?closeConn(Connection?conn){try?{if(conn?!=?null){conn.close();}}?catch?(SQLException?e)?{e.printStackTrace();}finally{conn?=?null;}} }

?

七、數(shù)據(jù)庫的CRUD

  • insert操作
INSERT?INTO?t_stu?(NAME?,?age)?VALUES?('wangqiang',28)INSERT?INTO?t_stu?VALUES?(NULL,'wangqiang2',28) //?1.?獲取連接對象 conn?=?JDBCUtil.getConn(); //?2.?根據(jù)連接對象,得到statement st?=?conn.createStatement();//3.?執(zhí)行添加 String?sql?=?"insert?into?t_stu?values(null?,?'aobama'?,?59)"; //影響的行數(shù),?,如果大于0?表明操作成功。?否則失敗 int?result?=?st.executeUpdate(sql);if(result?>0?){System.out.println("添加成功"); }else{System.out.println("添加失敗"); }
  • delete操作
DELETE?FROM?t_stu?WHERE?id?=?6 //?1.?獲取連接對象 conn?=?JDBCUtil.getConn(); //?2.?根據(jù)連接對象,得到statement st?=?conn.createStatement();//3.?執(zhí)行添加 String?sql?=?"delete?from?t_stu?where?name='aobama'"; //影響的行數(shù),?,如果大于0?表明操作成功。?否則失敗 int?result?=?st.executeUpdate(sql);if(result?>0?){System.out.println("刪除成功"); }else{System.out.println("刪除失敗"); }
  • query操作
SELECT?*?FROM?t_stu ????//?1.?獲取連接對象conn?=?JDBCUtil.getConn();//?2.?根據(jù)連接對象,得到statementst?=?conn.createStatement();//?3.?執(zhí)行sql語句,返回ResultSetString?sql?=?"select?*?from?t_stu";rs?=?st.executeQuery(sql);//?4.?遍歷結(jié)果集while?(rs.next())?{String?name?=?rs.getString("name");int?age?=?rs.getInt("age");System.out.println(name?+?"???"?+?age);}
  • update操作
UPDATE?t_stu?SET?age?=?38?WHERE?id?=?1; //?1.?獲取連接對象 conn?=?JDBCUtil.getConn(); //?2.?根據(jù)連接對象,得到statement st?=?conn.createStatement();//3.?執(zhí)行添加 String?sql?=?"update?t_stu?set?age?=?26?where?name?='qyq'"; //影響的行數(shù),?,如果大于0?表明操作成功。?否則失敗 int?result?=?st.executeUpdate(sql);if(result?>0?){System.out.println("更新成功"); }else{System.out.println("更新失敗"); }

八、使用單元測試,測試代碼

1. 定義一個類, TestXXX , 里面定義方法 testXXX.

這個命名不一定需要這樣,但是這樣的命名更容易懂得測試的意思,所以建議命名見名知意。

2. 添加junit的支持。

右鍵工程 --- add Library --- Junit --- Junit4

3. 在方法的上面加上注解 , 其實(shí)就是一個標(biāo)記。
????/***?使用junit執(zhí)行單元測試*/ public?class?TestDemo?{@Testpublic?void?testQuery()?{//?查詢Connection?conn?=?null;Statement?st?=?null;ResultSet?rs?=?null;try?{//?1.?獲取連接對象conn?=?JDBCUtil.getConn();//?2.?根據(jù)連接對象,得到statementst?=?conn.createStatement();//?3.?執(zhí)行sql語句,返回ResultSetString?sql?=?"select?*?from?t_stu";rs?=?st.executeQuery(sql);//?4.?遍歷結(jié)果集while?(rs.next())?{String?name?=?rs.getString("name");int?age?=?rs.getInt("age");System.out.println(name?+?"???"?+?age);}}?catch?(Exception?e)?{e.printStackTrace();}?finally?{JDBCUtil.release(conn,?st,?rs);}}@Testpublic?void?testInsert(){//?查詢Connection?conn?=?null;Statement?st?=?null;try?{//?1.?獲取連接對象conn?=?JDBCUtil.getConn();//?2.?根據(jù)連接對象,得到statementst?=?conn.createStatement();//3.?執(zhí)行添加String?sql?=?"insert?into?t_stu?values(null?,?'aobama'?,?59)";//影響的行數(shù),?,如果大于0?表明操作成功。?否則失敗int?result?=?st.executeUpdate(sql);if(result?>0?){System.out.println("添加成功");}else{System.out.println("添加失敗");}}?catch?(Exception?e)?{e.printStackTrace();}finally{JDBCUtil.release(conn,?st);}}@Testpublic?void?testDelete(){//?查詢Connection?conn?=?null;Statement?st?=?null;try?{//?1.?獲取連接對象conn?=?JDBCUtil.getConn();//?2.?根據(jù)連接對象,得到statementst?=?conn.createStatement();//3.?執(zhí)行添加String?sql?=?"delete?from?t_stu?where?name='aobama'";//影響的行數(shù),?,如果大于0?表明操作成功。?否則失敗int?result?=?st.executeUpdate(sql);if(result?>0?){System.out.println("刪除成功");}else{System.out.println("刪除失敗");}}?catch?(Exception?e)?{e.printStackTrace();}finally{JDBCUtil.release(conn,?st);}}@Testpublic?void?testUpdate(){//?查詢Connection?conn?=?null;Statement?st?=?null;try?{//?1.?獲取連接對象conn?=?JDBCUtil.getConn();//?2.?根據(jù)連接對象,得到statementst?=?conn.createStatement();//3.?執(zhí)行添加String?sql?=?"update?t_stu?set?age?=?26?where?name?='qyq'";//影響的行數(shù),?,如果大于0?表明操作成功。?否則失敗int?result?=?st.executeUpdate(sql);if(result?>0?){System.out.println("更新成功");}else{System.out.println("更新失敗");}}?catch?(Exception?e)?{e.printStackTrace();}finally{JDBCUtil.release(conn,?st);}} }
4. 光標(biāo)選中方法名字,然后右鍵執(zhí)行單元測試。 或者是打開outline視圖, 然后選擇方法右鍵執(zhí)行。

九、Dao模式

Data Access Object 數(shù)據(jù)訪問對象

DAO(Data Access Object) 數(shù)據(jù)訪問對象是一個面向?qū)ο蟮臄?shù)據(jù)庫接口,它顯露了 Microsoft Jet 數(shù)據(jù)庫引擎(由 Microsoft Access 所使用),并允許 Visual Basic 開發(fā)者通過 ODBC 像直接連接到其他數(shù)據(jù)庫一樣,直接連接到 Access 表。DAO 最適用于單系統(tǒng)應(yīng)用程序或小范圍本地分布使用。

1. 新建一個dao的接口, 里面聲明數(shù)據(jù)庫訪問規(guī)則
????/***?定義操作數(shù)據(jù)庫的方法*/public?interface?UserDao?{/***?查詢所有*/void?findAll();}
2. 新建一個dao的實(shí)現(xiàn)類,具體實(shí)現(xiàn)早前定義的規(guī)則
public?class?UserDaoImpl?implements?UserDao{@Overridepublic?void?findAll()?{Connection?conn?=?null;Statement?st?=?null;ResultSet?rs?=?null;try?{//1.?獲取連接對象conn?=?JDBCUtil.getConn();//2.?創(chuàng)建statement對象st?=?conn.createStatement();String?sql?=?"select?*?from?t_user";rs?=?st.executeQuery(sql);while(rs.next()){String?userName?=?rs.getString("username");String?password?=?rs.getString("password");System.out.println(userName+"="+password);}}?catch?(Exception?e)?{e.printStackTrace();}finally?{JDBCUtil.release(conn,?st,?rs);}}}
3. 直接使用實(shí)現(xiàn)
????@Testpublic?void?testFindAll(){UserDao?dao?=?new?UserDaoImpl();dao.findAll();}

十、Statement安全問題

1. Statement執(zhí)行 ,其實(shí)是拼接sql語句的。 先拼接sql語句,然后在一起執(zhí)行。
String?sql?=?"select?*?from?t_user?where?username='"+?username??+"'?and?password='"+?password?+"'";UserDao?dao?=?new?UserDaoImpl(); dao.login("admin",?"100234khsdf88'?or?'1=1");SELECT?*?FROM?t_user?WHERE?username='admin'?AND?PASSWORD='100234khsdf88'?or?'1=1'?//前面先拼接sql語句,?如果變量里面帶有了?數(shù)據(jù)庫的關(guān)鍵字,那么一并認(rèn)為是關(guān)鍵字。?不認(rèn)為是普通的字符串。? rs?=?st.executeQuery(sql);

PrepareStatement

該對象就是替換前面的statement對象。

  • 相比較以前的statement, 預(yù)先處理給定的sql語句,對其執(zhí)行語法檢查。 在sql語句里面使用 ? 占位符來替代后續(xù)要傳遞進(jìn)來的變量。 后面進(jìn)來的變量值,將會被看成是字符串,不會產(chǎn)生任何的關(guān)鍵字。
  • String?sql?=?"insert?into?t_user?values(null?,???,??)"; ps?=?conn.prepareStatement(sql);//給占位符賦值?從左到右數(shù)過來,1?代表第一個問號,?永遠(yuǎn)你是1開始。ps.setString(1,?userName);ps.setString(2,?password);

    PreparedStatement與Statement比較

    (1) 使用PreparedStatement,代碼的可讀性和可維護(hù)性比Statement高。

    (2) PreparedStatement 能最大可能提高性能。

    DBServer會對預(yù)編譯語句提供性能優(yōu)化。因?yàn)轭A(yù)編譯語句有可能被重復(fù)調(diào)用,所以語句在被DBServer的編譯器編譯后的執(zhí)行代碼被緩存下來,那么下次調(diào)用時只要是相同的預(yù)編譯語句就不需要編譯,只要將參數(shù)直接傳入編譯過的語句執(zhí)行代碼中就會得到執(zhí)行。

    在statement語句中,即使是相同操作但因?yàn)閿?shù)據(jù)內(nèi)容不一樣,所以整個語句本身不能匹配,沒有緩存語句的意義。事實(shí)是沒有數(shù)據(jù)庫會對普通語句編譯后的執(zhí)行代碼緩存。這樣每執(zhí)行一次都要對傳入的語句編譯一次。

    (3) PreparedStatement能保證安全性,但 Statement有sql注入等安全問題。

    十一、數(shù)據(jù)庫事務(wù)

    1. 概述

    在數(shù)據(jù)庫中,所謂事務(wù)是指一組邏輯操作單元,使數(shù)據(jù)從一種狀態(tài)變換到另一種狀態(tài)。

    為確保數(shù)據(jù)庫中數(shù)據(jù)的一致性,數(shù)據(jù)的操縱應(yīng)當(dāng)是離散的成組的邏輯單元:當(dāng)它全部完成時,數(shù)據(jù)的一致性可以保持,而當(dāng)這個單元中的一部分操作失敗,整個事務(wù)應(yīng)全部視為錯誤,所有從起始點(diǎn)以后的操作應(yīng)全部回退到開始狀態(tài)。

    事務(wù)的操作:先定義開始一個事務(wù),然后對數(shù)據(jù)作修改操作,這時如果提交(COMMIT),這些修改就永久地保存下來,如果回退(ROLLBACK),數(shù)據(jù)庫管理系統(tǒng)將放棄您所作的所有修改而回到開始事務(wù)時的狀態(tài)。

    2. 事務(wù)的ACID屬性

    2.1 原子性(Atomicity)

    原子性是指事務(wù)是一個不可分割的工作單位,事務(wù)中的操作要么都發(fā)生,要么都不發(fā)生。

    2.2 一致性(Consistency)

    事務(wù)必須使數(shù)據(jù)庫從一個一致性狀態(tài)變換到另外一個一致性狀態(tài)。(數(shù)據(jù)不被破壞)

    2.3 隔離性(Isolation)

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

    2.4 持久性(Durability)

    持久性是指一個事務(wù)一旦被提交,它對數(shù)據(jù)庫中數(shù)據(jù)的改變就是永久性的,接下來的其他操作和數(shù)據(jù)庫故障不應(yīng)該對其有任何影響。

    3. JDBC 事務(wù)處理

    在JDBC中,事務(wù)默認(rèn)是自動提交的,每次執(zhí)行一個 SQL 語句時,如果執(zhí)行成功,就會向數(shù)據(jù)庫自動提交,而不能回滾。

    為了讓多個 SQL 語句作為一個事務(wù)執(zhí)行,需調(diào)用 Connection 對象的 setAutoCommit(false); 以取消自動提交事務(wù):

    conn.setAutoCommit(false);

    在所有的 SQL 語句都成功執(zhí)行后,調(diào)用 commit(); 方法提交事務(wù)

    conn.commit();

    在出現(xiàn)異常時,調(diào)用 rollback(); 方法回滾事務(wù),一般再catch模塊中執(zhí)行回滾操作。

    conn.rollback();

    可以通過Connection的getAutoCommit()方法來獲得當(dāng)前事務(wù)的提交方式。

    注意:在MySQL中的數(shù)據(jù)庫存儲引擎InnoDB支持事務(wù),MyISAM不支持事務(wù)。

    十二、批量處理JDBC語句

    1. 概述

    當(dāng)需要批量插入或者更新記錄時。可以采用Java的批量更新機(jī)制,這一機(jī)制允許多條語句一次性提交給數(shù)據(jù)庫批量處理。通常情況下比單獨(dú)提交處理更有效率。

    JDBC的批量處理語句包括下面兩個方法:

    • addBatch(String):添加需要批量處理的SQL語句或是參數(shù);
    • executeBatch();執(zhí)行批量處理語句;

    通常我們會遇到兩種批量執(zhí)行SQL語句的情況:

    • 多條SQL語句的批量處理;
    • 一個SQL語句的批量傳參;

    2. Statement批量處理

    Statement?sm?=?conn.createStatement(); sm.addBatch(sql1); sm.addBatch(sql2); ... //批量處理 sm.executeBatch() //清除sm中積攢的參數(shù)列表 sm.clearBatch();

    3. PreparedStatement批量傳參

    preparedStatement?ps?=?conn.preparedStatement(sql); for(int?i=1;i<100000;i++){ps.setInt(1,?i);ps.setString(2,?"name"+i);ps.setString(3,?"email"+i);ps.addBatch();if((i+1)%1000==0){//批量處理ps.executeBatch();//清空ps中積攢的sqlps.clearBatch();} }

    注意:MySQL不支持批量處理。

    批量處理應(yīng)該設(shè)置一個上限,當(dāng)批量處理列表中的sql累積到一定數(shù)量后,就應(yīng)該執(zhí)行,并在執(zhí)行完成后,清空批量列表。

    一般在excel導(dǎo)入數(shù)據(jù)的時候會用到批處理。

    十三、使用 JDBC 處理元數(shù)據(jù)

    1. 概述

    Java 通過JDBC獲得連接以后,得到一個Connection 對象,可以從這個對象獲得有關(guān)數(shù)據(jù)庫管理系統(tǒng)的各種信息,包括數(shù)據(jù)庫中的各個表,表中的各個列,數(shù)據(jù)類型,觸發(fā)器,存儲過程等各方面的信息。根據(jù)這些信息,JDBC可以訪問一個實(shí)現(xiàn)事先并不了解的數(shù)據(jù)庫。

    獲取這些信息的方法都是在DatabaseMetaData類的對象上實(shí)現(xiàn)的,而DataBaseMetaData對象是在Connection對象上獲得的。

    2. 獲取數(shù)據(jù)庫元數(shù)據(jù)

    DatabaseMetaData 類中提供了許多方法用于獲得數(shù)據(jù)源的各種信息,通過這些方法可以非常詳細(xì)的了解數(shù)據(jù)庫的信息:

    • getURL():返回一個String類對象,代表數(shù)據(jù)庫的URL。
    • getUserName():返回連接當(dāng)前數(shù)據(jù)庫管理系統(tǒng)的用戶名。
    • isReadOnly():返回一個boolean值,指示數(shù)據(jù)庫是否只允許讀操作。
    • getDatabaseProductName():返回?cái)?shù)據(jù)庫的產(chǎn)品名稱。
    • getDatabaseProductVersion():返回?cái)?shù)據(jù)庫的版本號。
    • getDriverName():返回驅(qū)動驅(qū)動程序的名稱。
    • getDriverVersion():返回驅(qū)動程序的版本號。

    3. ResultSetMetaData

    可用于獲取關(guān)于 ResultSet 對象中列的類型和屬性信息的對象:

    • getColumnName(int column):獲取指定列的名稱
    • getColumnCount():返回當(dāng)前 ResultSet 對象中的列數(shù)。
    • getColumnTypeName(int column):檢索指定列的數(shù)據(jù)庫特定的類型名稱。
    • getColumnDisplaySize(int column):指示指定列的最大標(biāo)準(zhǔn)寬度,以字符為單位。
    • isNullable(int column):指示指定列中的值是否可以為 null。
    • isAutoIncrement(int column):指示是否自動為指定列進(jìn)行編號,這樣這些列仍然是只讀的。

    十四、創(chuàng)建可滾動、更新的記錄集

    1. Statement

    Statement?stmt?=?conn.createStatement(type,concurrency);

    2. PreparedStatement

    PreparedStatement?stmt?=?conn.prepareStatement(sql,type,concurrency);

    type說明:

    ResultSet的Type說明
    TYPE_FORWARD_ONLY結(jié)果集不能滾動,只可向前滾動
    TYPE_SCROLL_INSENSITIVE雙向滾動,但不及時更新,就是如果數(shù)據(jù)庫里的數(shù)據(jù)修改過,并不在ResultSet中反應(yīng)出來
    TYPE_SCROLL_SENSITIVE雙向滾動,并及時跟蹤數(shù)據(jù)庫的更新,以便更改ResultSet中的數(shù)據(jù)

    Concurrency(并發(fā)類型)說明:

    ResultSet的Concurrency(并發(fā)類型)說明
    CONCUR_READ_ONLY結(jié)果集不可用于更新數(shù)據(jù)庫
    CONCUR_UPDATABLE結(jié)果集可以用于更新數(shù)據(jù)庫

    3. ResultSet滾動的結(jié)果集使用

    First: 將指針移動到此 ResultSet 對象的第一行
    Last: 將指針移動到此 ResultSet 對象的最后一行
    beforeFirst: 將指針移動到此 ResultSet 對象的開頭,正好位于第一行之前
    afterLast: 將指針移動到此 ResultSet 對象的末尾,正好位于最后一行之后
    isFirst: 檢索指針是否位于此 ResultSet 對象的第一行
    isLast: 檢索指針是否位于此 ResultSet 對象的最后一行
    isBeforeFirst: 檢索指針是否位于此 ResultSet 對象的第一行之前
    isAfterLast: 檢索指針是否位于此 ResultSet 對象的最后一行之后
    Relative: 按相對行數(shù)(或正或負(fù))移動指針
    Next: 將指針從當(dāng)前位置下移一行
    Previous: 將指針移動到此 ResultSet 對象的上一行
    Absolute: 將指針移動到此 ResultSet 對象的給定行編號

    如:

    rs.absolute(80);?//將指針移動到ResultSet?對象的第80行記錄。

    注意:該特性對Oralce數(shù)據(jù)有效。但是在Mysql數(shù)據(jù)庫中無效,Mysql只支持TYPE_SCROLL_INSENSITIVE,CONCUR_READ_ONLY。

    十五、JDBC連接池

    1. 為什么要使用JDBC連接池

    普通的JDBC數(shù)據(jù)庫連接使用 DriverManager 來獲取,每次向數(shù)據(jù)庫建立連接的時候都要將 Connection 加載到內(nèi)存中,再驗(yàn)證用戶名和密碼。需要數(shù)據(jù)庫連接的時候,就向數(shù)據(jù)庫要求一個,執(zhí)行完成后再斷開連接。這樣的方式將會消耗大量的資源和時間。數(shù)據(jù)庫的連接資源并沒有得到很好的重復(fù)利用.若同時有幾百人甚至幾千人在線,頻繁的進(jìn)行數(shù)據(jù)庫連接操作將占用很多的系統(tǒng)資源,嚴(yán)重的甚至?xí)斐煞?wù)器的崩潰。

    對于每一次數(shù)據(jù)庫連接,使用完后都得斷開。否則,如果程序出現(xiàn)異常而未能關(guān)閉,將會導(dǎo)致數(shù)據(jù)庫系統(tǒng)中的內(nèi)存泄漏,最終將導(dǎo)致重啟數(shù)據(jù)庫。

    這種開發(fā)不能控制被創(chuàng)建的連接對象數(shù),系統(tǒng)資源會被毫無顧及的分配出去,如連接過多,也可能導(dǎo)致內(nèi)存泄漏,服務(wù)器崩潰。

    為解決傳統(tǒng)開發(fā)中的數(shù)據(jù)庫連接問題,可以采用數(shù)據(jù)庫連接池技術(shù)。

    2. 數(shù)據(jù)庫連接池(connection pool)

    數(shù)據(jù)庫連接池的基本思想就是為數(shù)據(jù)庫連接建立一個“緩沖池”。預(yù)先在緩沖池中放入一定數(shù)量的連接,當(dāng)需要建立數(shù)據(jù)庫連接時,只需從“緩沖池”中取出一個,使用完畢之后再放回去。

    數(shù)據(jù)庫連接池負(fù)責(zé)分配、管理和釋放數(shù)據(jù)庫連接,它允許應(yīng)用程序重復(fù)使用一個現(xiàn)有的數(shù)據(jù)庫連接,而不是重新建立一個。

    數(shù)據(jù)庫連接池在初始化時將創(chuàng)建一定數(shù)量的數(shù)據(jù)庫連接放到連接池中,這些數(shù)據(jù)庫連接的數(shù)量是由最小數(shù)據(jù)庫連接數(shù)來設(shè)定的。無論這些數(shù)據(jù)庫連接是否被使用,連接池都將一直保證至少擁有這么多的連接數(shù)量。連接池的最大數(shù)據(jù)庫連接數(shù)量限定了這個連接池能占有的最大連接數(shù),當(dāng)應(yīng)用程序向連接池請求的連接數(shù)超過最大連接數(shù)量時,這些請求將被加入到等待隊(duì)列中。

    3. 數(shù)據(jù)庫連接池工作原理

    2.png

    4. 使用數(shù)據(jù)庫連接池的優(yōu)點(diǎn)

    (1)資源重用:

    由于數(shù)據(jù)庫連接得以重用,避免了頻繁創(chuàng)建,釋放連接引起的大量性能開銷。在減少系統(tǒng)消耗的基礎(chǔ)上,另一方面也增加了系統(tǒng)運(yùn)行環(huán)境的平穩(wěn)性。

    (2)更快的系統(tǒng)反應(yīng)速度

    數(shù)據(jù)庫連接池在初始化過程中,往往已經(jīng)創(chuàng)建了若干數(shù)據(jù)庫連接置于連接池中備用。此時連接的初始化工作均已完成。對于業(yè)務(wù)請求處理而言,直接利用現(xiàn)有可用連接,避免了數(shù)據(jù)庫連接初始化和釋放過程的時間開銷,從而減少了系統(tǒng)的響應(yīng)時間。

    (3)新的資源分配手段

    對于多應(yīng)用共享同一數(shù)據(jù)庫的系統(tǒng)而言,可在應(yīng)用層通過數(shù)據(jù)庫連接池的配置,實(shí)現(xiàn)某一應(yīng)用最大可用數(shù)據(jù)庫連接數(shù)的限制,避免某一應(yīng)用獨(dú)占所有的數(shù)據(jù)庫資源。

    (4)統(tǒng)一的連接管理,避免數(shù)據(jù)庫連接泄露
    在較為完善的數(shù)據(jù)庫連接池實(shí)現(xiàn)中,可根據(jù)預(yù)先的占用超時設(shè)定,強(qiáng)制回收被占用連接,從而避免了常規(guī)數(shù)據(jù)庫連接操作中可能出現(xiàn)的資源泄露。

    5. 常用數(shù)據(jù)庫連接池介紹

    JDBC 的數(shù)據(jù)庫連接池使用 javax.sql.DataSource 來表示,DataSource 只是一個接口,該接口通常由服務(wù)器(Weblogic, WebSphere, Tomcat)提供實(shí)現(xiàn),也有一些開源組織提供實(shí)現(xiàn),如:

    • DBCP 數(shù)據(jù)庫連接池
    • C3P0 數(shù)據(jù)庫連接池
    • Proxpool 數(shù)據(jù)庫連接池

    其中,DBCP和C3P0用得比較多。

    Tomcat 在 7.0 以前的版本都是使用 commons-dbcp 做為連接池的實(shí)現(xiàn)。

    數(shù)據(jù)源和數(shù)據(jù)庫連接不同,數(shù)據(jù)源無需創(chuàng)建多個,它是產(chǎn)生數(shù)據(jù)庫連接的工廠,因此整個應(yīng)用只需要一個數(shù)據(jù)源即可。

    當(dāng)數(shù)據(jù)庫訪問結(jié)束后,程序還是像以前一樣關(guān)閉數(shù)據(jù)庫連接:conn.close(); 但它并沒有關(guān)閉數(shù)據(jù)庫的物理連接,它僅僅把數(shù)據(jù)庫連接釋放,歸還給了數(shù)據(jù)庫連接池。

    大概基本的就是這么多了,希望能夠幫助到大家,有問題可以交流溝通。

    ?

    總結(jié)

    以上是生活随笔為你收集整理的jdbc就是这么简单的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。