一、傳統JDBC:
/**
* 釋放資源
*
* @param rs
* @param st
* @param conn
*/
public static void free(ResultSet rs, Statement st, Connection conn) {
try {
if (rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (st != null)
st.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (conn != null)
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
public static Connection getConn() {
String driver = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
String username = "scott";
String password = "tiger";
Connection conn = null;
try {
Class.forName(driver); // classLoader,加載對應驅動
conn = (Connection) DriverManager.getConnection(url, username,
password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static int insertAndDelete(String sql) {
Connection conn = getConn();
int i = 0;
PreparedStatement pstmt = null;
try {
pstmt = (PreparedStatement) conn.prepareStatement(sql);
i = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return i;
}
public static List queryForList(String sql) {
System.out.println("queryForList=======" + sql);
Connection conn = getConn();
PreparedStatement pstmt = null;
List<Map> list = new ArrayList();
try {
pstmt = (PreparedStatement) conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
int col = rs.getMetaData().getColumnCount();// 記錄數
while (rs.next()) {
Map<String, Object> map = new HashMap();
for (int i = 1; i <= col; i++) {
map.put(rs.getMetaData().getColumnName(i),
rs.getObject(i) == null ? "" : rs.getObject(i));
}
list.add(map);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return list;
}
/**
sql2 = "{call wzx_update_word()}";
**/
public static int doProcedure(String sql) {
Connection conn = getConn();
CallableStatement statement = null;
try {
statement = conn.prepareCall(sql);
statement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCTool.free(null, statement, conn);
}
return 0;
}
傳統JDBC優缺點:
優點:1.簡單,一個java類就可以開始操作數據庫。
2. sql靈活,sql隨便寫,需要傳值就填問號即可。
3.原始框架直接操作數據庫,效率高。
缺點: 1.安全性不高,SQL注入等。
2.查詢體驗差(很難獲得bean,或List<bean>)。
3.連接使用釋放難控制,萬一程序異常連接沒有釋放,造成數據庫內存泄漏,需要重啓數據庫。
4.不適用大型應用,成千上萬個人申請連接,再斷開,會佔用系統資源,嚴重的會造成服務器崩潰。
二、連接池
數據庫連接池負責分配、管理和釋放數據庫連接,它允許應用程序重複使用一個現有的數據庫連接,使用完再放回到連接池中,而不是重新建立一個。連接池在初始化時將創建一定數量的數據庫連接放到連接池中。
小提示:oracle數據庫最大連接數默認150,也就是最多創建150個connection。
知識擴展:connection實際上就是一個socket請求發送到數據庫進行通信。
爲什麼要使用連接池?
首先,沒有連接池的情況
1.如果程序出現異常,連接沒有釋放,造成數據庫內存泄漏,只能重啓數據庫。
2.幾百萬用戶請求,頻繁連接和釋放會消耗資源,導致服務器變慢。爲什麼會消耗資源?因爲創建連接時耗資源(比如進行分配內存的工作),大用戶數時就會影響網站響應速度。
3.和第1點類似,可以無限創建連接,導致數據庫內存泄漏。
使用連接池
連接池允許程序重複使用已有的connection,而不用重新創建。當有事務開始時,就從連接池中取一個可用的進行事務處理,沒有時則等待;事務處理完畢後再將連接放回連接池中
解決了什麼問題?
1.連接的釋放由連接池控制,不擔心內存泄漏。
2.connection重複利用,減少創建連接導致的資源消耗。
如果併發超過連接池連接數,則鏈接排隊等待,直到空出鏈接。
如果併發遠遠大於一個數據庫的承受能力,怎麼辦?
第一 , 可以 增加 緩存,減少查詢連接。
第二, 可以部署數據庫集羣,讀寫分離。
第三, 使用微服務,一個服務使用一個數據庫。
第四,如果插入太多,也可以使用消息隊列,先把要插入的數據保存到隊列中,然後定時插入到數據庫。