JDBC的应用
JDBC
1. 概述:
JDBC - Java DataBase Connectivity Java數據庫連接,
更簡單的說就是Java語言操作數據庫。
JDBC本質:其實是Sun公司定義的一套操作所有關
系型數據庫的規則,即接口,各個廠商去實現這套接
口,提供數據庫驅動Jar包,我們可以使用這套接口進行
編程,真正執行的代碼是數據庫驅動中的實現類。
其實這也是多態編程的優點:比如我調用了JDBC接
口中的一個getName()方法,實際執行會根據不同的驅
動,調用不同的方法。2. 快速入門
步驟:
1. 導入驅動Jar包
2. 注冊驅動,讓程序知道我們用的是哪個版本的驅動
3. 獲取數據庫連接對象 Connection
4. 定義SQL
5. 獲取執行SQL語句的對象:Statement
6. 執行SQL,接收返回結果
7. 處理結果
8. 釋放資源
1. 創建一個空Project
2. 在空項目中添加Module選擇Java項目
?
選擇存儲路徑3. 在項目中新建包 和 對應的快速入門演示案例類 4. 導入驅動jar包 在項目中添加一個文件夾,將驅動包復制到該包中,右 鍵---》 add as library...接下來就是代碼部分 演示案例 數據庫:CREATE DATABASE IF NOT EXISTS test CHARSET utf8; USE test; CREATE TABLE IF NOT EXISTS student( id INT,#學號 NAME VARCHAR(20),#姓名 age INT,#年齡 sex VARCHAR(5),#性別 address VARCHAR(100),#地址 math INT,#數學 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. 注冊驅動 Class.forName("com.mysql.jdbc.Driver"); //2.獲取數據庫連接對象 Connection connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test", "root", "root"); //3.定義sql語句 String sql = "update student set english=90 where id = 4"; //4獲取執行sql的對象 Statement statement = connection.createStatement(); //5.執行sql int count = statement.executeUpdate(sql); //6.處理結果 System.out.println(count); //7.釋放資源 statement.close(); connection.close(); } }3. JDBC過程中的對象詳解 3.1 Class.forName 疑問:這行代碼獲取到Class對象,卻又不用變量接收, 這行代碼有什么意義? 答:我們先去驅動包中找到Driver的源碼 源碼截圖?
JVM加載類的過程分為三步:加載,鏈接,初始 化。 在初始化這步,會執行類構造器方法clinit(),而 該方法是由變量的賦值動作 和 靜態代碼塊的語句合并產 生的。也就是說 類的加載器在加載指定的類的時候,如 果該類結構中包含靜態代碼塊,則會執行靜態代碼塊中 的代碼。因為JDBC的驅動有多種版本,所以JDBC規范中規 定,所有驅動都必須向驅動管理器注冊以區分各個版 本。而Driver類 中只有一個無參構造 和 一個靜態代碼 塊,靜態代碼塊中的內容 剛好就是 驅動向驅動管理器注 冊的代碼。所以:Class.forName()的目的是加載 Driver類的時候向驅動管理器注冊自己。 3.2 DriverManager : 驅動器管理對 象 功能: 1. 注冊驅動(Class.forName()中已經解釋):MySql5 之后的驅動Jar可以不注冊驅動,它會自動幫我們注 冊。 2. 獲取數據庫連接對象: 方法: DriverManager.getConnection("URL", "用戶 名", "密碼"); 參數: url:jdbc : mysql : // ip地址(域名):端口號 / 數 據庫名稱 注意:如果mysql是本機數據庫且端口是默 認端口3306,則可以將ip地址(域名):端口 號部分省略jdbc:mysql:///test 用戶名:連接mysql的用戶名 密碼:對應的密碼 3.3 Connection : 數據庫連接對象 功能: 1. 獲取執行sql的對象 Statement createStatement() PreparedStatement prepareStatement(String sql) 2. 管理事務: 開啟事務:void setAutoCommit(boolean autoCommit):調用該方法,參數為false,即開啟 事務 提交事務:commit() 回滾事務: rollback() 3.4 Statement : 執行靜態sql的對象 功能: 1. 執行 靜態SQL 的對象 boolean execute(String sql) :可以執行任意的 sql (不常用)int executeUpdate(String sql) :執行 DML(insert、update、delete)語句、 DDL(create,alter、drop)語句 返回值int為影響行數可以作為語句是否執行成 功的判斷標準:>0 成功 ResultSet executeQuery(String sql) :執行 DQL(select)語句 練習: 1. 給student表中增加一條記錄 /** * 給student表中添加一條記錄 */ public class JdbcDemo2 { public static void main(String[] args) { Statement statement = null; Connection connection = null; try { //注冊驅動 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)"; //獲取執行sql的對象 statement = connection.createStatement(); //執行sql int count = statement.executeUpdate(sql); //處理結果 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表中的數據 /** * 修改表中的數據 */ public class JdbcDemo3 { public static void main(String[] args) { Statement statement = null; Connection connection = null; try { //注冊驅動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"; //獲取執行sql的對象 statement = connection.createStatement(); //執行sql int count = statement.executeUpdate(sql); //處理結果 if (count > 0) { System.out.println("修改成 功"); } else { System.out.println("修改失 敗"); } } catch (Exception e) { e.printStackTrace(); }finally {3.5 ResultSet : 結果集對象 功能: 1. next(): 與Itrator迭代器的next()功能類似,將 游標移動到下一條記錄。 起始位置在表頭位置,所以 第一 次取數據需要先調用一次next()。 2. getXxx(參數):獲取數據 Xxx: 代表數據類型:比如 int getInt() 參數: int : 代表列的編號,從1開始 try { if (statement != null) { statement.close(); } if (connection != null) { connection.close(); } } catch (SQLException se) { se.printStackTrace(); } } } }String : 代表列名稱:比如 getString("name") 演示案例1:取一條記錄 /** * 查詢表中數據,并取一條記錄 */ public class JdbcDemo4 { public static void main(String[] args) { Statement statement = null; Connection connection = null; ResultSet resultSet = null; try { //注冊驅動 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"; //獲取執行sql的對象statement = connection.createStatement(); //執行sql resultSet = statement.executeQuery(sql); //處理結果 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:遍歷結果集 通過查詢API,我們看到 next()方法 的返回值為 是否還有下一條數據:false:沒有 true:有。那么我 們就可以根據next方法的返回值來作為循環的條件, 對結果集進行遍歷 /** * 查詢表中數據,遍歷結果集 */ public class JdbcDemo5 { public static void main(String[] args) { Statement statement = null; Connection connection = null; ResultSet resultSet = null; try { //注冊驅動 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"; //獲取執行sql的對象 statement = connection.createStatement(); //執行sql resultSet = statement.executeQuery(sql); //處理結果 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表中所有數據,并將數據 存儲到集合中 /** * 查詢Student表中數據,并將所有數據存入到集合 中 */ 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 { //注冊驅動 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"; //獲取執行sql的對象 statement = connection.createStatement(); //執行sql resultSet = statement.executeQuery(sql); //處理結果集 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 { //配置文件中的鍵對應的屬性 private static String user; private static String password; private static String url; static{ //在靜態代碼塊中讀取配置信息,可以減少讀取 次數 //讀取配置文件 try { //1.創建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"); //注冊驅動 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 執行sql語句對象 * @param conn mysql連接對象*/ public static void close(Statement stmt, Connection conn) { if (stmt != null) { try { stmt.close(); } catch (SQLException se) { se.printStackTrace(); } } //兩個異常處理不能寫一起,因為一旦前面語句 出現異常,會導致后面資源不能正確被釋放造成資源浪費 if (conn != null) { try { conn.close(); } catch (SQLException se) { se.printStackTrace(); } } } /** * 釋放資源(查詢) * @param stmt 執行sql語句對象 * @param conn mysql連接對象 * @param rs 存儲查詢結果集的對象 */ 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. 抽取獲取連接對象的方法時,如果使用用戶傳參的方 式與實際代碼中獲取連接對象的代碼一致,達不到簡化效果,所以我們將url,user,password , driver 抽取到配置文件中 2. 配置文件信息的讀取涉及到IO流,所以應該是次數越 少越好,所以我們將讀取配置文件 和 注冊驅動這兩 步放在靜態代碼塊中,這樣隨著類的加載,配置文件 只需讀取一次就可以有所有我們需要的信息。 演示案例: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 的學生 信息 */ 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); //處理結果 while (resultSet.next()) { System.out.println(resultSet.getString("na me")); } //釋放資源 JDBCUtils.close(statement,connection,resul tSet); } } 演示案例2:模擬登陸 分析: 1. 用戶輸入用戶名,密碼 2. 數據庫查詢是否有該信息 如果有,提示登錄成功 如果沒有,提示用戶名或密碼錯誤 3. 數據庫表準備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(); //執行sql ResultSet resultSet = statement.executeQuery(sql); //判斷 return resultSet.next(); } return false; } } 這個案例中有一個很大的BUG: 在控制臺輸入密碼時,我們這樣輸入,用戶名 隨 便輸 a'or'a'='a 最終即便是密碼用戶名不匹配,依舊可以登錄成功! 這就是我們常說的 SQL注入。 SQL注入:因為某些關鍵字參與SQL語句拼接導致出現安全問 題。 如何解決SQL注入: 使用 PreparedStatement 5. PreparedStatement: 執行 動態sql的對象 Statement 對象執行的sql 是在編譯期就確定的 而PreparedStatement 執行的sql語句中,參數使 用?占位符替代,在執行時通過某些方法給相應的占位 符賦值才能獲得完整的的SQL語句。這樣就有效的防止 了SQL注入 步驟: 1. 導入驅動Jar包 2. 注冊驅動,讓程序知道我們用的是哪個版本的驅動 3. 獲取數據庫連接對象 Connection 4. 定義SQL,參數使用占位符 5. 獲取執行動態SQL語句的對象PreparedStatement :Connection.PreparedStatement(String sql) 6. 給?占位符賦值 setXxx(參數1,參數2)參數1:?的位置編號,從1開始 參數2: ?對應的值 7. 執行SQL,接收返回結果,執行時不需要再傳遞sql語 句 8. 處理結果 9. 釋放資源 演示案例:改進登錄代碼 /** * 登錄方法 * @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);后期開發我們都使用PreparedStatement。因為它可 以防止SQL注入 6. JDBC 控制事務 6.1 事務: 一個包含多個步驟的業務操作。如果這個業務被事務管 理,則這多個步驟要么同時成功,要么同時失敗。 6.2 事務操作 2. 提交事務 //設置?的值 statement.setString(1, username); statement.setString(2,password); //執行sql ResultSet resultSet = statement.executeQuery(); //判斷 return resultSet.next(); } return false; } 1. 開啟事務3. 回滾事務 6.3 使用Connection對象管理事務 1. 開啟事務:void setAutoCommit(boolean autoCommit):調用該方法,參數為false,即開啟 事務 獲取Connection對象后即可開啟事務 2. 提交事務:commit() 所有sql語句執行完畢后即可提交事務 3. 回滾事務: rollback() 只要捕獲異常,就在catch中進行事務回滾 演示案例:JDBC控制事務 1. 準備數據庫表 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 控制事務 */ public class JdbcDemo10 { public static void main(String[] args) throws SQLException { Connection connection = null; PreparedStatement stmt1 = null; PreparedStatement stmt2 = null; try { //獲取連接 connection = JDBCUtils.getConnection(); //開啟事務 connection.setAutoCommit(false); //定義sql //張三+500 String sql1 = "update zhuanzhang set money = money + ? where name = ?"; //李四-500String sql2 = "update zhuanzhang set money = money - ? where name = ?"; //獲取執行sql對象 stmt1 = connection.prepareStatement(sql1); stmt2 = connection.prepareStatement(sql2); //設置參數 stmt1.setDouble(1, 500); stmt1.setString(2,"張三"); stmt2.setDouble(1, 500); stmt2.setString(2,"李四"); //執行更新 stmt1.execute();//更新操作不能 使用executeQuery()方法 //int a = 3 / 0;手動添加異常 stmt2.execute(); //提交事務 connection.commit(); } catch (Exception e) { if (connection != null) { connection.rollback(); } e.printStackTrace(); }finally { //釋放資源7. 數據庫連接池 數據庫連接池類似于多線程種的線程池。 概述: 數據庫連接池就是一個容器,存放了一些數據庫連接 對象。 當系統初始化完成后,容器被創建,容器會申請一些 連接對象,當用戶訪問數據庫時,從容器中獲取連接對 象即可。訪問完之后,會將連接對象歸還給連接池。這 樣做可以提高效率,提高連接對象的復用,不必頻繁的 創建和釋放連接對象。 實現: Java中提供了一個接口:javax . sql . DataSource。該接口是連接池技術的規范,具體實現 由數據庫廠商實現。該接口中定義了兩個方法: JDBCUtils.close(stmt1, connection); JDBCUtils.close(stmt2, null); } } }方法: 獲取連接:getConnection() 歸還連接:close() 。如果連接對象是從連接池中 獲得,那么調用Connection.close()將不再關閉連 接,而 是歸還連接。 連接池技術實現 C3P0 :數據庫連接池技術 Druid: 由阿里巴巴提供的數據庫連接池技術 7.1 C3P0連接池 步驟: 1. 導入Jar包 c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar 2. 定義配置文件: 規定名稱:c3p0.properties 或者 c3p0- confifig.xml 規定路徑:放在src目錄下 3. 創建核心對象 :數據庫連接池對象 ComboPooledDataSource 4. 獲取連接: getConnection 演示案例:入門案例1. 新建一個Module ,在Module中新建lib目錄,將jar包 拷貝的lib中,將配置文件拷貝到src下。不要忘記還 有mysql連接驅動jar包?
2. 查看配置文件 c3p0-confifig.xml?
3. 創建包和相應的演示案例類?
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.創建數據庫連接池對象 DataSource dataSource = new ComboPooledDataSource(); //2. 獲取連接對象 Connection connection = dataSource.getConnection(); //3. 查看連接對象 System.out.println(connection); //打印出對象信息就表示創建成功。 } }演示案例:配置參數演示 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 配置參數演示案例 */ public class C3P0Demo2 { /* 驗證 最大連接數 和 等待時間 */ @Test public void test() throws SQLException { //1.創建數據庫連接池對象 DataSource dataSource = new ComboPooledDataSource(); //2. 獲取連接對象:通過循環獲取11個,前10 個都能獲取,第11個等待3秒就會報錯for (int i = 1; i <= 11; i++) { Connection connection = dataSource.getConnection(); System.out.println(i+" "+connection); } } /* 驗證 連接池的連接會被歸還 */ @Test public void test2() throws SQLException { //1.創建數據庫連接池對象 DataSource dataSource = new ComboPooledDataSource(); for (int i = 1; i <= 11; i++) { Connection connection = dataSource.getConnection(); System.out.println(i+" "+connection); //歸還第三次循環的連接對象,看被歸還的對象 是否還出現 if (i == 3) { connection.close(); } } } /*指定配置信息:如果new ComboPooledDataSource()方法不傳參數,則默認使用 配置文件中的default-config 如果指定字符串,使用指定名稱的配置信息 */ @Test public void test3() throws SQLException { //1.創建數據庫連接池對象 DataSource dataSource = new ComboPooledDataSource("otherc3p0"); for (int i = 1; i <= 10; i++) { Connection connection = dataSource.getConnection(); System.out.println(i+" "+connection); } } } 7.2 Druid 連接池 - 目前公認最先進 的連接池技術 步驟: 1. 導包:druid-1.0.9.jar 2. 定義配置文件: 是properties形式的可以叫任意名稱,可以放在任意目錄下 3. 加載配置文件:Properties 4. 獲取數據庫連接池對象:通過工廠來來獲取 DruidDataSourceFactory 5. 獲取連接:getConnection 演示案例: 1. 將jar包拷入lib目錄,將配置 druid.properties 文 件拷貝到src下 2. 創建包,在包中創建演示案例類?
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. 提供靜態代碼塊,加載配置文件,初始化連接池對象 3. 提供方法 獲取連接的方法: 釋放資源: 獲取連接池的方法:因為有一些框架自己會通過連 接池獲取連接對象。所以也需要提供這樣一個方 法。 演示案例: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 執行sql的對象 * @param conn 連接數據庫的對象 */ public static void close(Statement stmt, Connection conn) { close(stmt,conn,null); } /** * 釋放資源 * @param stmt 執行sql的對象 * @param conn 連接數據庫的對象 * @param rs 查詢結果集對象 */ 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:使用工具類操作數據庫 /** * 使用JDBC工具類操作數據庫 */ public class DruidDemo2 { /* 向student表中添加一條數據 */ @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的開發。 步驟: //3. 獲取執行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.執行 int count = pst.executeUpdate(); System.out.println(count); } }1. 導包:Spring的5個jar包,mysql連接驅動包,Druid 連接池jar包 2. 創建JdbcTemplate對象。依賴于數據源DataSource 3. 調用JdbcTemplate的方法來完成CRUD操作 update() : 執行DML語句。增,刪,改語句。 queryForMap():查詢結果,將結果封裝為Map集 合 queryForList():查詢結果,將結果集封裝為List集 合 query():查詢結果,將結果封裝為JavaBean對象 queryForObject():查詢結果,將結果封裝為對象 練習中會對上述方法進行詳細說明 入門案例: /** * JDBCTemplate 入門 * 新項目中我們需要使用JDBCTemplate, 我們需要先 添加Druid連接池的jar包和配置文件,添加JDBCUtiles 工具類,才能使用JDBCTemplate。 */ public class JDBCTemplateDemo { public static void main(String[] args) { //1. 創建JDBCTemplate對象 JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); //2.調用方法使用JDBCTemplate操作數據庫只關心sql的編寫 和 執 行,其他的操作JDBCTemplate都會替我們完成。 演示案例:DML,DQL語句 需求:使用Student表,將Student實體類復制到當前工 程中 1. 修改id為3 的學生數據,將 age改為 30 2. 添加一條記錄 3. 刪除剛才添加的記錄 4. 查詢id為3的記錄,將其封裝為Map集合 5. 查詢所有記錄,將其封裝為List集合 6. 查詢所有記錄,將其封裝為Student對象的List 集合 7. 查詢name="埃隆馬斯克" 的學生信息,并封裝 成Student對象 String sql = "update student set sex=?,address=? where id=?"; // 有幾個?,就在update()方法中傳幾個參 數即可。 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 的學生數據,將 age改為 30 */ @Test public void test() { //1.獲取連接對象 // JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());//2.編寫sql String sql = "update student set age=? where id=?"; //3.執行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. 執行 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格式 : 字段名 = 字段值 注意: 結果集長度只能是1 超過則會報錯 */ @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);//報錯,因為記 錄超過兩條 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()}); 該方法需要自己實現一個接口,每查詢一條記錄 就會執行一次接口里面的mapRow()方法,將結果進行封裝 */ @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<實體類>(實體類.class)) 注意:如果用方式2,你的實體類中屬性的基本數 據類型一定要定義成包裝類型,否則如果你的查詢記錄中有 null的話 會報錯,因為 基本數據類型中不能存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="埃隆馬斯克" 的學生信息,并封裝成 Student對象queryForObject(sql,new BeanPropertyRowMapper<>(封裝的實體類.class), 參數) */ @Test public void test7() { String sql = "select * from student where name=?"; Student student = template.queryForObject(sql, new BeanPropertyRowMapper<>(Student.class),"埃隆 馬斯克"); System.out.println(student); } }總結
- 上一篇: Louvain算法实现
- 下一篇: Accusoft结构化工具包FormSu