經過對前面代碼的分析,會發現如下幾個問題:java
Url、User、Password直接在代碼中定義,若是數據庫服務器稍做變更,怎麼辦?mysql
一個項目基本針對一個底層數據庫,難道每次操做數據庫,都要註冊一次驅動程序嘛?是否能夠只註冊一次?sql
獲取數據庫鏈接時,每次都須要Url、User、Password,一旦改動其中一個數據,意味着要修改全部此處的代碼。數據庫
釋放資源,每次數據庫操做後,都須要釋放資源,難道每次操做後都要寫三次try close catch代碼嘛?緩存
若是要解決上面的幾個問題,那麼就要對剛纔的代碼實現封裝,而且把數據庫的配置放到配置文件(Properties)中,具體作法以下:服務器
新建jdbc.properties,ide
內容以下:性能
[plain] view plain copyurl
#數據庫鏈接配置 spa
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/lcma?characterEncoding=utf-8
user=root
password=iflytek
新建一個JdbcUtil類,實現代碼以下:
[java] view plain copy
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JdbcUtil {
private static String url;
private static String user;
private static String password;
static{
//使用properties加載屬性文件
Properties prop = new Properties();
try {
InputStream is = JdbcUtil.class.getClassLoader().getResourceAsStream("com/iflytek/jdbc.properties");
prop.load(is);
//註冊驅動(獲取屬性文件中的數據)
String driverClassName = prop.getProperty("driverClassName");
Class.forName(driverClassName);
//獲取屬性文件中的url,username,password
url = prop.getProperty("url");
user = prop.getProperty("user");
password = prop.getProperty("password");
} catch (Exception e) {
e.printStackTrace();
}
}
//獲取數據庫鏈接
public static Connection getConnection(){
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
//釋放資源
public static void close(Connection conn, Statement stat, ResultSet rs){
if(conn != null){
try {conn.close();} catch (SQLException e) {e.printStackTrace();}
}
if(stat != null){
try {stat.close();} catch (SQLException e) {e.printStackTrace();}
}
if(rs != null){
try {rs.close();} catch (SQLException e) {e.printStackTrace();}
}
}
}
在加載配置文件的時候使用了靜態代碼塊,代表類一加載,配置文件就會立馬加載,屬性被保存在靜態變量中(url,user,password)。
獲取數據庫鏈接和釋放資源都採用了靜態方法,經過類直接調用改方法,實現了公用代碼的封裝,下降的代碼的耦合性。
這時候咱們再來看JDBC獲取數據庫數據代碼:
[java] view plain copy
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
try{
//經過JdbcUtil獲取數據庫連接
conn = JdbcUtil.getConnection();
stat = conn.createStatement();
rs = stat.executeQuery("select * from student");
while(rs.next()){
System.out.println(rs.getString("name"));
}
}catch(Exception e){
e.printStackTrace();
}finally {
//經過JdbcUtil關閉資源
JdbcUtil.close(conn, stat, rs);
}
經過如今的代碼能夠看出,代碼簡介了不少,沒有出現容易出錯的配置,獲取鏈接,加載配置文件,關閉資源咱們也不須要關心,大大下降了代碼的耦合性,提升了代碼重用性。
封裝事後的代碼仍是有些問題,就是採用了Statement對數據庫操做,若是如今SQL語句須要傳入變量,只有採用拼接的方式,這樣作有不少缺點,例如拼接容易出錯或容易產生SQL注入等。
經過PreparedStatement對數據庫操做能夠解決Statement帶來的缺點,PreparedStatement和Statement區別以下:
Statement的缺點:
一樣的SQL語句,每次都要發送,不能進行有效的緩存。
拼接SQL字符串很是容易出現錯誤。
不能防止惡意數據,易產生SQL注入。
升級後的新接口PreparedStatement(推薦):
預編譯SQL語句,並進行有效的緩存,性能更好。
容許使用問號佔位符參數,而且該參數必須得到值後才能夠執行。
無需拼接SQL語句。
問號佔位符參數:INSERTINTO User(id,name,age,birthday)VALUES(?,?,?,?);
來看一下經過PreparedStatement對數據庫操做的代碼:
[java] view plain copy
Connection conn = null;
PreparedStatement stat = null;
ResultSet rs = null;
try{
//經過JdbcUtil獲取數據庫連接
conn = JdbcUtil.getConnection();
stat = conn.prepareStatement("select * from student where name like ? and age = ? ");
stat.setString(1, "%小%");
stat.setInt(2, 22);
rs = stat.executeQuery();
while(rs.next()){
System.out.println(rs.getString("name"));
}
}catch(Exception e){
e.printStackTrace();
}finally {
//經過JdbcUtil關閉資源
JdbcUtil.close(conn, stat, rs);
}
}
注意如下兩點:
1.問號佔位符不能加引號。
2.佔位符參數設置值從下標從1開始。
轉載url:http://blog.csdn.net/mlc1218559742/article/details/52216895