JDBC和分包
JDBC(Java Data Base Connectivity,java資料庫連線)
JDBC是一種用於執行SQL語句的Java API,可以為多種關係資料庫提供統一訪問,它由一組用Java語言編寫的類和介面組成。是Java訪問資料庫的標準規範。
JDBC提供了一種基準,據此可以構建更高階的工具和介面,使資料庫開發人員能夠編寫資料庫應用程式。
JDBC需要連線驅動(就是實現類),由資料庫廠商提供。
1 JDBC原理
是面向介面程式設計
Java提供訪問資料庫規範稱為JDBC,而生產廠商提供規範的實現類稱為驅動。
JDBC是介面,驅動是介面的實現,沒有驅動將無法完成資料庫連線,從而不能操作資料庫。
2 JDBC開發步驟
1)導驅動包
專案上new一個資料夾lib(右鍵--new--Folder--輸入lib),把驅動包(下載下來的,如下圖)
把這個檔案複製進lib中,右鍵--build path--add to build path,可以看到專案多了一些檔案
每個專案這樣導一次就可以。
2)註冊驅動
程式碼為:Class.forName("com.mysql.jdbc.Driver");
意思是將Driver類載入到記憶體,讓其執行。
Driver類就在剛才匯入的驅動包中:
寫完後會有異常,因為傳引數是字串,出錯可能性大(一般按格式傳字串的,都會拋異常)。
這裡可以先throws,實際做專案時,再try/catch。
還有另一種註冊方法,但不推薦
3)獲取連線
程式碼:Connection con = DriverManager.getConnection(“jdbc:mysql://localhost:3306/mydb”,”root”,”root”);
三個引數分別表示:
url 需要連線資料庫的位置(網址)
user使用者名稱
password 密碼
JDBC規定url的格式由三部分組成,每個部分中間使用冒號分隔。
第一部分是jdbc,這是固定的;
第二部分是資料庫名稱,連線mysql資料庫,當然就寫mysql;
第三部分是由資料庫廠商規定的,我們需要了解每個資料庫廠商的要求。
mysql的第三部分分別由資料庫伺服器的IP地址(localhost)、埠號(3306),以及DATABASE資料庫名稱(mydb)組成。
這裡有可能連線不成功,所以還要thorws異常
4)獲得語句執行平臺
格式:
獲取Statement語句執行平臺:Statement sta = con.createStatement();
注意導包要導sql下的
String sql = "某SQL語句";
常用方法為:
int executeUpdate(String sql); --執行insert update delete語句,(增,刪,改都用這個)
ResultSet executeQuery(String sql); --執行select語句(查詢用這個)
5)處理結果集(只查詢時需要)
ResultSet實際上就是一張二維的表格,可以呼叫其boolean next()方法指向某行記錄,當第一次呼叫next()方法時,便指向第一行記錄的位置,這時就可以使用ResultSet提供的getXXX(int col)方法(與索引從0開始不同個,列從1開始)來獲取指定列的資料:
rs.next();//指向第一行
rs.getInt(1);//獲取第一行第一列的資料
常用方法:
Object getObject(int index) / Object getObject(String name) 獲得任意物件
String getString(int index) / Object getObject(String name) 獲得字串
int getInt(int index) / Object getObject(String name) 獲得整形
double getDouble(int index) / Object getObject(String name) 獲得雙精度浮點型
也就是資料庫中的欄位是什麼型別的,就用相應的型別的方法來獲取。
6)釋放資源
原則是先開後關。
rs.close();
stmt.close();
con.close();
例:
首先建一個數據庫market0929,再建一個user表
插入一條資料
import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Scanner; public class Test1 { public static void main(String[] args) throws ClassNotFoundException, SQLException { //註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //獲得連線物件 String url="jdbc:mysql://127.0.0.1:3306/market0929?useUnicode=true&characterEncoding=UTF-8"; String user="root"; String password="123456"; Connection conn=DriverManager.getConnection(url, user, password); //獲取語句執行平臺 Statement sta=conn.createStatement(); //讓使用者輸入使用者名稱和密碼 Scanner sc=new Scanner(System.in); System.out.println("請輸入使用者名稱:"); String uname=sc.next(); System.out.println("請輸入密碼:"); String pwd=sc.next(); //執行sql String sql="select count(*) from user where uname='"+uname+"' and password='"+pwd+"'"; //處理結果集 ResultSet rs=sta.executeQuery(sql); int count=0; while(rs.next()){ count=rs.getInt(1);//取第一列 } System.out.println(count); //釋放 先開後關 rs.close(); sta.close(); conn.close(); } }
Tips:
1)返回1,說明登入成功。
2)裡面?useUnicode=true&characterEncoding=UTF-8"; 這樣寫是為了和資料庫的字符集統一,避免新增資料時全是亂碼。
3)字串拼接技巧:先寫兩個雙引,在裡面寫兩個加號,再在加號裡面寫上變數
3 SQL注入問題
上面那個登入的例子,如果這樣輸入:
可以看到,返回了1,說明登入成功了。
因為這樣輸入時,實際的sql為:
SELECT COUNT(*) FROM USER WHERE uname='suiyishu' AND PASSWORD='1' OR '1=1';
這條查詢語句永遠可以查詢出結果,那麼使用者就直接登入成功了,這便是SQL注入問題。
4預處理物件
為了解決SQL注入問題,使用PreparedStatement預處理物件。
每條sql語句所有的實際引數都先用?佔位,引數使用逗號分隔,然後再給?賦值。這樣保證sql語句的結構不會再變了,不管使用者輸入什麼,都被認為是值。
4.1格式:
String sql = "insert into sort(sid,sname) values(?,?)";
PreparedStatement psmt = conn.prepareStatement(sql);
4.2設定實際引數
void setXxx(int index, Xxx xx) 將指定引數設定為給定Java的xx值。
4.3常用方法:
PreparedStatement是繼承Statement的,所以其方法都一樣:
增刪改用:int executeUpdate();
查詢用:ResultSet executeQuery();
查詢的還要處理結果集,都是一樣的。就只是執行sql時不同,以後都用PreparedStatement來寫。
5 JDBC工具類
“獲得資料庫連線”操作,將在以後的增刪改查所有功能中都存在,可以封裝工具類JDBCUtils。提供獲取連線物件的方法,從而達到程式碼的重複利用。
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class JDBCUtils { //工具類 public static Connection getConn(){ Connection conn=null; //定義成成員變數 try { //註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //獲得連線物件 String url="jdbc:mysql://127.0.0.1:3306/market0929?useUnicode=true&characterEncoding=UTF-8"; String user="root"; String password="123456"; conn=DriverManager.getConnection(url, user, password); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return conn; } //釋放增刪改資源 public static void close(Connection conn,PreparedStatement pst){ if(pst!=null){ try { pst.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } //釋放查詢資源 public static void close(Connection conn,PreparedStatement pst,ResultSet rs){ if(rs!=null){ try { rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(pst!=null){ try { pst.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
6上面登入的例子修改為:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Scanner; public class Test3 { public static void main(String[] args) throws ClassNotFoundException, SQLException { //讓使用者輸入使用者名稱和密碼 Scanner sc=new Scanner(System.in); System.out.println("請輸入使用者名稱:"); String uname=sc.next(); System.out.println("請輸入密碼:"); String pwd=sc.next(); //獲取連線物件 Connection conn=JDBCUtils.getConn(); //獲取語句執行平臺 String sql="select count(*) from user where uname=? and password=?"; PreparedStatement pst=conn.prepareStatement(sql); //注意導sql包 是Statement子類 //給問號賦值 pst.setString(1, uname); pst.setString(2, pwd); //執行sql ResultSet rs=pst.executeQuery(); //處理結果集 int count=0; while(rs.next()){ count=rs.getInt(1);//取第一列 } System.out.println(count); //釋放資源 JDBCUtils.close(conn,pst,rs); } }
再輸入一下:
7專案分層(分包)
- view層作用: 檢視層,即專案中的介面
- controller層作用: 控制層, 獲取介面上的資料,為介面設定資料; 將要實現的功能交給業務層處理。連線前後端的類,接收前臺封裝 和頁面
- service層作用: 業務層, 功能的實現, 與controller控制層和資料訪問層DAO互動, 將對資料庫的操作交給DAO資料訪問層來處理
- dao層(Data Access Object))作用: 資料訪問層, 用來操作資料庫表的資料
- db資料庫: 這裡指MySQL
- domain 實體包: 存放JavaBean
- tools工具包:存放專案中使用到的工具類
- test 測試包: 存放專案功能測試的程式碼
Tips:
1)用引數列表 和 返回值,一層調一層
2)View層:只有Scanner和System.out.println,(及一些簡單的處理, 正則表示式,驗證使用者輸入等,相當於js)
3)Controller層:用於封裝資料
4)Service層:處理業務邏輯
5)Dao:與資料庫有關的所有。一個類對應一個表
6)一般在dao層throws異常。在Service層try/catch
例:
建一個商品分類表:sort
專案結構為:
(方便複製
test
view
tools
domain
controller
service
dao
)
實現步驟:
1)寫view,建一個run方法建立Controller層物件,在該呼叫Controller層方法的地方先加好註釋
2)建實體類,成員變數就是資料庫中的欄位名,點出get,set方法和toString方法
3)tools中放工具類
4)寫dao層
5)寫Service層,建立dao層物件呼叫dao層方法
6)寫Controller層,建立Service層物件呼叫Service層方法,如果view層傳的引數過多,可以封裝成一個物件,再向後傳
7)回到view呼叫Controller層方法
8)test層中寫main方法,呼叫view層的run方法
例項程式碼下載: