五、JDBC(复习)
目錄
一、JDBC核心組件
二、使用步驟
三、連接步驟
1.導(dǎo)包? ??
2.注冊JDBC驅(qū)動程序:
?3.數(shù)據(jù)庫URL配置,創(chuàng)建連接對象
(1)加載驅(qū)動
(2)獲得鏈接
(3)定義sql,創(chuàng)建狀態(tài)通道
(4)關(guān)閉資源
(5)完整代碼
四、SQl注入和預(yù)狀態(tài)通道PreparedStatement
五、多表操作
1.創(chuàng)建bean下的實體
2.創(chuàng)建接口和實現(xiàn)接口
3.在demo中打印查詢結(jié)果
4.結(jié)果
六、事務(wù)的應(yīng)用
1.自動提交/手動提交切換
2.事務(wù)的提交commit和回滾rollback
3.保存點(diǎn)Savepoints
七、JDBC批處理
?1.Statement批處理
2.PreparedStatement批處理
八、反射處理結(jié)果集
九、封裝工具類
十、屬性文件
十一、連接池
1.DBCP(不可以自動回收空閑連接)
2.C3P0(自動回收空閑連接)
3.Druid德魯伊(阿里開發(fā))
JDBC是一種用于執(zhí)行SQL語句的Java API,可以在各種平臺上使用Java,如Windows,Mac OS和各種版本的UNIX。
一、JDBC核心組件
DriverManager: 此類管理數(shù)據(jù)庫驅(qū)動程序列表。使用通信子協(xié)議將來自java應(yīng)用程序的連接請求 與適當(dāng)?shù)臄?shù)據(jù)庫驅(qū)動程序匹配。
Driver:此接口處理與數(shù)據(jù)庫服務(wù)器的通信,我們很少會直接與Driver對象進(jìn)行交互。而是使用 DriverManager對象來管理這種類型的對象。
Connection:該界面具有用于聯(lián)系數(shù)據(jù)庫的所有方法。連接對象表示通信上下文,即,與數(shù)據(jù)庫 的所有通信僅通過連接對象。
Statement:使用從此接口創(chuàng)建的對象將SQL語句提交到數(shù)據(jù)庫。除了執(zhí)行存儲過程之外,一些派 生接口還接受參數(shù)。
ResultSet:在使用Statement對象執(zhí)行SQL查詢后,這些對象保存從數(shù)據(jù)庫檢索的數(shù)據(jù)。它作為一 個迭代器,允許我們移動其數(shù)據(jù)。
SQLException:此類處理數(shù)據(jù)庫應(yīng)用程序中發(fā)生的任何錯誤
二、使用步驟
構(gòu)建JDBC應(yīng)用程序涉及以下六個步驟:
- 導(dǎo)入包:需要包含包含數(shù)據(jù)庫編程所需的JDBC類的包。大多數(shù)情況下,使用import java.sql.*就足夠 了。
- 注冊JDBC驅(qū)動程序:要求您初始化驅(qū)動程序,以便您可以打開與數(shù)據(jù)庫的通信通道。
- 打開連接:需要使用DriverManager.getConnection()方法創(chuàng)建一個Connection對象,該對象表 示與數(shù)據(jù)庫的物理連接。
- 執(zhí)行查詢:需要使用類型為Statement的對象來構(gòu)建和提交SQL語句到數(shù)據(jù)庫。
- 從結(jié)果集中提取數(shù)據(jù):需要使用相應(yīng)的ResultSet.getXXX()方法從結(jié)果集中檢索數(shù)據(jù)。
- 釋放資源:需要明確地關(guān)閉所有數(shù)據(jù)庫資源,而不依賴于JVM的垃圾收集。
三、連接步驟
1.導(dǎo)包? ??
import java.sql.*2.注冊JDBC驅(qū)動程序:
? ? ? ? 工程下創(chuàng)建lib文件夾,把mysql-connector壓縮包放入lib下,點(diǎn)擊左上角文件復(fù)選框-項目結(jié)構(gòu),打開此界面,點(diǎn)擊依賴
點(diǎn)擊+,單擊第一個JAR或目錄,找到剛剛的lib文件下壓縮包,點(diǎn)擊確定注入。
?
?3.數(shù)據(jù)庫URL配置,創(chuàng)建連接對象
這是為了創(chuàng)建一個格式正確的地址,指向要連接到的數(shù)據(jù)庫。
(1)加載驅(qū)動
Class.forName("com.mysql.cj.jdbc.Driver");//從本地工程加載驅(qū)動(2)獲得鏈接
創(chuàng)建數(shù)據(jù)庫連接對象
String userName = "root";//數(shù)據(jù)庫用戶名 String userPassword = "123456";//數(shù)據(jù)庫密碼 String url = "jdbc:mysql://localhost:3306/practice?serverTimezone=UTC";//數(shù)據(jù)庫mysql8 URL配置 Connection connection = DriverManager.getConnection(url,userName, userPassword);加載驅(qū)動程序后,可以使用DriverManager.getConnection()方法建立連接。
- getConnection(String url)
- getConnection(String url,Properties prop)
- getConnection(String url,String user,String password)
完整的連接地址:
第一種:jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC
? ? ? ??localhost:數(shù)據(jù)庫地址,本地就是這個?3306:數(shù)據(jù)庫所用的端口?yhp2:要打開的數(shù)據(jù)庫名
第二種:jdbc:mysql://localhost:3306/數(shù)據(jù)庫名?useSSL=false&useUnicode=true&characterEncoding=UTF-8
(3)定義sql,創(chuàng)建狀態(tài)通道
Statement statement = connection.createStatement(); ResultSet resultSet=statement.executeQuery("select * from student;");//執(zhí)行查詢while (resultSet.next()) {System.out.println("編號:"+resultSet.getInt("stuid")+"\t姓名" +resultSet.getString("name")+"\t\t生日"+resultSet.getDate("birthday")); } 執(zhí)行查詢的語句:返回的是一個結(jié)果集(executeQuery) resultSet=statement.executeQuery("select * from student;");執(zhí)行增刪改的語句,返回數(shù)大于0成功,否則失敗。(executeUpdate)
int i=statement.executeUpdate("update student set birthday='1011-1-1' ");
ResultSet:
用resultset接收結(jié)果集
(4)關(guān)閉資源
resultSet.close(); statement.close(); connection.close();(5)完整代碼
import java.sql.*;public class Demo1 {public static void main(String[] args) {Connection connection = null;Statement statement = null;ResultSet resultSet = null;try {Class.forName("com.mysql.cj.jdbc.Driver");String userName = "root";String userPassword = "123456";String url = "jdbc:mysql://localhost:3306/practice?serverTimezone=UTC";connection = DriverManager.getConnection(url, userName, userPassword);statement = connection.createStatement();resultSet = statement.executeQuery("select * from student;");while (resultSet.next()) {System.out.println("編號:" + resultSet.getInt("stuid")+ "\t姓名" + resultSet.getString("name")+ "\t\t生日" + resultSet.getDate("birthday"));}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();} finally {try {if (resultSet != null) {resultSet.close();}if (statement != null) {statement.close();}if (connection != null) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}} }四、SQl注入和預(yù)狀態(tài)通道PreparedStatement
? ? ? ? 現(xiàn)在網(wǎng)站比較安全,但還是要考慮到。sql注入就是在執(zhí)行sql語句的時候,比如輸入密碼的時候夾帶別的對數(shù)據(jù)庫安全有威脅的sql語句,如密碼輸入 or 1=1;那樣條件恒等,就可以隨便進(jìn)入
預(yù)狀態(tài)通道,PreparedStatement此種方式將sql語句中的輸入用?代替,確保sql語句的本塊在傳到了數(shù)據(jù)庫執(zhí)行時帶有引號如錯誤密碼變成了?' 123456 or 1=1',因為有了引號就都變成了字符串,or不會再被當(dāng)成條件執(zhí)行,之后按照從1開始1的下標(biāo)順序以此給?賦值
此代碼塊和第三模塊第(3)定義sql,創(chuàng)建狀態(tài)通道相通,經(jīng)過更改后變成下面,換了案例,用用戶名和密碼為例子
String sql = "select * from userVIP where userName=? and userPass=?";//問號占位 PreparedStatement preparedStatement = connection.prepareStatement(sql);//PreparedStatement接收數(shù)據(jù) preparedStatement.setString(1, "張三");//按照從1開始的下標(biāo)順序給sql語句中的問號賦值 preparedStatement.setString(2, "123456"); resultSet = preparedStatement.executeQuery();解決了sql注入后的完整代碼
import java.sql.*;public class Demo1 {public static void main(String[] args) {Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;try {Class.forName("com.mysql.cj.jdbc.Driver");String userName = "root";String userPassword = "123456";String url = "jdbc:mysql://localhost:3306/practice?serverTimezone=UTC";;connection = DriverManager.getConnection(url, userName, userPassword);String sql = "select * from userVIP where userName=? and userPass=?";preparedStatement = connection.prepareStatement(sql);preparedStatement.setString(1, "張三");preparedStatement.setString(2, "123456");resultSet = preparedStatement.executeQuery();while (resultSet.next()) {System.out.println("編號:"+resultSet.getInt("id")+"\t用戶名" +resultSet.getString("userName")+"\t\t密碼"+resultSet.getString("userPass"));}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();} finally {try {if (resultSet != null) {resultSet.close();}if (preparedStatement != null) {preparedStatement.close();}if (connection != null) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}} }
五、多表操作
? ? ? ? 一對多,多對一,一對一,多對多
記錄一個多對多
一個學(xué)生可以學(xué)很多課程,一個課程也可以有很多學(xué)生在學(xué),形成多對多關(guān)系。
1.創(chuàng)建bean下的實體
Student
package bean;import java.util.List;public class Student {private int stuid;private String stuname;private int teacherid;private List<Subject> subjects;public int getStuid() {return stuid;}public void setStuid(int stuid) {this.stuid = stuid;}public String getStuname() {return stuname;}public void setStuname(String stuname) {this.stuname = stuname;}public int getTeacherid() {return teacherid;}public void setTeacherid(int teacherid) {this.teacherid = teacherid;}public List<Subject> getSubjects() {return subjects;}public void setSubjects(List<Subject> subjects) {this.subjects = subjects;} }Subject
package bean;import java.util.List;public class Subject {private int subid;private String subname;private List<Student> students;public int getSubid() {return subid;}public void setSubid(int subid) {this.subid = subid;}public String getSubname() {return subname;}public void setSubname(String subname) {this.subname = subname;}public List<Student> getStudents() {return students;}public void setStudents(List<Student> students) {this.students = students;} }2.創(chuàng)建接口和實現(xiàn)接口
接口功能是根據(jù)科目id查找誰在學(xué)習(xí)本課程,或者根據(jù)學(xué)生id查找這個學(xué)生學(xué)習(xí)了哪些課程。
interface StudentSubjectDao package impl;import bean.Student; import bean.Subject;public interface StudentSubjectDao {Subject getSubjectId(int subid);Student getStudentId(int stuid); } StudentSubjectDaoImp package dao;import bean.Student; import bean.Subject; import impl.StudentSubjectDao;import java.sql.*; import java.util.ArrayList; import java.util.List;public class StudentSubjectDaoImp implements StudentSubjectDao {@Overridepublic Subject getSubjectId(int subid) {Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;try {Class.forName("com.mysql.cj.jdbc.Driver");String userName = "root";String userPass = "123456";String url = "jdbc:mysql://localhost:3306/practice?serverTimezone=UTC";connection = DriverManager.getConnection(url, userName, userPass);String SQL = "select * FROM middle m,student st,subject su where m.stuid=st.stuid and m.subid=su.subid and m.subid=?";preparedStatement = connection.prepareStatement(SQL);preparedStatement.setInt(1, subid);resultSet = preparedStatement.executeQuery();Subject subject = new Subject();List<Student> students = new ArrayList<>();while (resultSet.next()) {subject.setSubid(resultSet.getInt("subid"));subject.setSubname(resultSet.getString("subname"));Student student = new Student();student.setStuname(resultSet.getString("stuname"));student.setStuid(resultSet.getInt("stuid"));students.add(student);}subject.setStudents(students);return subject;} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();} finally {try {if (connection != null) {connection.close();}if (preparedStatement != null) {preparedStatement.close();}if (resultSet != null) {resultSet.close();}} catch (SQLException e) {e.printStackTrace();}}return null;}@Overridepublic Student getStudentId(int stuid) {Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;try {Class.forName("com.mysql.cj.jdbc.Driver");String user = "root";String pass = "123456";String url = "jdbc:mysql://localhost:3306/practice?serverTimezone=UTC";connection = DriverManager.getConnection(url, user, pass);String sql = "select * from middle m,student st,subject su where su.subid=m.subid and st.stuid=m.stuid and m.stuid=?";preparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1, stuid);resultSet = preparedStatement.executeQuery();Student student = new Student();List<Subject> subjects = new ArrayList<>();while (resultSet.next()) {student.setStuid(resultSet.getInt("stuid"));student.setStuname(resultSet.getString("stuname"));Subject subject = new Subject();subject.setSubname(resultSet.getString("subname"));subject.setSubid(resultSet.getInt("subid"));subjects.add(subject);}student.setSubjects(subjects);return student;} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();} finally {try {if (resultSet != null) {resultSet.close();}if (preparedStatement != null) {preparedStatement.close();}if (connection != null) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}return null;} }3.在demo中打印查詢結(jié)果
package com;import bean.Student; import bean.Subject; import dao.StudentSubjectDaoImp; import impl.StudentSubjectDao;import java.util.List;public class Demo2 {public static void main(String[] args) {StudentSubjectDao studentSubjectDao2 = new StudentSubjectDaoImp();Subject subject = studentSubjectDao2.getSubjectId(2);List<Student> students = subject.getStudents();System.out.println(subject.getSubname() + subject.getSubid());for (Student student1 : students) {System.out.println(student1.getStuname() + student1.getStuid());}System.out.println("___________________________");StudentSubjectDao studentSubjectDao = new StudentSubjectDaoImp();Student student = studentSubjectDao.getStudentId(1);List<Subject> subjects = student.getSubjects();System.out.println(student.getStuname());for (Subject subject2 : subjects) {System.out.println(subject2.getSubname());}}}4.結(jié)果
ui2 張三1 李四2 王五3 趙六4 花花5 瀟瀟6 ___________________________ 張三 java ui h5 c++進(jìn)程已結(jié)束,退出代碼0六、事務(wù)的應(yīng)用
1.自動提交/手動提交切換
如果JDBC連接處于自動提交模式,默認(rèn)情況下,則每個SQL語句在完成后都會提交到數(shù)據(jù)庫。 事務(wù)使您能夠控制是否和何時更改應(yīng)用于數(shù)據(jù)庫。它將單個SQL語句或一組SQL語句視為一個邏輯單 元,如果任何語句失敗,則整個事務(wù)將失敗。 要啟用手動事務(wù)支持,而不是JDBC驅(qū)動程序默認(rèn)使用的自動提交模式,請使用Connection對象的 setAutoCommit()方法。如果將boolean false傳遞給setAutoCommit(),則關(guān)閉自動提交。我們 可以傳遞一個布爾值true來重新打開它。
connection.setAutoCommit(false);//關(guān)閉事務(wù)自動提交 connection.setAutoCommit(true);2.事務(wù)的提交commit和回滾rollback
conn.commit( );//提交事務(wù) conn.rollback( );//回滾事務(wù)可以在事務(wù)寫完之后加上conn.commit( );來提交事務(wù),在catch代碼塊報異常時寫回滾rollback來撤銷此次事務(wù)的操作。
3.保存點(diǎn)Savepoints
新的JDBC 3.0 Savepoint接口為提供了額外的事務(wù)控制。 設(shè)置保存點(diǎn)時,可以在事務(wù)中定義邏輯回滾點(diǎn)。如果通過保存點(diǎn)發(fā)生錯誤,則可以使用回滾方法來撤消 所有更改或僅保存在保存點(diǎn)之后所做的更改。
Connection對象有兩種新的方法來管理保存點(diǎn)
- setSavepoint(String savepointName):定義新的保存點(diǎn)。它還返回一個Savepoint對象。
- releaseSavepoint(Savepoint savepointName):刪除保存點(diǎn)。請注意,它需要一個Savepoint 對象作為參數(shù)。此對象通常是由setSavepoint()方法生成的保存點(diǎn)。
上面一旦發(fā)生任何錯誤那么sql2就會執(zhí)行失敗,但是如果sql1的語句是對的,那么還可以正常執(zhí)行
如過此處沒有添加事務(wù)的概念,那么即使出現(xiàn)了其它的異常,只要sql語句沒問題,數(shù)據(jù)庫還是會改動數(shù)據(jù),這樣有些需要同步執(zhí)行的數(shù)據(jù)操作就會出現(xiàn)錯誤,如轉(zhuǎn)賬,一個加錢另一個卻沒減錢就很不合理。
七、JDBC批處理
?1.Statement批處理
????????- 使用createStatement()方法o創(chuàng)建Statement對象。
????????- 使用setAutoCommit()將auto-commit設(shè)置為false 。 (設(shè)置為手動提交事務(wù))
????????- 使用addBatch()方法在創(chuàng)建的語句對象上添加您喜歡的SQL語句到批處理中。
????????- 在創(chuàng)建的語句對象上使用executeBatch()方法執(zhí)行所有SQL語句。
????????- 最后,使用commit()方法提交所有更改。
2.PreparedStatement批處理
String SQL = "INSERT INTO Employees (id, first, last, age) VALUES(?, ?, ?, ?)";PreparedStatement pstmt = conn.prepareStatement(SQL);//處理sql語句 conn.setAutoCommit(false);//切換手動提交事務(wù)pstmt.setInt( 1, 400 );//問號賦值 pstmt.setString( 2, "Pappu" ); pstmt.setString( 3, "Singh" ); pstmt.setInt( 4, 33 );pstmt.addBatch();pstmt.setInt( 1, 401 ); pstmt.setString( 2, "Pawan" ); pstmt.setString( 3, "Singh" ); pstmt.setInt( 4, 31 );pstmt.addBatch();int[] count = stmt.executeBatch();//執(zhí)行所有sql語句conn.commit();八、反射處理結(jié)果集
????????
interface StudentSubjectDao package impl;import bean.Student;import java.util.List;public interface StudentSubjectDao {List<Student> getAllStudent(Class cla); } StudentSubjectDaoImp implements StudentSubjectDao package dao;import bean.Student; import bean.Subject; import impl.StudentSubjectDao;import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.*; import java.util.ArrayList; import java.util.List;public class StudentSubjectDaoImp implements StudentSubjectDao {@Overridepublic List<Student> getAllStudent(Class cla) {Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;try {Class.forName("com.mysql.cj.jdbc.Driver");String user = "root";String pass = "123456";String url = "jdbc:mysql://localhost:3306/practice?serverTimezone=UTC";connection = DriverManager.getConnection(url, user, pass);String sql = "select * from student";preparedStatement = connection.prepareStatement(sql);resultSet = preparedStatement.executeQuery();List students = new ArrayList<>();//1.得到數(shù)據(jù)庫的查詢結(jié)果的列信息ResultSetMetaData metaData = resultSet.getMetaData();int columnCount = metaData.getColumnCount();//得到列名,返回列名數(shù)量String[] columnNames = new String[columnCount];//列名for (int i = 0; i < columnCount; i++) {columnNames[i]=metaData.getColumnName(i+1);//將結(jié)果集中的列名取出來 // System.out.println(columnNames[i]);}//2.得到類中方法Method[] declaredMethods = cla.getDeclaredMethods();//通過傳來的cla得到student方法while (resultSet.next()) {try {Object stu=cla.getDeclaredConstructor().newInstance();//創(chuàng)建對象for (String columnName : columnNames) {//遍歷結(jié)果的列名String methodName = "set"+columnName;//set組合列名for (Method declaredMethod : declaredMethods) {//遍歷方法集if (declaredMethod.getName().equalsIgnoreCase(methodName)){//如果student中某個的方法名和set加結(jié)果集列名組合的方法名一樣declaredMethod.invoke(stu,resultSet.getObject(columnName));//調(diào)用這個set方法將結(jié)果集中的數(shù)據(jù)賦值給這個studen對象break;}}}students.add(stu);} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();}}return students;} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();} finally {try {if (resultSet != null) {resultSet.close();}if (preparedStatement != null) {preparedStatement.close();}if (connection != null) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}return null;} }demo
package com;import bean.Student; import dao.StudentSubjectDaoImp; import impl.StudentSubjectDao;import java.util.List;public class Demo3 {public static void main(String[] args) {StudentSubjectDao studentSubjectDao = new StudentSubjectDaoImp();List<Student> allStudent = studentSubjectDao.getAllStudent(Student.class);for (Student student : allStudent) {System.out.println(student.getStuid()+student.getStuname()+student.getTeacherid());}} }結(jié)果
1張三3 2李四1 3王五3 4趙六1 5花花1 6瀟瀟2九、封裝工具類
通過工具類可以極大地簡化代碼
DBUtils package util;import java.sql.*; import java.util.List;public class DBUtils {private Connection connection = null;private PreparedStatement preparedStatement = null;private ResultSet resultSet = null;private int count;//統(tǒng)計增刪改操作受影響的行數(shù)String userName = "root";String userPass = "123456";String url = "jdbc:mysql://localhost:3306/practice?serverTimezone=UTC";//加載驅(qū)動static {try {Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}}/*** 獲得連接*/protected Connection getConnection() {try {connection = DriverManager.getConnection(url, userName, userPass);} catch (SQLException e) {e.printStackTrace();}return connection;}/*** 得到預(yù)狀態(tài)通道*/protected PreparedStatement getPreparedStatement(String sql) {try {preparedStatement = getConnection().prepareStatement(sql);} catch (SQLException e) {e.printStackTrace();}return preparedStatement;}/*** 綁定參數(shù)* List保存的是給占位符所賦的值,即?部分的值*/protected void param(List list) {if (list != null && list.size() > 0) {for (int i = 0; i < list.size(); i++) {try {preparedStatement.setObject(i + 1, list.get(i));} catch (SQLException e) {e.printStackTrace();}}}}/*** 更新操作*/protected int upData(String sql, List list) {try {getPreparedStatement(sql);//獲得預(yù)狀態(tài)通道param(list);//補(bǔ)全sql中問號部分count = preparedStatement.executeUpdate();} catch (SQLException e) {e.printStackTrace();}return count;}/*** 查詢操作*/protected ResultSet query(String sql, List list) {try {getPreparedStatement(sql);//獲得預(yù)狀態(tài)通道param(list);//補(bǔ)全sql中問號部分resultSet = preparedStatement.executeQuery();} catch (SQLException e) {e.printStackTrace();}return resultSet;}/*** 關(guān)閉資源*/protected void closeAll() {try {if (connection != null) {connection.close();}if (preparedStatement != null) {preparedStatement.close();}if (resultSet != null) {resultSet.close();}} catch (SQLException e) {e.printStackTrace();}}} StudentSubjectDaoImp extends DBUtils implements StudentSubjectDao(繼承工具類以直接使用工具類DBUtils中的方法) public class StudentSubjectDaoImp extends DBUtils implements StudentSubjectDao { @Overridepublic Student getByStudentId(int stuid) {Student student = new Student();try {String sql="select * from student where stuid=?";List list = new ArrayList();list.add(stuid);ResultSet resultSet = query(sql,list);while (resultSet.next()){student.setStuid(resultSet.getInt("stuid"));student.setStuname(resultSet.getString("stuname"));}} catch (SQLException e) {e.printStackTrace();}return student;} }demo(通過學(xué)號查找人)
package com;import bean.Student; import dao.StudentSubjectDaoImp; import impl.StudentSubjectDao;public class Demo4 {public static void main(String[] args) {StudentSubjectDao studentSubjectDao = new StudentSubjectDaoImp();Student student = studentSubjectDao.getByStudentId(2);System.out.println(student.getStuid()+student.getStuname());} }十、屬性文件
用來存儲用戶名密碼url等信息
db.properties userName=root userPass=123456 url=jdbc:mysql://localhost:3306/practice?serverTimezone=UTC driver=com.mysql.cj.jdbc.Driver?加載驅(qū)動的兩種方法
//方法1 InputStream inputStream = 當(dāng)前類名.class.getClassLoader() .getResourceAsStream("db.properties"); Properties properties = new Properties(); properties.load(inputStream); dirverName = properties.getProperty("driver"); url = properties.getProperty("url"); username = properties.getProperty("user"); password = properties.getProperty("password");//方法2 ResourceBundle bundle = ResourceBundle.getBundle("db"); driver = bundle.getString("driver"); url = bundle.getString("url"); userName = bundle.getString("userName"); userPass = bundle.getString("userPass"); Class.forName(driver);完整DBUtils
package util;import java.sql.*; import java.util.List; import java.util.ResourceBundle;public class DBUtils {private Connection connection = null;private PreparedStatement preparedStatement = null;private ResultSet resultSet = null;private int count=0;//統(tǒng)計增刪改操作受影響的行數(shù)private static String userName;private static String userPass;private static String url;private static String driver;//加載驅(qū)動static {try {ResourceBundle bundle = ResourceBundle.getBundle("db");driver = bundle.getString("driver");url = bundle.getString("url");userName = bundle.getString("userName");userPass = bundle.getString("userPass");Class.forName(driver);} catch (ClassNotFoundException e) {e.printStackTrace();}}/*** 獲得連接*/protected Connection getConnection() {try {connection = DriverManager.getConnection(url, userName, userPass);} catch (SQLException e) {e.printStackTrace();}return connection;}/*** 得到預(yù)狀態(tài)通道*/protected PreparedStatement getPreparedStatement(String sql) {try {preparedStatement = getConnection().prepareStatement(sql);} catch (SQLException e) {e.printStackTrace();}return preparedStatement;}/*** 綁定參數(shù)* List保存的是給占位符所賦的值,即?部分的值*/protected void param(List list) {if (list != null && list.size() > 0) {for (int i = 0; i < list.size(); i++) {try {preparedStatement.setObject(i + 1, list.get(i));} catch (SQLException e) {e.printStackTrace();}}}}/*** 更新操作* 參數(shù)含義(sql語句,?占位符上的值)* @return 返回受影響的行數(shù)*/protected int upData(String sql, List list) {try {getPreparedStatement(sql);//獲得預(yù)狀態(tài)通道param(list);//補(bǔ)全sql中問號部分count = preparedStatement.executeUpdate();} catch (SQLException e) {e.printStackTrace();}return count;}/*** 查詢操作* 參數(shù)含義(sql語句,?占位符上的值)* @return 查詢數(shù)據(jù)庫返回的結(jié)果集*/protected ResultSet query(String sql, List list) {try {getPreparedStatement(sql);//獲得預(yù)狀態(tài)通道param(list);//補(bǔ)全sql中問號部分resultSet = preparedStatement.executeQuery();} catch (SQLException e) {e.printStackTrace();}return resultSet;}/*** 關(guān)閉資源*/protected void closeAll() {try {if (connection != null) {connection.close();}if (preparedStatement != null) {preparedStatement.close();}if (resultSet != null) {resultSet.close();}} catch (SQLException e) {e.printStackTrace();}}}十一、連接池
*連接池基本的思想是在系統(tǒng)初始化的時候,將數(shù)據(jù)庫連接作為對象存儲在內(nèi)存中,當(dāng)用戶需要訪問數(shù) 據(jù)庫時,并非建立一個新的連接,而是從連接池中取出一個已建立的空閑連接對象。使用完畢后,用戶 也并非將連接關(guān)閉,而是將連接放回連接池中,以供下一個請求訪問使用。而連接的建立、斷開都由連 接池自身來管理。同時,還可以通過設(shè)置連接池的參數(shù)來控制連接池中的初始連接數(shù)、連接的上下限數(shù) 以及每個連接的最大使用次數(shù)、最大空閑時間等等,也可以通過其自身的管理機(jī)制來監(jiān)視數(shù)據(jù)庫連接的數(shù)量、使用情況等。
*連接池用linklist默認(rèn)初始化十個連接,其中有commit,rollback等常規(guī)方法,其中close方法在關(guān)閉資源時并不是真的關(guān)閉了資源,而是使用linklist的addlast方法將這個連接放在了連接池尾部,以待下次調(diào)用。 *最小連接數(shù) : 是數(shù)據(jù)庫一直保持的數(shù)據(jù)庫連接數(shù),所以如果應(yīng)用程序?qū)?shù)據(jù)庫連接的使用量不大,將有大量的數(shù)據(jù)庫資源被浪費(fèi)。 *初始化連接數(shù): 連接池啟動時創(chuàng)建的初始化數(shù)據(jù)庫連接數(shù)量。 *最大連接數(shù): 是連接池能申請的最大連接數(shù),如果數(shù)據(jù)庫連接請求超過此數(shù),后面的數(shù)據(jù)庫連接請求被加入到等待隊列中。 *最大等待時間: 當(dāng)沒有可用連接時,連接池等待連接被歸還的最大時間,超過時間則拋出異常,可設(shè)置參數(shù)為 0 或者負(fù)數(shù) 使得無限等待( 根據(jù)不同連接池配置 ) 。| DBCP | C3P0 | DRUID | |
| 最小連接數(shù) | minldle(0) | minPoolSize(3) | mindle(o) |
| 初始化連接數(shù) | initialSize(0) | initialPoolSize(3) | initialSize(0) |
| 最大連接數(shù) | maxTotal(8) | maxPoolSize(15) | maxActive(8) |
| 最大等待時間 | maxWaitMillis(毫秒) | maxldleTime(0秒) | maxWait(毫秒) |
1.DBCP(不可以自動回收空閑連接)
先在lib文件夾下注入jia包
?將DBUtils部分的加載驅(qū)動和獲得連接部分做修改
private static BasicDataSource basicDataSource = new BasicDataSource(); //加載驅(qū)動static {ResourceBundle bundle = ResourceBundle.getBundle("db");driver = bundle.getString("driver");url = bundle.getString("url");userName = bundle.getString("userName");userPass = bundle.getString("userPass");basicDataSource.setUsername(userName);//獲取用戶名basicDataSource.setPassword(userPass);//獲取密碼basicDataSource.setUrl(url);//獲取urlbasicDataSource.setDriverClassName(driver);//獲取驅(qū)動位置basicDataSource.setInitialSize(10);//設(shè)置初始連接數(shù)}/*** 獲得連接*/protected Connection getConnection() {try {connection = basicDataSource.getConnection();//獲得連接} catch (SQLException e) {e.printStackTrace();}return connection;}2.C3P0(自動回收空閑連接)
在lib下注入jar包,src目錄下創(chuàng)建c3p0-config.xml文件
C3P0通過配置文件來完成所有操作,因此將原先db.properties中的信息寫入配置文件
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config><default-config><property name="driverClass">com.mysql.cj.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/practice?serverTimezone=UTC</property><property name="user">root</property><property name="password">123456</property><!-- 等待連接的超時時間,默認(rèn)為0,代表無限等待,單位是毫秒 --><property name="checkoutTimeout">30000</property><!-- 檢查空閑連接 默認(rèn)為0 代表不檢查 --><property name="idleConnectionTestPeriod">30</property><!-- 初始化連接 --><property name="initialPoolSize">10</property><!-- 最大空閑時間,超過這個時間的連接將被丟棄,默認(rèn)為0,代表永遠(yuǎn)不關(guān)閉 --><property name="maxIdleTime">30</property><!-- 最大連接數(shù) --><property name="maxPoolSize">100</property><!-- 最小連接數(shù) --><property name="minPoolSize">10</property><!-- preparedStatement的緩存大小 --><property name="maxStatements">200</property><!--當(dāng)連接池中的連接耗盡的時候c3p0一次同時獲取的連接數(shù)。默認(rèn)值: 3 --> <property name="AcquireIncrement">5</property></default-config></c3p0-config>寫入配置文件后不用再手動加載驅(qū)動?,static加載驅(qū)動部分不用再寫
private static ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();/*** 獲得連接*/protected Connection getConnection() {try {connection = comboPooledDataSource.getConnection();} catch (SQLException e) {e.printStackTrace();}return connection;}3.Druid德魯伊(阿里開發(fā))
????????它不僅僅是一個數(shù)據(jù)庫連接池,它還包含一個 ProxyDriver(代理驅(qū)動),一系列內(nèi)置的JDBC 組件庫,一個 SQL Parser(sql 解析器 ) 。支持所有 JDBC 兼 容的數(shù)據(jù)庫,包括Oracle 、 MySql 、 Derby 、 Postgresql 、 SQL Server 、 H2 等等。 ????????Druid針對 Oracle 和 MySql 做了特別優(yōu)化,比如 Oracle 的 PS Cache 內(nèi)存占用優(yōu)化, MySql 的 ping 檢測優(yōu)化。 ????????Druid提供了 MySql 、 Oracle 、 Postgresql 、 SQL-92 的 SQL 的完整支持,這是一個手寫的高性能 SQL Parser,支持 Visitor 模式,使得分析 SQL 的抽象語法樹很方便。 簡單SQL 語句用時 10 微秒以內(nèi),復(fù)雜 SQL 用時 30 微秒。 ????????通過Druid 提供的 SQL Parser 可以在 JDBC 層攔截 SQL 做相應(yīng)處理,比如說分庫分表、審計等。 Druid 防御SQL注入攻擊的WallFilter 就是通過 Druid 的 SQL Parser 分析語義實現(xiàn)的。 ????????Druid 是目前比較流行的高性能的,分布式列存儲的 OLAP 框架 ( 具體來說是 MOLAP) 。它有如下幾個特點(diǎn) 一 . 亞秒級查詢 ????????druid提供了快速的聚合能力以及亞秒級的 OLAP 查詢能力,多租戶的設(shè)計,是面向用戶分析應(yīng)用的理想方式。 二 . 實時數(shù)據(jù)注入 druid 支持流數(shù)據(jù)的注入,并提供了數(shù)據(jù)的事件驅(qū)動,保證在實時和離線環(huán)境下事件的實效性和統(tǒng)一性 三 . 可擴(kuò)展的 PB 級存儲 druid 集群可以很方便的擴(kuò)容到 PB 的數(shù)據(jù)量,每秒百 萬級別的數(shù)據(jù)注入。即便在加大數(shù)據(jù)規(guī)模的情況下,也能保證時其效性 四 . 多環(huán)境部署 druid 既可以運(yùn)行在商業(yè)的硬件上,也可以運(yùn)行在云上。它可以從多種數(shù)據(jù)系統(tǒng)中注入數(shù)據(jù),包括 hadoop , spark , kafka , storm 和 samza 等 五 . 豐富的社區(qū) 使用方法: 在lib下注入jar包 獲得對象,手動獲取地址,需要注意德魯伊默認(rèn)最大活躍連接數(shù)量是8因此如果要設(shè)置大于8的活躍連接數(shù)應(yīng)該先設(shè)置上限?
//Druid對象private static DruidDataSource druidDataSource = new DruidDataSource();//加載驅(qū)動static {ResourceBundle bundle = ResourceBundle.getBundle("db");driver = bundle.getString("driver");url = bundle.getString("url");userName = bundle.getString("userName");userPass = bundle.getString("userPass");druidDataSource.setUrl(url);druidDataSource.setUsername(userName);druidDataSource.setPassword(userPass);druidDataSource.setDriverClassName(driver);druidDataSource.setMaxActive(20);//設(shè)置活躍連接上限druidDataSource.setInitialSize(20);//設(shè)置連接數(shù)}/*** 獲得連接*/protected Connection getConnection() {try {connection = druidDataSource.getConnection();} catch (SQLException e) {e.printStackTrace();}return connection;}總結(jié)
以上是生活随笔為你收集整理的五、JDBC(复习)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2020年中国无缝钢管行业发展现状及竞争
- 下一篇: HTC M8t unlock Bootl