import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class DBConnection { private static final String DBDRIVER = "com.mysql.jdbc.Driver" ; //驅動類類名 private static final String DBURL = "jdbc:mysql://localhost:3306/db_affairmanage";//鏈接URL private static final String DBUSER = "root" ; //數據庫用戶名 private static final String DBPASSWORD = "XXXXXX"; //數據庫密碼 public static Connection getConnection(){ Connection conn = null; //聲明一個鏈接對象 try { Class.forName(DBDRIVER); //註冊驅動 conn = DriverManager.getConnection(DBURL,DBUSER,DBPASSWORD); //得到鏈接對象 } catch (ClassNotFoundException e) { //捕獲驅動類沒法找到異常 e.printStackTrace(); } catch (SQLException e) { //捕獲SQL異常 e.printStackTrace(); } return conn; } public static void close(Connection conn) {//關閉鏈接對象 if(conn != null) { //若是conn鏈接對象不爲空 try { conn.close(); //關閉conn鏈接對象對象 } catch (SQLException e) { e.printStackTrace(); } } } public static void close(PreparedStatement pstmt) {//關閉預處理對象 if(pstmt != null) { //若是pstmt預處理對象不爲空 try { pstmt.close(); //關閉pstmt預處理對象 } catch (SQLException e) { e.printStackTrace(); } } } public static void close(ResultSet rs) {//關閉結果集對象 if(rs != null) { //若是rs結果集對象不爲null try { rs.close(); //關閉rs結果集對象 } catch (SQLException e) { e.printStackTrace(); } } } }
public interface CriticismDAO { public void addCriticism(Criticism criticism); //添加回復 }
public class CriticismDAOImpl implements CriticismDAO{ public void addCriticism(Criticism criticism) { Connection conn = DBConnection.getConnection(); //得到鏈接對象 String addSQL = "insert into tb_criticism(criticismContent,criticismTime,messageID) values(?,?,?,?)"; PreparedStatement pstmt = null; //聲明預處理對象 try { pstmt = conn.prepareStatement(addSQL); //得到預處理對象並賦值 pstmt.setString(1, criticism.getCriticismContent()); //設置第一個參數 pstmt.setInt(2, criticism.getEmployeeID());//設置第二個參數 pstmt.setInt(3, criticism.getMessageID()); pstmt.executeUpdate(); //執行更新 } catch (SQLException e) { e.printStackTrace(); } finally{ DBConnection.close(pstmt); //關閉預處理對象 DBConnection.close(conn); //關閉鏈接對象 } }
(1)當Jdbc程序向數據庫得到一個Connection對象時,默認狀況下這個Connection對象會自動向數據庫提交在它上面發送的SQL語句。若想關閉這種默認提交方式,讓多條SQL在一個事務中執行,可以使用下列語句:java
(2)JDBC控制事務語句mysql
Connection.setAutoCommit(false); sql
Connection.rollback(); 數據庫
Connection.commit(); apache
(1)爲何使用鏈接池編程
鏈接,是咱們的編程語言與數據庫交互的一種方式。咱們常常會聽到這麼一句話「數據庫鏈接很昂貴「,簡單的獲取一個鏈接,系統卻要在背後作不少消耗資源的事情,大多時候,建立鏈接的時間比執行sql語句的時間還要長,用戶每次請求都須要向數據庫得到連接,而數據庫建立鏈接一般須要消耗相對較大的資源,建立時間也較長。假設網站一天10萬訪問量,數據庫服務器就須要建立10萬次鏈接,極大的浪費數據庫的資源,而且極易形成數據庫服務器內存溢出、拓機;數據庫鏈接是一種關鍵的有限的昂貴的資源,這一點在多用戶的網頁應用程序中體現的尤其突出。對數據庫鏈接的管理能顯著影響到整個應用程序的伸縮性和健壯性,影響到程序的性能指標。數據庫鏈接池負責分配,管理和釋放數據庫鏈接,它容許應用程序重複使用一個現有的數據庫鏈接,而不是從新創建一個設計模式
(2)鏈接池核心思想安全
鏈接池技術的核心思想是:鏈接複用,經過創建一個數據庫鏈接池以及一套鏈接使用、分配、管理策略,使得該鏈接池中的鏈接能夠獲得高效、安全的複用,避免了數據庫鏈接頻繁創建、關閉的開銷。另外,因爲對JDBC中的原始鏈接進行了封裝,從而方便了數據庫應用對於鏈接的使用(特別是對於事務處理),提升了獲取數據庫鏈接效率,也正是由於這個封裝層的存在,隔離了應用的自己的處理邏輯和具體數據庫訪問邏輯,使應用自己的複用成爲可能。鏈接池主要由三部分組成:鏈接池的創建、鏈接池中鏈接的使用管理、鏈接池的關閉服務器
(3)鏈接池的管理編程語言
鏈接池管理策略是鏈接池機制的核心。當鏈接池創建後,如何對鏈接池中的鏈接進行管理,解決好鏈接池內鏈接的分配和釋放,對系統的性能有很大的影響。鏈接的合理分配、釋放可提升鏈接的複用,下降了系統創建新鏈接的開銷,同時也加速了用戶的訪問速度。下面介紹鏈接池中鏈接的分配、釋放策略。
鏈接池的分配、釋放策略對於有效複用鏈接很是重要,咱們採用的方法是一個頗有名的設計模式:Reference Counting(引用記數)。該模式在複用資源方面應用的很是普遍,把該方法運用到對於鏈接的分配釋放上,爲每個數據庫鏈接,保留一個引用記數,用來記錄該鏈接的使用者的個數。具體的實現方法是:
當客戶請求數據庫鏈接時,首先查看鏈接池中是否有空閒鏈接(指當前沒有分配出去的鏈接)。若是存在空閒鏈接,則把鏈接分配給客戶並做相應處理(即標記該鏈接爲正在使用,引用計數加1)。若是沒有空閒鏈接,則查看當前所開的鏈接數是否是已經達到maxConn(最大鏈接數),若是沒達到就從新建立一個鏈接給請求的客戶;若是達到就按設定的maxWaitTime(最大等待時間)進行等待,若是等待maxWaitTime後仍沒有空閒鏈接,就拋出無空閒鏈接的異常給用戶。
當客戶釋放數據庫鏈接時,先判斷該鏈接的引用次數是否超過了規定值,若是超過就刪除該鏈接,並判斷當前鏈接池內總的鏈接數是否小於minConn(最小鏈接數),若小於就將鏈接池充滿;若是沒超過就將該鏈接標記爲開放狀態,可供再次複用。能夠看出正是這套策略保證了數據庫鏈接的有效複用,避免頻繁地創建、釋放鏈接所帶來的系統資源開銷。
(4)鏈接池的關閉
當應用程序退出時,應關閉鏈接池,此時應把在鏈接池創建時向數據庫申請的鏈接對象統一歸還給數據庫(即關閉全部數據庫鏈接),這與鏈接池的創建正好是一個相反過程
(5)鏈接池配置
鏈接池是建立和管理一個鏈接的緩衝池的技術,這些鏈接準備好被任何須要它們的線程使用,經常使用鏈接池有dbcp,c3p0,Proxool,這裏只介紹一下dbcp
DBCP鏈接池
DBCP 是 Apache 軟件基金組織下的開源鏈接池實現,要使用DBCP數據源,須要應用程序應在系統中增長以下兩個 jar 文件: Commons-dbcp.jar:鏈接池的實現 Commons-pool.jar:鏈接池實現的依賴庫 Tomcat 的鏈接池正是採用該鏈接池來實現的。該數據庫鏈接池既能夠與應用服務器整合使用,也可由應用程序獨立使用
步驟1: 在類目錄下加入dbcp的配置文件:dbcp.properties
#數據庫驅動 driverClassName=com.mysql.jdbc.Driver #數據庫鏈接地址 url=jdbc:mysql://localhost/test #用戶名 username=root #密碼 password=123456 #鏈接池的最大數據庫鏈接數。設爲0表示無限制 maxActive=30 #最大空閒數,數據庫鏈接的最大空閒時間。超過空閒時間,數據庫連 #接將被標記爲不可用,而後被釋放。設爲0表示無限制 maxIdle=10 #最大創建鏈接等待時間。若是超過此時間將接到異常。設爲-1表示無限制 maxWait=1000 #超過removeAbandonedTimeout時間後,是否進行沒用鏈接(廢棄)的回收(默認爲false,調整爲true) removeAbandoned=true #超過期間限制,回收沒有用(廢棄)的鏈接(默認爲 300秒) removeAbandonedTimeout=180
步驟2: 在獲取數據庫鏈接的工具類(如jdbcUtils)的靜態代碼塊中建立池:
import java.io.InputStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; /** * 在java中,編寫數據庫鏈接池需實現java.sql.DataSource接口,每一種數據庫鏈接池都是DataSource接口的實現 * DBCP鏈接池就是java.sql.DataSource接口的一個具體實現 */ public classJdbcUtils_DBCP { private static DataSource ds = null; //在靜態代碼塊中建立數據庫鏈接池 static{ try{ //加載dbcp.properties配置文件 InputStream in =JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcp.properties"); Properties prop = new Properties(); prop.load(in); //建立數據源 ds =BasicDataSourceFactory.createDataSource(prop); }catch (Exception e) { throw newExceptionInInitializerError(e); } } //從數據源中獲取數據庫鏈接 public static Connection getConnection()throws SQLException{ //從數據源中獲取數據庫鏈接 return ds.getConnection(); } //釋放鏈接 public static void release(Connection conn){ if(conn!=null){ try{ //將Connection鏈接對象還給數據庫鏈接池 conn.close(); }catch (Exception e) { e.printStackTrace(); } } } }
步驟3:在應用中獲取鏈接
Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try{ //獲取數據庫鏈接 conn =JdbcUtils_DBCP.getConnection(); …… }catch (Exception e) { e.printStackTrace(); }finally{ //釋放資源 JdbcUtils_DBCP.release(conn); }