JDBC的应用
JDBC
1. 概述:
JDBC - Java DataBase Connectivity Java數(shù)據(jù)庫連接,
更簡單的說就是Java語言操作數(shù)據(jù)庫。
JDBC本質(zhì):其實(shí)是Sun公司定義的一套操作所有關(guān)
系型數(shù)據(jù)庫的規(guī)則,即接口,各個廠商去實(shí)現(xiàn)這套接
口,提供數(shù)據(jù)庫驅(qū)動Jar包,我們可以使用這套接口進(jìn)行
編程,真正執(zhí)行的代碼是數(shù)據(jù)庫驅(qū)動中的實(shí)現(xiàn)類。
其實(shí)這也是多態(tài)編程的優(yōu)點(diǎn):比如我調(diào)用了JDBC接
口中的一個getName()方法,實(shí)際執(zhí)行會根據(jù)不同的驅(qū)
動,調(diào)用不同的方法。2. 快速入門
步驟:
1. 導(dǎo)入驅(qū)動Jar包
2. 注冊驅(qū)動,讓程序知道我們用的是哪個版本的驅(qū)動
3. 獲取數(shù)據(jù)庫連接對象 Connection
4. 定義SQL
5. 獲取執(zhí)行SQL語句的對象:Statement
6. 執(zhí)行SQL,接收返回結(jié)果
7. 處理結(jié)果
8. 釋放資源
1. 創(chuàng)建一個空Project
2. 在空項(xiàng)目中添加Module選擇Java項(xiàng)目
?
選擇存儲路徑3. 在項(xiàng)目中新建包 和 對應(yīng)的快速入門演示案例類 4. 導(dǎo)入驅(qū)動jar包 在項(xiàng)目中添加一個文件夾,將驅(qū)動包復(fù)制到該包中,右 鍵---》 add as library...接下來就是代碼部分 演示案例 數(shù)據(jù)庫:CREATE DATABASE IF NOT EXISTS test CHARSET utf8; USE test; CREATE TABLE IF NOT EXISTS student( id INT,#學(xué)號 NAME VARCHAR(20),#姓名 age INT,#年齡 sex VARCHAR(5),#性別 address VARCHAR(100),#地址 math INT,#數(shù)學(xué) english INT#英語 ); INSERT INTO student (id,NAME,age,sex,address,math,english) VALUES (1,'馬云',18,'男','杭州',80,80), (2,'馬化騰',19,'男','深圳',75,60), (3,'埃隆馬斯克',31,'男','美國',76,93), (4,'扎克伯格',27,'男','美國',65,NULL), (5,'郎平',16,'女','上海',90,98), (6,'姚明',32,'男','上海',80,81); SELECT * FROM student; 測試案例: public class JdbcDemo1 {public static void main(String[] args) throws Exception { //1. 注冊驅(qū)動 Class.forName("com.mysql.jdbc.Driver"); //2.獲取數(shù)據(jù)庫連接對象 Connection connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test", "root", "root"); //3.定義sql語句 String sql = "update student set english=90 where id = 4"; //4獲取執(zhí)行sql的對象 Statement statement = connection.createStatement(); //5.執(zhí)行sql int count = statement.executeUpdate(sql); //6.處理結(jié)果 System.out.println(count); //7.釋放資源 statement.close(); connection.close(); } }3. JDBC過程中的對象詳解 3.1 Class.forName 疑問:這行代碼獲取到Class對象,卻又不用變量接收, 這行代碼有什么意義? 答:我們先去驅(qū)動包中找到Driver的源碼 源碼截圖?
JVM加載類的過程分為三步:加載,鏈接,初始 化。 在初始化這步,會執(zhí)行類構(gòu)造器方法clinit(),而 該方法是由變量的賦值動作 和 靜態(tài)代碼塊的語句合并產(chǎn) 生的。也就是說 類的加載器在加載指定的類的時候,如 果該類結(jié)構(gòu)中包含靜態(tài)代碼塊,則會執(zhí)行靜態(tài)代碼塊中 的代碼。因?yàn)?/span>JDBC的驅(qū)動有多種版本,所以JDBC規(guī)范中規(guī) 定,所有驅(qū)動都必須向驅(qū)動管理器注冊以區(qū)分各個版 本。而Driver類 中只有一個無參構(gòu)造 和 一個靜態(tài)代碼 塊,靜態(tài)代碼塊中的內(nèi)容 剛好就是 驅(qū)動向驅(qū)動管理器注 冊的代碼。所以:Class.forName()的目的是加載 Driver類的時候向驅(qū)動管理器注冊自己。 3.2 DriverManager : 驅(qū)動器管理對 象 功能: 1. 注冊驅(qū)動(Class.forName()中已經(jīng)解釋):MySql5 之后的驅(qū)動Jar可以不注冊驅(qū)動,它會自動幫我們注 冊。 2. 獲取數(shù)據(jù)庫連接對象: 方法: DriverManager.getConnection("URL", "用戶 名", "密碼"); 參數(shù): url:jdbc : mysql : // ip地址(域名):端口號 / 數(shù) 據(jù)庫名稱 注意:如果mysql是本機(jī)數(shù)據(jù)庫且端口是默 認(rèn)端口3306,則可以將ip地址(域名):端口 號部分省略jdbc:mysql:///test 用戶名:連接mysql的用戶名 密碼:對應(yīng)的密碼 3.3 Connection : 數(shù)據(jù)庫連接對象 功能: 1. 獲取執(zhí)行sql的對象 Statement createStatement() PreparedStatement prepareStatement(String sql) 2. 管理事務(wù): 開啟事務(wù):void setAutoCommit(boolean autoCommit):調(diào)用該方法,參數(shù)為false,即開啟 事務(wù) 提交事務(wù):commit() 回滾事務(wù): rollback() 3.4 Statement : 執(zhí)行靜態(tài)sql的對象 功能: 1. 執(zhí)行 靜態(tài)SQL 的對象 boolean execute(String sql) :可以執(zhí)行任意的 sql (不常用)int executeUpdate(String sql) :執(zhí)行 DML(insert、update、delete)語句、 DDL(create,alter、drop)語句 返回值int為影響行數(shù)可以作為語句是否執(zhí)行成 功的判斷標(biāo)準(zhǔn):>0 成功 ResultSet executeQuery(String sql) :執(zhí)行 DQL(select)語句 練習(xí): 1. 給student表中增加一條記錄 /** * 給student表中添加一條記錄 */ public class JdbcDemo2 { public static void main(String[] args) { Statement statement = null; Connection connection = null; try { //注冊驅(qū)動 Class.forName("com.mysql.jdbc.Driver"); //獲取連接對象connection = DriverManager.getConnection("jdbc:mysql://l ocalhost:3306/test? useUnicode=true&characterEncoding=utf8", "root", "root"); //編寫sql String sql = "insert into student (id,name,age,sex,address,math,english) values(21,'呵呵',18,'男','杭州',80,80)"; //獲取執(zhí)行sql的對象 statement = connection.createStatement(); //執(zhí)行sql int count = statement.executeUpdate(sql); //處理結(jié)果 if (count > 0) { System.out.println("添加成 功"); } else { System.out.println("添加失 敗"); } } catch (Exception e) { e.printStackTrace(); }finally { try {if (statement != null) { statement.close(); } if (connection != null) { connection.close(); } } catch (SQLException se) { se.printStackTrace(); } } } } 2.修改student表中的數(shù)據(jù) /** * 修改表中的數(shù)據(jù) */ public class JdbcDemo3 { public static void main(String[] args) { Statement statement = null; Connection connection = null; try { //注冊驅(qū)動Class.forName("com.mysql.jdbc.Driver"); //獲取連接對象 connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test? useUnicode=true&characterEncoding=utf8", "root", "root"); //編寫sql String sql = "update student set name ='丁磊' where id=20"; //獲取執(zhí)行sql的對象 statement = connection.createStatement(); //執(zhí)行sql int count = statement.executeUpdate(sql); //處理結(jié)果 if (count > 0) { System.out.println("修改成 功"); } else { System.out.println("修改失 敗"); } } catch (Exception e) { e.printStackTrace(); }finally {3.5 ResultSet : 結(jié)果集對象 功能: 1. next(): 與Itrator迭代器的next()功能類似,將 游標(biāo)移動到下一條記錄。 起始位置在表頭位置,所以 第一 次取數(shù)據(jù)需要先調(diào)用一次next()。 2. getXxx(參數(shù)):獲取數(shù)據(jù) Xxx: 代表數(shù)據(jù)類型:比如 int getInt() 參數(shù): int : 代表列的編號,從1開始 try { if (statement != null) { statement.close(); } if (connection != null) { connection.close(); } } catch (SQLException se) { se.printStackTrace(); } } } }String : 代表列名稱:比如 getString("name") 演示案例1:取一條記錄 /** * 查詢表中數(shù)據(jù),并取一條記錄 */ public class JdbcDemo4 { public static void main(String[] args) { Statement statement = null; Connection connection = null; ResultSet resultSet = null; try { //注冊驅(qū)動 Class.forName("com.mysql.jdbc.Driver"); //獲取連接對象 connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test? useUnicode=true&characterEncoding=utf8", "root", "root"); //編寫sql String sql = "select * from student"; //獲取執(zhí)行sql的對象statement = connection.createStatement(); //執(zhí)行sql resultSet = statement.executeQuery(sql); //處理結(jié)果 resultSet.next(); String name = resultSet.getString("name"); int age = resultSet.getInt("age"); System.out.println(name+"-- "+age); } catch (Exception e) { e.printStackTrace(); }finally { try { if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } if (connection != null) { connection.close(); } } catch (SQLException se) { se.printStackTrace(); } }} 演示案例2:遍歷結(jié)果集 通過查詢API,我們看到 next()方法 的返回值為 是否還有下一條數(shù)據(jù):false:沒有 true:有。那么我 們就可以根據(jù)next方法的返回值來作為循環(huán)的條件, 對結(jié)果集進(jìn)行遍歷 /** * 查詢表中數(shù)據(jù),遍歷結(jié)果集 */ public class JdbcDemo5 { public static void main(String[] args) { Statement statement = null; Connection connection = null; ResultSet resultSet = null; try { //注冊驅(qū)動 Class.forName("com.mysql.jdbc.Driver"); //獲取連接對象 connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test? useUnicode=true&characterEncoding=utf8", "root", "root");//編寫sql String sql = "select * from student"; //獲取執(zhí)行sql的對象 statement = connection.createStatement(); //執(zhí)行sql resultSet = statement.executeQuery(sql); //處理結(jié)果 while (resultSet.next()) { String name = resultSet.getString("name"); int age = resultSet.getInt("age"); System.out.println(name+"--"+age); } } catch (Exception e) { e.printStackTrace(); }finally { try { if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } if (connection != null) {connection.close(); } } catch (SQLException se) { se.printStackTrace(); } } } } 演示案例3:查詢Student表中所有數(shù)據(jù),并將數(shù)據(jù) 存儲到集合中 /** * 查詢Student表中數(shù)據(jù),并將所有數(shù)據(jù)存入到集合 中 */ public class JdbcDemo6 { public static void main(String[] args) { System.out.println(findAll()); } public static List<Student> findAll() { Statement statement = null; Connection connection = null; ResultSet resultSet = null;List<Student> list = new ArrayList<>(); try { //注冊驅(qū)動 Class.forName("com.mysql.jdbc.Driver"); //獲取連接對象 connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test? useUnicode=true&characterEncoding=utf8", "root", "root"); //編寫sql String sql = "select * from student"; //獲取執(zhí)行sql的對象 statement = connection.createStatement(); //執(zhí)行sql resultSet = statement.executeQuery(sql); //處理結(jié)果集 while (resultSet.next()) { int id = resultSet.getInt("id"); String name = resultSet.getString("name");int age = resultSet.getInt("age"); String sex = resultSet.getString("sex"); String address = resultSet.getString("address"); int math = resultSet.getInt("math"); int english = resultSet.getInt("english"); //封裝對象 Student student = new Student(id, name, age, sex, address, math, english); list.add(student); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } if (connection != null) { connection.close(); } } catch (SQLException se) {4. 抽取JDBC工具類 目的:簡化書寫 se.printStackTrace(); } } return list; } } import java.io.InputStream; import java.sql.Connection; import java.sql.Statement; import java.io.FileReader; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Properties; /** * 簡化JDBC操作的工具類 */public class JDBCUtils { //配置文件中的鍵對應(yīng)的屬性 private static String user; private static String password; private static String url; static{ //在靜態(tài)代碼塊中讀取配置信息,可以減少讀取 次數(shù) //讀取配置文件 try { //1.創(chuàng)建Properties對象 Properties properties = new Properties(); //2.加載文件 ClassLoader classLoader = JDBCUtils.class.getClassLoader(); InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc.prope rties"); properties.load(resourceAsStream); //獲取值 url = properties.getProperty("url"); user = properties.getProperty("user");password = properties.getProperty("password"); //注冊驅(qū)動 Class.forName(properties.getProperty("driv er")); } catch (Exception e) { e.printStackTrace(); } } /** * 獲取連接對象 * @return * @throws SQLException */ public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, user, password); } /** * 釋放資源(增刪改) * @param stmt 執(zhí)行sql語句對象 * @param conn mysql連接對象*/ public static void close(Statement stmt, Connection conn) { if (stmt != null) { try { stmt.close(); } catch (SQLException se) { se.printStackTrace(); } } //兩個異常處理不能寫一起,因?yàn)橐坏┣懊嬲Z句 出現(xiàn)異常,會導(dǎo)致后面資源不能正確被釋放造成資源浪費(fèi) if (conn != null) { try { conn.close(); } catch (SQLException se) { se.printStackTrace(); } } } /** * 釋放資源(查詢) * @param stmt 執(zhí)行sql語句對象 * @param conn mysql連接對象 * @param rs 存儲查詢結(jié)果集的對象 */ public static void close(Statement stmt, Connection conn, ResultSet rs) {if (stmt != null) { try { stmt.close(); } catch (SQLException se) { se.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException se) { se.printStackTrace(); } } if (rs != null) { try { rs.close(); } catch (SQLException se) { se.printStackTrace(); } } } } 注意1: 1. 抽取獲取連接對象的方法時,如果使用用戶傳參的方 式與實(shí)際代碼中獲取連接對象的代碼一致,達(dá)不到簡化效果,所以我們將url,user,password , driver 抽取到配置文件中 2. 配置文件信息的讀取涉及到IO流,所以應(yīng)該是次數(shù)越 少越好,所以我們將讀取配置文件 和 注冊驅(qū)動這兩 步放在靜態(tài)代碼塊中,這樣隨著類的加載,配置文件 只需讀取一次就可以有所有我們需要的信息。 演示案例:JDBC工具類使用 import org.wdzl.utils.JDBCUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /** * JDBCUtils使用:查詢Student表中id = 2 的學(xué)生 信息 */ public class JdbcDemo7 { public static void main(String[] args) throws SQLException { //獲取連接對象 Connection connection = JDBCUtils.getConnection(); //編寫sql String sql = "select * from student where id=2";//獲取statement對象 Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql); //處理結(jié)果 while (resultSet.next()) { System.out.println(resultSet.getString("na me")); } //釋放資源 JDBCUtils.close(statement,connection,resul tSet); } } 演示案例2:模擬登陸 分析: 1. 用戶輸入用戶名,密碼 2. 數(shù)據(jù)庫查詢是否有該信息 如果有,提示登錄成功 如果沒有,提示用戶名或密碼錯誤 3. 數(shù)據(jù)庫表準(zhǔn)備create table if not exists user( id int primary key auto_increment, username varchar(32) not null, password varchar(32) not null ) insert into user values(null,'test','test'); select * from user; 4. 測試案例 import org.wdzl.utils.JDBCUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Scanner; /** * 模擬用戶登錄 */ public class JdbcDemo8 { public static void main(String[] args) throws SQLException { Scanner sc = new Scanner(System.in);System.out.println("請輸入用戶 名:"); String username = sc.next(); System.out.println("請輸入密碼:"); String password = sc.next(); //登錄 boolean flag = login(username, password); if (flag) { System.out.println("登錄成 功"); } else { System.out.println("登錄失 敗"); } } /** * 登錄方法 * @param username 用戶名 * @param password 密碼 * @return */ public static boolean login(String username, String password) throws SQLException { if (username != null && password != null) { //獲取連接對象Connection connection = JDBCUtils.getConnection(); String sql = "select * from user where username='" + username + "' and password = '" + password + "'"; //獲取指定sql的對象 Statement statement = connection.createStatement(); //執(zhí)行sql ResultSet resultSet = statement.executeQuery(sql); //判斷 return resultSet.next(); } return false; } } 這個案例中有一個很大的BUG: 在控制臺輸入密碼時,我們這樣輸入,用戶名 隨 便輸 a'or'a'='a 最終即便是密碼用戶名不匹配,依舊可以登錄成功! 這就是我們常說的 SQL注入。 SQL注入:因?yàn)槟承╆P(guān)鍵字參與SQL語句拼接導(dǎo)致出現(xiàn)安全問 題。 如何解決SQL注入: 使用 PreparedStatement 5. PreparedStatement: 執(zhí)行 動態(tài)sql的對象 Statement 對象執(zhí)行的sql 是在編譯期就確定的 而PreparedStatement 執(zhí)行的sql語句中,參數(shù)使 用?占位符替代,在執(zhí)行時通過某些方法給相應(yīng)的占位 符賦值才能獲得完整的的SQL語句。這樣就有效的防止 了SQL注入 步驟: 1. 導(dǎo)入驅(qū)動Jar包 2. 注冊驅(qū)動,讓程序知道我們用的是哪個版本的驅(qū)動 3. 獲取數(shù)據(jù)庫連接對象 Connection 4. 定義SQL,參數(shù)使用占位符 5. 獲取執(zhí)行動態(tài)SQL語句的對象PreparedStatement :Connection.PreparedStatement(String sql) 6. 給?占位符賦值 setXxx(參數(shù)1,參數(shù)2)參數(shù)1:?的位置編號,從1開始 參數(shù)2: ?對應(yīng)的值 7. 執(zhí)行SQL,接收返回結(jié)果,執(zhí)行時不需要再傳遞sql語 句 8. 處理結(jié)果 9. 釋放資源 演示案例:改進(jìn)登錄代碼 /** * 登錄方法 * @param username 用戶名 * @param password 密碼 * @return */ public static boolean login(String username, String password) throws SQLException { if (username != null && password != null) { //獲取連接對象 Connection connection = JDBCUtils.getConnection(); String sql = "select * from user where username=? and password = ?"; System.out.println(sql); //獲取指定sql的對象 PreparedStatement statement = connection.prepareStatement(sql);后期開發(fā)我們都使用PreparedStatement。因?yàn)樗? 以防止SQL注入 6. JDBC 控制事務(wù) 6.1 事務(wù): 一個包含多個步驟的業(yè)務(wù)操作。如果這個業(yè)務(wù)被事務(wù)管 理,則這多個步驟要么同時成功,要么同時失敗。 6.2 事務(wù)操作 2. 提交事務(wù) //設(shè)置?的值 statement.setString(1, username); statement.setString(2,password); //執(zhí)行sql ResultSet resultSet = statement.executeQuery(); //判斷 return resultSet.next(); } return false; } 1. 開啟事務(wù)3. 回滾事務(wù) 6.3 使用Connection對象管理事務(wù) 1. 開啟事務(wù):void setAutoCommit(boolean autoCommit):調(diào)用該方法,參數(shù)為false,即開啟 事務(wù) 獲取Connection對象后即可開啟事務(wù) 2. 提交事務(wù):commit() 所有sql語句執(zhí)行完畢后即可提交事務(wù) 3. 回滾事務(wù): rollback() 只要捕獲異常,就在catch中進(jìn)行事務(wù)回滾 演示案例:JDBC控制事務(wù) 1. 準(zhǔn)備數(shù)據(jù)庫表 CREATE TABLE zhuanzhang( NAME VARCHAR(10), money DOUBLE(7,2) ); INSERT INTO zhuanzhang (NAME,money) VALUES ('張三',1000),('李四',1000); SELECT * FROM zhuanzhang; 2. 測試代碼 import org.wdzl.utils.JDBCUtils;import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; /** * JDBC 控制事務(wù) */ public class JdbcDemo10 { public static void main(String[] args) throws SQLException { Connection connection = null; PreparedStatement stmt1 = null; PreparedStatement stmt2 = null; try { //獲取連接 connection = JDBCUtils.getConnection(); //開啟事務(wù) connection.setAutoCommit(false); //定義sql //張三+500 String sql1 = "update zhuanzhang set money = money + ? where name = ?"; //李四-500String sql2 = "update zhuanzhang set money = money - ? where name = ?"; //獲取執(zhí)行sql對象 stmt1 = connection.prepareStatement(sql1); stmt2 = connection.prepareStatement(sql2); //設(shè)置參數(shù) stmt1.setDouble(1, 500); stmt1.setString(2,"張三"); stmt2.setDouble(1, 500); stmt2.setString(2,"李四"); //執(zhí)行更新 stmt1.execute();//更新操作不能 使用executeQuery()方法 //int a = 3 / 0;手動添加異常 stmt2.execute(); //提交事務(wù) connection.commit(); } catch (Exception e) { if (connection != null) { connection.rollback(); } e.printStackTrace(); }finally { //釋放資源7. 數(shù)據(jù)庫連接池 數(shù)據(jù)庫連接池類似于多線程種的線程池。 概述: 數(shù)據(jù)庫連接池就是一個容器,存放了一些數(shù)據(jù)庫連接 對象。 當(dāng)系統(tǒng)初始化完成后,容器被創(chuàng)建,容器會申請一些 連接對象,當(dāng)用戶訪問數(shù)據(jù)庫時,從容器中獲取連接對 象即可。訪問完之后,會將連接對象歸還給連接池。這 樣做可以提高效率,提高連接對象的復(fù)用,不必頻繁的 創(chuàng)建和釋放連接對象。 實(shí)現(xiàn): Java中提供了一個接口:javax . sql . DataSource。該接口是連接池技術(shù)的規(guī)范,具體實(shí)現(xiàn) 由數(shù)據(jù)庫廠商實(shí)現(xiàn)。該接口中定義了兩個方法: JDBCUtils.close(stmt1, connection); JDBCUtils.close(stmt2, null); } } }方法: 獲取連接:getConnection() 歸還連接:close() 。如果連接對象是從連接池中 獲得,那么調(diào)用Connection.close()將不再關(guān)閉連 接,而 是歸還連接。 連接池技術(shù)實(shí)現(xiàn) C3P0 :數(shù)據(jù)庫連接池技術(shù) Druid: 由阿里巴巴提供的數(shù)據(jù)庫連接池技術(shù) 7.1 C3P0連接池 步驟: 1. 導(dǎo)入Jar包 c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar 2. 定義配置文件: 規(guī)定名稱:c3p0.properties 或者 c3p0- confifig.xml 規(guī)定路徑:放在src目錄下 3. 創(chuàng)建核心對象 :數(shù)據(jù)庫連接池對象 ComboPooledDataSource 4. 獲取連接: getConnection 演示案例:入門案例1. 新建一個Module ,在Module中新建lib目錄,將jar包 拷貝的lib中,將配置文件拷貝到src下。不要忘記還 有mysql連接驅(qū)動jar包?
2. 查看配置文件 c3p0-confifig.xml?
3. 創(chuàng)建包和相應(yīng)的演示案例類?
package org.wdzl.datasource.c3p0; import com.mchange.v2.c3p0.ComboPooledDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; /** * C3P0演示案例 */ public class C3P0Demo1 { public static void main(String[] args) throws SQLException { //1.創(chuàng)建數(shù)據(jù)庫連接池對象 DataSource dataSource = new ComboPooledDataSource(); //2. 獲取連接對象 Connection connection = dataSource.getConnection(); //3. 查看連接對象 System.out.println(connection); //打印出對象信息就表示創(chuàng)建成功。 } }演示案例:配置參數(shù)演示 package org.wdzl.datasource.c3p0; import com.mchange.v2.c3p0.ComboPooledDataSource; import org.junit.Test; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; /** * C3P0 配置參數(shù)演示案例 */ public class C3P0Demo2 { /* 驗(yàn)證 最大連接數(shù) 和 等待時間 */ @Test public void test() throws SQLException { //1.創(chuàng)建數(shù)據(jù)庫連接池對象 DataSource dataSource = new ComboPooledDataSource(); //2. 獲取連接對象:通過循環(huán)獲取11個,前10 個都能獲取,第11個等待3秒就會報(bào)錯for (int i = 1; i <= 11; i++) { Connection connection = dataSource.getConnection(); System.out.println(i+" "+connection); } } /* 驗(yàn)證 連接池的連接會被歸還 */ @Test public void test2() throws SQLException { //1.創(chuàng)建數(shù)據(jù)庫連接池對象 DataSource dataSource = new ComboPooledDataSource(); for (int i = 1; i <= 11; i++) { Connection connection = dataSource.getConnection(); System.out.println(i+" "+connection); //歸還第三次循環(huán)的連接對象,看被歸還的對象 是否還出現(xiàn) if (i == 3) { connection.close(); } } } /*指定配置信息:如果new ComboPooledDataSource()方法不傳參數(shù),則默認(rèn)使用 配置文件中的default-config 如果指定字符串,使用指定名稱的配置信息 */ @Test public void test3() throws SQLException { //1.創(chuàng)建數(shù)據(jù)庫連接池對象 DataSource dataSource = new ComboPooledDataSource("otherc3p0"); for (int i = 1; i <= 10; i++) { Connection connection = dataSource.getConnection(); System.out.println(i+" "+connection); } } } 7.2 Druid 連接池 - 目前公認(rèn)最先進(jìn) 的連接池技術(shù) 步驟: 1. 導(dǎo)包:druid-1.0.9.jar 2. 定義配置文件: 是properties形式的可以叫任意名稱,可以放在任意目錄下 3. 加載配置文件:Properties 4. 獲取數(shù)據(jù)庫連接池對象:通過工廠來來獲取 DruidDataSourceFactory 5. 獲取連接:getConnection 演示案例: 1. 將jar包拷入lib目錄,將配置 druid.properties 文 件拷貝到src下 2. 創(chuàng)建包,在包中創(chuàng)建演示案例類?
3. 測試案例 package org.wdzl.datasource.druid;import com.alibaba.druid.pool.DruidDataSourceFac tory; import javax.sql.DataSource; import java.io.InputStream; import java.sql.Connection; import java.util.Properties; /** * Druid 演示 */ public class DruidDemo1 { public static void main(String[] args) throws Exception { //加載配置文件 Properties properties = new Properties(); InputStream resourceAsStream = DruidDemo1.class.getClassLoader().getReso urceAsStream("druid.properties"); properties.load(resourceAsStream); //獲取連接池對象 DataSource dataSource = DruidDataSourceFactory.createDataSource(p roperties); Connection connection = dataSource.getConnection();7.3 定義Druid 工具類 步驟: 1. 定義一個工具類:JDBCUtils 2. 提供靜態(tài)代碼塊,加載配置文件,初始化連接池對象 3. 提供方法 獲取連接的方法: 釋放資源: 獲取連接池的方法:因?yàn)橛幸恍┛蚣茏约簳ㄟ^連 接池獲取連接對象。所以也需要提供這樣一個方 法。 演示案例:JDBCUtils工具類 //查看連接對象 System.out.println(connection); } } package org.wdzl.datasource.utils; import com.alibaba.druid.pool.DruidDataSourceFacto ry; import com.mysql.jdbc.Statement;import javax.sql.DataSource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Properties; /** * Druid連接池工具類 */ public class JDBCUtils { //成員變量 private static DataSource dataSource; static{ try { //1. 加載配置文件 Properties properties = new Properties(); properties.load(JDBCUtils.class.getClassLo ader().getResourceAsStream("druid.propertie s")); //2. 獲取連接池對象 dataSource = DruidDataSourceFactory.createDataSource(pro perties); } catch (Exception e) { e.printStackTrace();} } /** * 獲取連接對象 * @return 連接對象 */ public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } /** * 釋放資源 * @param stmt 執(zhí)行sql的對象 * @param conn 連接數(shù)據(jù)庫的對象 */ public static void close(Statement stmt, Connection conn) { close(stmt,conn,null); } /** * 釋放資源 * @param stmt 執(zhí)行sql的對象 * @param conn 連接數(shù)據(jù)庫的對象 * @param rs 查詢結(jié)果集對象 */ public static void close(Statement stmt, Connection conn, ResultSet rs) {if (stmt != null) { try { stmt.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if (rs != null) { try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } }/** * 獲取連接池對象 * @return 連接池對象 */ public static DataSource getDataSource() { return dataSource; } } 演示案例2:使用工具類操作數(shù)據(jù)庫 /** * 使用JDBC工具類操作數(shù)據(jù)庫 */ public class DruidDemo2 { /* 向student表中添加一條數(shù)據(jù) */ @Test public void test() throws SQLException { //1. 獲取連接 Connection connection = JDBCUtils.getConnection(); //2.定義sql String sql = "insert into student (id,name,age,sex,address,math,english)" + " values(?,?,?,?,?,?,?)";8. Spring -JDBCTemplate 概述: Spring框架 對JDBC的簡單封裝,提供了一個 JDBCTemplate對象,來簡化JDBC的開發(fā)。 步驟: //3. 獲取執(zhí)行sql的對象 PreparedStatement pst = connection.prepareStatement(sql); //4. 給占位符賦值 pst.setInt(1, 101); pst.setString(2,"哈哈"); pst.setInt(3, 20); pst.setString(4,"女"); pst.setString(5,"西安"); pst.setInt(6,100); pst.setInt(7,100); //5.執(zhí)行 int count = pst.executeUpdate(); System.out.println(count); } }1. 導(dǎo)包:Spring的5個jar包,mysql連接驅(qū)動包,Druid 連接池jar包 2. 創(chuàng)建JdbcTemplate對象。依賴于數(shù)據(jù)源DataSource 3. 調(diào)用JdbcTemplate的方法來完成CRUD操作 update() : 執(zhí)行DML語句。增,刪,改語句。 queryForMap():查詢結(jié)果,將結(jié)果封裝為Map集 合 queryForList():查詢結(jié)果,將結(jié)果集封裝為List集 合 query():查詢結(jié)果,將結(jié)果封裝為JavaBean對象 queryForObject():查詢結(jié)果,將結(jié)果封裝為對象 練習(xí)中會對上述方法進(jìn)行詳細(xì)說明 入門案例: /** * JDBCTemplate 入門 * 新項(xiàng)目中我們需要使用JDBCTemplate, 我們需要先 添加Druid連接池的jar包和配置文件,添加JDBCUtiles 工具類,才能使用JDBCTemplate。 */ public class JDBCTemplateDemo { public static void main(String[] args) { //1. 創(chuàng)建JDBCTemplate對象 JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); //2.調(diào)用方法使用JDBCTemplate操作數(shù)據(jù)庫只關(guān)心sql的編寫 和 執(zhí) 行,其他的操作JDBCTemplate都會替我們完成。 演示案例:DML,DQL語句 需求:使用Student表,將Student實(shí)體類復(fù)制到當(dāng)前工 程中 1. 修改id為3 的學(xué)生數(shù)據(jù),將 age改為 30 2. 添加一條記錄 3. 刪除剛才添加的記錄 4. 查詢id為3的記錄,將其封裝為Map集合 5. 查詢所有記錄,將其封裝為List集合 6. 查詢所有記錄,將其封裝為Student對象的List 集合 7. 查詢name="埃隆馬斯克" 的學(xué)生信息,并封裝 成Student對象 String sql = "update student set sex=?,address=? where id=?"; // 有幾個?,就在update()方法中傳幾個參 數(shù)即可。 int update = template.update(sql, "男", "太原", 20); System.out.println(update); } } import org.junit.Test;import org.springframework.jdbc.core.BeanPropertyR owMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.wdzl.datasource.utils.JDBCUtils; import org.wdzl.pojo.Student; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import java.util.Map; /** * JDBCTemplate 入門 */ public class JDBCTemplateDemo2 { //方便使用 private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); /* 修改id為3 的學(xué)生數(shù)據(jù),將 age改為 30 */ @Test public void test() { //1.獲取連接對象 // JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());//2.編寫sql String sql = "update student set age=? where id=?"; //3.執(zhí)行sql,給占位符賦值 int update = template.update(sql, 30, 3); System.out.println(update); } /* 添加一條記錄 */ @Test public void test2() { //2.編寫sql String sql = "insert into student values(?,?,?,?,?,?,?)"; //3. 執(zhí)行 int update = template.update(sql, 22, "劉德華", 25, "男", "香港", 80, 75); System.out.println(update); } /* 刪除剛添加的記錄 */ @Test public void test3() { String sql = "delete from student where id=?";int update = template.update(sql, 22); System.out.println(update); } /* 查詢id為3的記錄,將其封裝為Map集合 queryForMap():將記錄的字段名作為鍵,字段值作 為值封裝到map集合中。 map格式 : 字段名 = 字段值 注意: 結(jié)果集長度只能是1 超過則會報(bào)錯 */ @Test public void test4() { String sql = "select * from student where id=?"; Map<String, Object> map = template.queryForMap(sql, 3); // String sql = "select * from student where id=? or id=?"; // Map<String, Object> map = template.queryForMap(sql, 3,4);//報(bào)錯,因?yàn)橛? 錄超過兩條 System.out.println(map); } /* 查詢所有記錄,將其封裝為List集合 queryForList():將每一條記錄封裝到map集合, 再把每一條記錄的map集合存入list集合*/ @Test public void test5() { String sql = "select * from student"; List<Map<String, Object>> maps = template.queryForList(sql); for (Map<String, Object> map : maps) { System.out.println(map); } } /* 查詢所有記錄,將其封裝為Student對象的 List集合--方式1 template.query(sql, new RowMapper<Student>() {mapRow()}); 該方法需要自己實(shí)現(xiàn)一個接口,每查詢一條記錄 就會執(zhí)行一次接口里面的mapRow()方法,將結(jié)果進(jìn)行封裝 */ @Test public void test6() { String sql = "select * from student"; List<Student> students = template.query(sql, new RowMapper<Student> () { @Overridepublic Student mapRow(ResultSet resultSet, int i) throws SQLException { int id = resultSet.getInt("id"); String name = resultSet.getString("name"); int age = resultSet.getInt("age"); String sex = resultSet.getString("sex"); String address = resultSet.getString("address"); int math = resultSet.getInt("math"); int english = resultSet.getInt("english"); Student student = new Student(id, name, age, sex, address, math, english); return student; } }); //遍歷集合 for (Student student : students) { System.out.println(student); } } /*查詢所有記錄,將其封裝為Student對象的List 集合-方式2 template.query(sql,new BeanPropertyRowMapper<實(shí)體類>(實(shí)體類.class)) 注意:如果用方式2,你的實(shí)體類中屬性的基本數(shù) 據(jù)類型一定要定義成包裝類型,否則如果你的查詢記錄中有 null的話 會報(bào)錯,因?yàn)? 基本數(shù)據(jù)類型中不能存null */ @Test public void test6_2() { String sql = "select * from student"; List<Student> students = template.query(sql,new BeanPropertyRowMapper<Student> (Student.class)); //遍歷集合 for (Student student : students) { System.out.println(student); } } /* 查詢name="埃隆馬斯克" 的學(xué)生信息,并封裝成 Student對象queryForObject(sql,new BeanPropertyRowMapper<>(封裝的實(shí)體類.class), 參數(shù)) */ @Test public void test7() { String sql = "select * from student where name=?"; Student student = template.queryForObject(sql, new BeanPropertyRowMapper<>(Student.class),"埃隆 馬斯克"); System.out.println(student); } }總結(jié)
- 上一篇: Louvain算法实现
- 下一篇: 前端radio单选框默认选中_开发记录篇