PreparedStatement的使用
1.1 PreparedStatement介紹
-
可以通過調用 Connection 對象的 preparedStatement(String sql) 方法獲取 PreparedStatement 對象
-
PreparedStatement 接口是 Statement 的子接口,它表示一條預編譯過的 SQL 語句
-
PreparedStatement 對象所代表的 SQL 語句中的參數用問號(?)來表示,調用 PreparedStatement 對象的 setXxx() 方法來設置這些參數. setXxx() 方法有兩個參數,第一個參數是要設置的 SQL 語句中的參數的索引(從 1 開始),第二個是設置的 SQL 語句中的參數的值
1.2 PreparedStatement vs Statement
-
代碼的可讀性和可維護性。
-
PreparedStatement 能最大可能提高性能:
- DBServer會對預編譯語句提供性能優化。因為預編譯語句有可能被重復調用,所以語句在被DBServer的編譯器編譯后的執行代碼被緩存下來,那么下次調用時只要是相同的預編譯語句就不需要編譯,只要將參數直接傳入編譯過的語句執行代碼中就會得到執行。
- 在statement語句中,即使是相同操作但因為數據內容不一樣,所以整個語句本身不能匹配,沒有緩存語句的意義.事實是沒有數據庫會對普通語句編譯后的執行代碼緩存。這樣每執行一次都要對傳入的語句編譯一次。
- (語法檢查,語義檢查,翻譯成二進制命令,緩存)
-
PreparedStatement 可以防止 SQL 注入
1.3 ORM思想(object relational mapping)
- 一個數據表對應一個java類
- 表中的一條記錄對應java類的一個對象
- 表中的一個字段對應java類的一個屬性
sql是需要結合列名和表的屬性名來寫。注意起別名。
Java與SQL對應數據類型轉換表
Java類型 | SQL類型 |
---|---|
boolean | BIT |
byte | TINYINT |
short | SMALLINT |
int | INTEGER |
long | BIGINT |
String | CHAR,VARCHAR,LONGVARCHAR |
byte array | BINARY , VAR BINARY |
java.sql.Date | DATE |
java.sql.Time | TIME |
java.sql.Timestamp | TIMESTAMP |
1.4 使用PreparedStatement實現增、刪、改操作
//通用的增、刪、改操作(體現一:增、刪、改 ; 體現二:針對於不同的表)
public void update(String sql,Object ... args){
Connection conn = null;
PreparedStatement ps = null;
try {
//1.獲取數據庫的連接
conn = JDBCUtils.getConnection();
//2.獲取PreparedStatement的實例 (或:預編譯sql語句)
ps = conn.prepareStatement(sql);
//3.填充占位符
for(int i = 0;i < args.length;i++){
ps.setObject(i + 1, args[i]);
}
//4.執行sql語句
ps.execute();
} catch (Exception e) {
e.printStackTrace();
}finally{
//5.關閉資源
JDBCUtils.closeResource(conn, ps);
}
}
1.5 使用PreparedStatement實現查詢操作
// 通用的針對於不同表的查詢:返回一個對象
public <T> T getInstance(Class<T> clazz, String sql, Object... args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 1.獲取數據庫連接
conn = JDBCUtils.getConnection();
// 2.預編譯sql語句,得到PreparedStatement對象
ps = conn.prepareStatement(sql);
// 3.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
// 4.執行executeQuery(),得到結果集:ResultSet
rs = ps.executeQuery();
// 5.得到結果集的元數據:ResultSetMetaData
ResultSetMetaData rsmd = rs.getMetaData();
// 6.1通過ResultSetMetaData得到columnCount,columnLabel;通過ResultSet得到列值
int columnCount = rsmd.getColumnCount();
if (rs.next()) {
T t = clazz.newInstance();
for (int i = 0; i < columnCount; i++) {// 遍歷每一個列
// 獲取列值
Object columnVal = rs.getObject(i + 1);
// 獲取列的別名:列的別名,使用類的屬性名充當
String columnLabel = rsmd.getColumnLabel(i + 1);
// 6.2使用反射,給對象的相應屬性賦值
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t, columnVal);
}
return t;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 7.關閉資源
JDBCUtils.closeResource(conn, ps, rs);
}
return null;
}
說明:使用PreparedStatement實現的查詢操作可以替換Statement實現的查詢操作,解決Statement拼串和SQL注入問題。