爲何要使用JDBC?java
JDBC:Java DataBase Connectivity,是SUN公司提供的一套操做數據庫的標準規範(技術)。mysql
JDBC與數據庫驅動的關係:接口與實現的關係。sql
JDBC規範(掌握四個核心對象):數據庫
DriverManager類:用於註冊驅動(建立鏈接對象)。 java.sql.DriverManager;安全
Connection接口:表示與數據庫建立的鏈接 。java.sql.Connection;服務器
Statement接口:操做數據庫sql語句的對象,並返回相應結果的對象。 java.sql.Statement;oracle
preparedStatement接口:預編譯對象,是Statement對象的子類。用於解決sql的注入問題。實際用的是這個類。java.sql.PreparedStatement;ide
ResultSet接口:結果集或一張虛擬表(客戶端存表數據的對象)。 java.sql.ResultSet;性能
使用JDBC技術,經過java代碼實現查詢數據庫中的數據並顯示在java的控制檯中。測試
一、先建立數據庫表,並向表中添加測試數據。
create database stu; use stu; create table user ( id int primary key auto_increment, username varchar(40), password varchar(40), ) character set utf8 collate utf8_general_ci; insert into user(username, password) values('zs', '123456'); insert into user(username, password) values('lisi', '123456'); insert into user(username, password) values('wangwu', '123456');
二、建立Java Project項目,添加數據庫驅動(xxx.jar)。
三、實現JDBC操做。
4.源碼示例
package com.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class JDBCUtils { public static Connection connection; private static String url ="jdbc:mysql://localhost:3306/stu?serverTimezone=GMT%2B8"; private static String user ="root"; private static String pwd = "root"; static{ try { Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection(url,user,pwd); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } public static Connection getConnection(){ return connection; } }
package com.pojo; public class User { private int id; private String username; private String password; public User() { } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } public User(int id, String username, String password) { this.id = id; this.username = username; this.password = password; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
package com.dao; import com.jdbc.JDBCUtils; import com.pojo.User; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class UserDao { private Connection conn = JDBCUtils.getConnection(); private PreparedStatement ps; /** * 添加用戶 * @param user 要添加的用戶對象 * @throws SQLException */ public int add(User user) throws SQLException { String sql = "insert into user(username,password) values(?,?)"; ps = conn.prepareStatement(sql); ps.setObject(1,user.getUsername()); ps.setObject(2,user.getPassword()); return ps.executeUpdate(); } /** * 刪除 * @param id * @return * @throws SQLException */ public int delete(int id) throws SQLException { String sql = "delete from user where id=?"; ps = conn.prepareStatement(sql); ps.setObject(1,id); return ps.executeUpdate(); } /** * 修改 * @param user * @return * @throws SQLException */ public int update(User user) throws SQLException { String sql = "update user set username=? , password=? where id=?"; ps = conn.prepareStatement(sql); ps.setObject(1,user.getUsername()); ps.setObject(2,user.getPassword()); ps.setObject(3,user.getId()); return ps.executeUpdate(); } /** * 查詢全部 * @return * @throws SQLException */ public List<User> findAll() throws SQLException { String sql = "select * from user"; ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery(); List<User> list = new ArrayList<User>(); while(rs.next()){ int id = rs.getInt("id"); String username = rs.getString("username"); String password = rs.getString("password"); User u = new User(id,username,password); list.add(u); } return list; } /** * 根據ID查詢 * @param id * @return * @throws SQLException */ public User findByID(int id) throws SQLException { String sql = "select * from user where id=?"; ps = conn.prepareStatement(sql); ps.setInt(1,id); ResultSet rs = ps.executeQuery(); User u = null; while(rs.next()){ int uid = rs.getInt("id"); String username = rs.getString("username"); String password = rs.getString("password"); u = new User(uid,username,password); } return u; } /** * 登陸的方法 */ public User login(User user) throws SQLException { String sql = "select * from user where username=? and password=?"; ps = conn.prepareStatement(sql); ps.setObject(1,user.getUsername()); ps.setObject(2,user.getPassword()); ResultSet rs = ps.executeQuery(); User u = null; while(rs.next()){ int uid = rs.getInt("id"); String username = rs.getString("username"); String password = rs.getString("password"); u = new User(uid,username,password); } return u; } }
package com.service; import com.dao.UserDao; import com.pojo.User; import java.sql.SQLException; import java.util.List; public class UserService { private UserDao userDao = new UserDao(); /** * 添加用戶 * @param user 要添加的用戶對象 * @throws SQLException */ public int add(User user) throws SQLException { return userDao.add(user); } /** * 刪除 * @param id * @return * @throws SQLException */ public int delete(int id) throws SQLException { return userDao.delete(id); } /** * 修改 * @param user * @return * @throws SQLException */ public int update(User user) throws SQLException { return userDao.update(user); } /** * 查詢全部 * @return * @throws SQLException */ public List<User> findAll() throws SQLException { return userDao.findAll(); } /** * 根據ID查詢 * @param id * @return * @throws SQLException */ public User findByID(int id) throws SQLException { return userDao.findByID(id); } /** * 登陸 */ public User login(User user) throws SQLException { return userDao.login(user); } }
package com.jdbc; import com.pojo.User; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; public class Demo { public static void main(String[] args) throws Exception { //1.動態加載驅動 // Class.forName("com.mysql.cj.jdbc.Driver"); // // //2.獲取鏈接對象 // String url = "jdbc:mysql://localhost:3306/stu?serverTimezone=GMT%2B8"; // String user = "root"; // String pwd = "123456"; // Connection conn = DriverManager.getConnection(url, user, pwd); //3.使用jdbc規範實現CRUD //String sql = "insert into user(username,password) value(?,?)"; // String sql ="select * from user "; // // 建立一個 PreparedStatement 對象來將參數化的 SQL 語句發送到數據庫。 // PreparedStatement ps = conn.prepareStatement(sql); // //// ps.setString(1,"曉峯");//將指定參數設置爲給定 Java String 值 //// ps.setString(2,"xf"); // //// ps.setObject(1,"軍帥");//使用給定對象設置指定參數的值。 //// ps.setObject(2,"js"); // ////若是第一個結果是 ResultSet 對象,則返回 true;若是第一個結果是更新計數或者沒有結果,則返回 false //// boolean res = ps.execute(); //// System.out.println(res); // // //(1) SQL 數據操做語言 (DML) 語句的行數 (2) 對於無返回內容的 SQL 語句,返回 0 //// int rel = ps.executeUpdate(); //// System.out.println(rel);//1 // // //ResultSet 對象具備指向其當前數據行的光標。最初,光標被置於第一行以前。next 方法將光標移動到下一行; // //在此 PreparedStatement 對象中執行 SQL 查詢,並返回該查詢生成的 ResultSet 對象。 // ResultSet rs = ps.executeQuery(); //// rs.next(); //// rs.next(); //// rs.next(); //// rs.next(); //// boolean rel = rs.next(); //// System.out.println(rel); // // List<User> list = new ArrayList<User>(); // // while (rs.next()){ // // int id = rs.getInt(1); // String username = rs.getString(2); // String password = rs.getString(3); // //// User u = new User(id,username,password); //// list.add(u); // User u = (User) Class.forName("com.pojo.User").newInstance(); // list.add(u); // // } // // System.out.println(list); } }
DriverManager.deregisterDriver(new com.mysql.jdbc.Driver()); // 不建議使用
緣由有2個:
> 致使驅動被註冊2次。
> 強烈依賴數據庫的驅動jar包 (若把Build Path給Remove掉,代碼就會報錯,就能看到效果)
解決辦法:
Class.forName("com.mysql.jdbc.Driver"); // 把Build Path給Remove掉,代碼也不會報錯了
用到反射機制的知識:靠類的全路徑來加載,解耦合了,不依賴數據庫的驅動jar包了,之後會把上面的字符串放在配置文件裏,更靈活了,便於後期維護。
DriverManager類的靜態方法:
public static Connection getConnection(String url, String user, String password) 試圖創建到給定數據庫 URL 的鏈接
DriverManager.getConnection("jdbc:mysql://localhost:3306/stu?serverTimezone=GMT%2B8", "root", "root");
URL:是SUN公司與數據庫廠商之間的一種協議。
jdbc:mysql://localhost:3306/stu?serverTimezone=GMT%2B8
協議 子協議 IP 數據庫端口號 數據庫名稱
mysql:jdbc:mysql://localhost:3306/day14 或者
jdbc:mysql:///day14(默認鏈接本機的數據庫)
oracle:jdbc:oracle:thin:@localhost:1521:sid 瘦客戶端,好比:玩頁遊協議
子協議 子子協議 IP 數據庫端口號 數據庫名稱
oracle:jdbc:oracle:thick:@localhost:1521:sid 胖客戶端,好比:LOL、魔獸世界(須要下載軟件)
與數據庫創建鏈接的方式
第一種:
// public static Connection getConnection(String url, String user, String password)
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/stu?serverTimezone=GMT%2B8", "root", "root");
第二種:
// public static Connection getConnection(String url, Properties info)
Properties info = new Properties(); // 要參考數據庫文檔
info.setProperty("username", "root");
info.setProperty("password", "root");
Connection conn = DriverManager.getConnection("jjdbc:mysql://localhost:3306/stu?serverTimezone=GMT%2B8", info);
第三種:
// public static Connection getConnection(String url)
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/stu?serverTimezone=GMT%2B8?username=root&password=root");
// 模擬表單form提交的兩種方式:GET和POST
實際開發經常使用第一種。
}
-------------------------------------------
該接口的實如今數據庫驅動jar包中。全部與數據庫交互都是基於鏈接對象的。
該接口的實如今數據庫驅動jar包中。用於執行靜態 SQL 語句並返回它所生成結果的對象。
提供一個遊標,默認遊標指向結果集第一行以前(即表頭)。
調用一次boolean next(),遊標向下移動一行。
提供一些getXxx()方法。
-------------------------------------------
將結果集中的數據封裝到javaBean類中,javaBean就是一普通java類,該類中只有private類型的成員變量、無參構造方法和getter/setter方法。
java的數據類型與數據庫中的類型的關係:
JAVA DB
byte tityint 1字節
short smallint 2字節
int int 4字節
long bigint 8字節
float float
double double
String char 或者 varchar
Date date
-------------------------------------------
ResultSet結果集封裝數據的方法:
Object getObject(int columnIndex) 根據序號取值,索引從1開始
Object getObject(String ColomnName) 根據列名取值
boolean next() 將光標從當前位置向下移動一行
int getInt(int colIndex) 以int 形式獲取ResultSet結果集當前行指定列號值
int getInt(String colLabel) 以int 形式獲取ResultSet結果集當前行指定列名值
float getFloat(int colIndex) 以float 形式獲取ResultSet結果集當前行指定列號值
float getFloat(String colLabel) 以float形式獲取ResultSet結果集當前行指定列名值
String getString(int colIndex) 以String 形式獲取ResultSet結果集當前行指定列號值
String getString(String colLabel) 以String 形式獲取ResultSet結果集當前行指定列名值
Date getDate(int columnIndex) 以Date 形式獲取ResultSet結果集當前行指定列號值
Date getDate(String columnName) 以Date 形式獲取ResultSet結果集當前行指定列名
void close() 關閉ResultSet 對象
package com.itheima.entitydemo; 2 3 import java.util.Date; 4 5 /* 6 * 通常實體類的類名和數據庫的表名一致。(注意:若數據庫的表名單詞帶s的,則實體類名就去掉s) 7 * 實體類的成員變量名和數據庫表中的列名一致。(這是一個約定,網站開發的時候會提到) 8 */ 9 public class User { 10 private int id; 11 private String name; 12 private String password; 13 private String email; 14 private Date birthday; 15 16 public int getId() { 17 return id; 18 } 19 20 public void setId(int id) { 21 this.id = id; 22 } 23 24 public String getName() { 25 return name; 26 } 27 28 public void setName(String name) { 29 this.name = name; 30 } 31 32 public String getPassword() { 33 return password; 34 } 35 36 public void setPassword(String password) { 37 this.password = password; 38 } 39 40 public String getEmail() { 41 return email; 42 } 43 44 public void setEmail(String email) { 45 this.email = email; 46 } 47 48 public Date getBirthday() { 49 return birthday; 50 } 51 52 public void setBirthday(Date birthday) { 53 this.birthday = birthday; 54 } 55 56 @Override 57 public String toString() { 58 return "User [id=" + id + ", name=" + name + ", password=" + password + ", email=" + email + ", birthday=" 59 + birthday + "]"; 60 } 61 62 }
package com.itheima.entitydemo; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.ResultSet; 6 import java.sql.Statement; 7 import java.util.ArrayList; 8 import java.util.List; 9 10 import org.junit.Test; 11 12 /* 13 * 服務器端叫法:insert、delete、update、select (增刪改查) 14 * 客戶端的叫法:create、read、update、delete (CRUD)(增刪改查) 15 */ 16 public class TestCRUD { 17 18 @Test 19 public void testSelect() throws Exception { 20 // 加載驅動 21 Class.forName("com.mysql.jdbc.Driver"); 22 23 // 獲取鏈接對象Connection(注意:能用接口的就不用實現類,多態=>對象上傳=>向上轉型=>里氏替換,利於後期代碼擴展) 24 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day06", "root", "root"); 25 26 // 獲取執行sql語句的對象Statement 27 Statement stmt = conn.createStatement(); 28 29 // 執行sql的查詢語句,並返回結果 30 ResultSet rs = stmt.executeQuery("select * from users"); 31 32 // 把取到的數據裝到集合中 33 List<User> list = new ArrayList<User>(); 34 35 // 處理結果 36 User u = null; 37 while (rs.next()) { 38 u = new User(); 39 u.setId(rs.getInt("id")); 40 u.setName(rs.getString("name")); 41 u.setPassword(rs.getString("password")); 42 u.setEmail(rs.getString("email")); 43 u.setBirthday(rs.getDate("birthday")); 44 list.add(u); // 把對象添加到集合中去 45 } 46 47 // 遍歷集合(加強for) 48 for (User user : list) { 49 System.out.println(user); 50 } 51 52 // 關閉資源 53 rs.close(); 54 stmt.close(); 55 conn.close(); 56 } 57 58 @Test 59 public void testInsert() throws Exception { 60 // 加載驅動 61 Class.forName("com.mysql.jdbc.Driver"); 62 63 // 獲取鏈接對象Connection(注意;能用接口的就不用實現類,多態=>對象上傳=>向上轉型=>里氏替換,利於後期代碼擴展) 64 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day06", "root", "root"); 65 66 // 獲取執行sql語句的對象Statement 67 Statement stmt = conn.createStatement(); 68 69 // 執行sql的插入語句,並返回結果 70 int i = stmt.executeUpdate("INSERT INTO users VALUES (4, 'tom', '123','tom@163.com', '2015-09-28')"); 71 72 // 處理返回的結果 73 if (i > 0) { 74 System.out.println("success"); 75 } 76 77 // 關閉資源 78 stmt.close(); 79 conn.close(); 80 } 81 82 @Test 83 public void testUpdate() throws Exception { 84 // 加載驅動 85 Class.forName("com.mysql.jdbc.Driver"); 86 87 // 獲取鏈接對象Connection(注意;能用接口的就不用實現類,多態=>對象上傳=>向上轉型=>里氏替換,利於後期代碼擴展) 88 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day06", "root", "root"); 89 90 // 獲取執行sql語句的對象Statement 91 Statement stmt = conn.createStatement(); 92 93 // 執行sql的更新語句,並返回結果 94 int i = stmt.executeUpdate("UPDATE users SET NAME = 'jerry', PASSWORD = '333', email = 'jerry@163.com' WHERE id = 4"); 95 96 // 處理返回的結果 97 if (i > 0) { 98 System.out.println("success"); 99 } 100 101 // 關閉資源 102 stmt.close(); 103 conn.close(); 104 } 105 106 @Test 107 public void testDelete() throws Exception { 108 // 加載驅動 109 Class.forName("com.mysql.jdbc.Driver"); 110 111 // 獲取鏈接對象Connection(注意;能用接口的就不用實現類,多態=>對象上傳=>向上轉型=>里氏替換,利於後期代碼擴展) 112 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day06", "root", "root"); 113 114 // 獲取執行sql語句的對象Statement 115 Statement stmt = conn.createStatement(); 116 117 // 執行sql的刪除語句,並返回結果 118 int i = stmt.executeUpdate("DELETE FROM users WHERE id = 4"); 119 120 // 處理返回的結果 121 if (i > 0) { 122 System.out.println("success"); 123 } 124 125 // 關閉資源 126 stmt.close(); 127 conn.close(); 128 } 129 130 }
資源有限,要正確關閉。
原則:在使用對象以前,先判斷對象是否爲空。
package com.itheima.jdbcdemo; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import java.sql.Statement; 8 9 /* 10 * 使用JDBC技術,經過java代碼實現查詢數據庫中的數據並顯示在java的控制檯中。 11 * 12 * 演示正確釋放資源。 13 * 14 * 把某一部分代碼加上try...catch...的快捷鍵:Alt + Shift + Z 15 */ 16 public class Demo4 { 17 18 public static void main(String[] args) { 19 // 獲取鏈接對象Connection 20 Connection conn = null; 21 // 獲取執行sql語句的對象Statement 22 Statement stmt = null; 23 // 執行sql查詢語句,並返回結果 24 ResultSet rs = null; 25 try { 26 // 加載驅動 27 Class.forName("com.mysql.jdbc.Driver"); 28 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day06", "root", "root"); 29 stmt = conn.createStatement(); 30 rs = stmt.executeQuery("select * from users"); 31 // 處理返回的結果 32 while (rs.next()) { 33 // 根據列名取值,順序本身定,更靈活 34 System.out.println(rs.getObject("id")); 35 System.out.println(rs.getObject("name")); 36 System.out.println(rs.getObject("password")); 37 System.out.println(rs.getObject("email")); 38 System.out.println(rs.getObject("birthday")); 39 } 40 } catch (Exception e) { 41 e.printStackTrace(); 42 } finally { 43 // 關閉資源 44 if (rs != null) { 45 try { 46 rs.close(); 47 } catch (SQLException e) { 48 e.printStackTrace(); 49 } 50 } 51 if (stmt != null) { 52 try { 53 stmt.close(); 54 } catch (SQLException e) { 55 e.printStackTrace(); 56 } 57 } 58 if (conn != null) { 59 try { 60 conn.close(); 61 } catch (SQLException e) { 62 e.printStackTrace(); 63 } 64 } 65 } 66 } 67 }
preparedStatement(接口):預編譯對象,是Statement(接口)對象的子類。
特色:(安全高效,防止惡義SQL語法)
一、性能要高;PreparedStatement 實例包含已編譯的 SQL 語句,因此其執行速度要快於 Statement 對象。
二、會把sql語句先編譯。
三、sql語句中的參數會發生變化,過濾掉用戶輸入的關鍵字。
package com.itheima.service; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import com.itheima.entity.User; import com.itheima.util.DBUtils; public class DoLogin { /** * 根據姓名和密碼查詢用戶信息 * @param name * @param password * @return User */ public User findUser(String name, String password) { Connection conn = null; // Statement stmt = null; PreparedStatement stmt = null; ResultSet rs = null; User u = null; try { conn = DBUtils.getConnection(); // stmt = conn.createStatement(); // String sql = "select * from users where name = '" + name + "' and password = '" + password + "'"; // rs = stmt.executeQuery(sql); String sql = "select * from users where name = ? and password = ?"; stmt = conn.prepareStatement(sql); stmt.setString(1, name); // 給?賦值 stmt.setString(2, password); // 給?賦值 rs = stmt.executeQuery(); if (rs.next()) { u = new User(); u.setId(rs.getInt("id")); u.setName(rs.getString("name")); u.setPassword(rs.getString("password")); u.setEmail(rs.getString("email")); u.setBirthday(rs.getDate("birthday")); } } catch (Exception e) { e.printStackTrace(); } finally { DBUtils.closeAll(rs, stmt, conn); } return u; } }