在控制檯中輸入語句:start transaction;
即開始事務。java
在控制檯中輸入語句:commit transaction;
即提交事務。mysql
在控制檯中輸入語句:rollback;
回滾事務,即在此事務中執行的操做所有無效,數據庫回到start transaction;
以前(前提是使用該語法前沒有執行commit transaction;
操做)。sql
在Jdbc中處理事務都是經過Connection對象完成的,同一事務中的全部操做,都在使用同一個Connection對象。數據庫
setAutoCommit(boolean);
設置是否自動提交事務,若是爲true表示自動提交(默認值就是true),也就是每條執行的sql語句都是一個單獨的事務,若是設置false,那麼就至關於開啓了事務了。con.setAutoCommit(false);
語句表示開啓事務。服務器
con.commit();
提交併結束事務。多線程
con.rollback();
回滾事務。併發
在控制檯中輸入語句:select @@tx_isolation;
ide
也能夠經過下面命令來設置隔離級別:set transaction isolationlevel[4選1];
工具
con.setTransactionisolation[int lever];
性能
用戶每次請求都須要向數據庫得到連接,而數據庫建立鏈接一般須要消耗相對較大的資源,建立時間也較長。假設網站一天10萬訪問量,數據庫服務器就須要建立10萬次鏈接,極大的浪費數據庫的資源,而且極易形成數據庫服務器內存溢出、拓機。以下圖所示:
數據庫鏈接是一種關鍵的有限的昂貴的資源,這一點在多用戶的網頁應用程序中體現的尤其突出.。對數據庫鏈接的管理能顯著影響到整個應用程序的伸縮性和健壯性,影響到程序的性能指標。數據庫鏈接池正式針對這個問題提出來的。數據庫鏈接池負責分配,管理和釋放數據庫鏈接,它容許應用程序重複使用一個現有的數據庫鏈接,而不是從新創建一個。以下圖所示:
數據庫鏈接池在初始化時將建立必定數量的數據庫鏈接放到鏈接池中, 這些數據庫鏈接的數量是由最小數據庫鏈接數來設定的.不管這些數據庫鏈接是否被使用,鏈接池都將一直保證至少擁有這麼多的鏈接數量.鏈接池的最大數據庫鏈接數量限定了這個鏈接池能佔有的最大鏈接數,當應用程序向鏈接池請求的鏈接數超過最大鏈接數量時,這些請求將被加入到等待隊列中。
數據庫鏈接池的最小鏈接數和最大鏈接數的設置要考慮到如下幾個因素:
1.最小鏈接數(MinActive):是鏈接池一直保持的數據庫鏈接,因此若是應用程序對數據庫鏈接的使用量不大,將會有大量的數據庫鏈接資源被浪費。
2.最大鏈接數(MaxActive):是鏈接池能申請的最大鏈接數,若是數據庫鏈接請求超過次數,後面的數據庫鏈接請求將被加入到等待隊列中,這會影響之後的數據庫操做。
3.若是最小鏈接數與最大鏈接數相差很大:那麼最早鏈接請求將會獲利,以後超過最小鏈接數量的鏈接請求等價於創建一個新的數據庫鏈接.不過,這些大於最小鏈接數的數據庫鏈接在使用完不會立刻被釋放,他將被放到鏈接池中等待重複使用或是空間超時後被釋放。
設置初始化大小:connection.setInitialSize(); 設置最小空閒鏈接數:connection.setMinIdle(); 設置最大空閒鏈接數:connection.setMaxIdle(); 設置最小鏈接數:connection.setMinActive(); 設置最大鏈接數:connection.setMaxActive(); 設置增量:一次建立的最小單位。 設置最大的等待時間:connection.setMaxWait();
鏈接池也是使用Jdbc中的四大鏈接參數和驅動jar包來完成建立鏈接對象。
鏈接池必須實現javax.sql.DataSource接口。
從鏈接池返回的Connection對象,它的close()方法不同凡響。調用它的close()方法不是關閉,而是把鏈接歸還給池。
DBCP是Apache軟件基金組織下的開源鏈接池實現,要使用DBCP數據源,須要應用程序應在系統中增長以下兩個jar文件:
Demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public class Demo{ public static void main(String[] args) { /* *1.建立鏈接池對象 *2.配置四大參數 *3.配置池參數 *4.獲得鏈接對象 */ BasicDataSource dataSource=new BasicDataSource(); dataSource.setDriverClassName(「com.mysql.jdbc.Driver」); dataSource.setUrl(「jdbc:mysql://localhost:3306/mydb」); dataSource.setUsername(「root」); dataSource.setPassword(123); dataSource.setMaxActive(20); dataSource.setMinIdle(3); dataSource.setMaxWait(1000); Connection con=dataSource.getConnection(); System.out.println(con); /* *鏈接池內部使用四大參數建立了鏈接對象,即mysql驅動提供的Connection *鏈接池使用mysql的鏈接對象進行了裝飾,只對close()方法進行了加強! *裝飾以後的Connection的close()方法,用來把當前鏈接歸還給池 */ con.close();//把鏈接歸還給池。 } } |
既然談到裝飾,那下面咱們就在下文3.7中來談談裝飾者模式。
c3p0,全名叫ComboPooledDataSource;
須要導入的jar包:
Demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class Demo{ public static void main(String[] args) { //建立鏈接池對象 ComboPooledDataSource dataSource=new ComboPooledDataSource(); //進行四大參數的配置 dataSource.setDriverClass(「com.mysql.jdbc.Driver」); dataSource.setJdbcUrl(「jdbc:mysql://localhost:3306/mydb」); dataSource.setUser("root"); dataSource.setPassword("123"); //池配置 dataSource.setAcquireIncrement(5); dataSource.setInitialPoolSize(20); dataSource.setMinPoolSize(2); dataSource.setMaxPoolSize(50); Connection con=dataSource.getConnection(); System.out.println(con); con.close(); } } |
配置文件要求:
文件名稱:必須叫c3p0-config.xml。
文件的位置:必須在src下。
寫入配置文件後的Demo:
1 2 3 4 5 6 7 8 9 |
public class Demo{ public static void main(String[] args) { //在建立鏈接池對象時,這個對象就會自動加載配置文件,不用咱們來指定。 ComboPooledDataSource data=new comboPooledDataSource(); Connection con=data.getConnection(); System.out.println(con); } } |
JNDI:java命名和目錄接口。做用:在服務器上配置資源,而後經過統一的方式來獲取配置的資源。
首先須要在Tomcat/conf/Catelina/localhost目錄下新建文件名: 項目名.xml
1 2 3 4 5 |
Context initCtx=new InitialContext();//建立一個上下文。 Context envCtx=(Context) initCtx.lookup(「java:comp/env」);//這個路徑是固定的不能改。 MyBean bean=(MyBean)envCtx.lookup(「bean/MyBeanFactory」);//經過該上下文進行二次查找才能找到資源。 |
Demo:測試類
將對象加強的手段有:
缺點:1.加強的內容是死的,不能動。2.被加強的對象也是死的。
特色:1.加強的內容是不能修改的。2.被加強的對象能夠是任意的。
下面經過一個簡單的例子來對裝飾者模式進行講解
class 咖啡類 {}; class 加奶咖啡 extends 咖啡類 {}; class 加糖咖啡 extends 咖啡類 {}; class 加鹽咖啡 extends 咖啡類 {}; 咖啡 a=new 加糖咖啡(); 咖啡 b=new 加鹽咖啡(a);//對a進行裝飾,就是給a加鹽 咖啡 c=new 加奶咖啡(b);//對b進行裝飾,就是給b加奶
裝飾者模式在Java API中的IO流中用到的不少。如BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter、ObjectInputStream、ObjectOutputStream這幾個都是運用了裝飾模式的裝飾流。關於的IO流的詳情見下篇博客Java之IO流詳解。
早在JDK 1.2的版本中就提供Java.lang.ThreadLocal,ThreadLocal爲解決多線程程序的併發問題提供了一種新的思路。使用這個工具類能夠很簡潔地編寫出優美的多線程程序。
ThreadLocal內部用Map來保存數據。雖然在使用上述API時沒有給出鍵,但其實它內部使用了當前線程做爲鍵。內部結構見下面demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class ThreadLocal { private Map<Thread,T> map=new HashMap<Thread,T>(); public void set(T value){ map.put(Thread.currentThread(),value); } public void remove(){ map.remove(Thread.currentThread()); } public T get(){ return map.get(Thread.currentThread()); } } |
須要導入的jar包:
關鍵要獲得QueryRunner對象,而後調用其各類方法。
update()方法:
1.int update(String sql,Object… params) 可執行增刪改語句。
2.重載方法int update(Connection con,String sql, Object… params)須要調用者提供Connection,這說明本方法再也不管理Connection了。本重載方法支持事務。
query()方法:
1.T query (String sql,ResultSetHandler rsh,Object… params)可執行查詢操做。
2.重載方法:T query(Connection con,String sql,ResultSetHandler rsh,Object… params); 本重載方法支持事務。它會先獲得ResultSet,而後調用rsh的handle()把rs轉換成須要的類型。
ResultSetHandler接口
1.BeanHandler(單行)-->構造器須要一個class類型的參數,用來把一行結果轉換成指定類型的javaBean對象。
2.BeanListHandler(多行)—>構造器也是須要一個Class類型的參數,用來把一行結果集轉換成一個javabean,哪麼多行就是轉換成List對象,一堆javabean。
3.MapHandler(單行)—>把一行結果集轉換成Map對象。
4.MapListHandler(多行)—>把一行記錄轉換成一個Map,多行就是多個Map,即List。
5.ScalarHandler(單行單列)->同來用於select count(*)from t_stu語句,結果集是單行單列的,它返回一個Object,就是count(*)的值,爲long類型。
dbutil結果處理集原理代碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
package demo; import javax.sql.DataSource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** * Created by codingBoy on 16/10/19. */ public class QR<T> { private DataSource dataSource; public QR(DataSource dataSource) { this.dataSource=dataSource; } public QR(){ super(); } public int update(String sql,Object... params) { Connection con=null; PreparedStatement pstmt=null; try { con=dataSource.getConnection();//經過鏈接池獲得鏈接對象 pstmt=con.prepareStatement(sql); initParams(pstmt,params);//給出參數 return pstmt.executeUpdate();//調用update執行增、刪、該 }catch (Exception e) { throw new RuntimeException(e); }finally { try{ if (pstmt!=null) pstmt.close(); if (con!=null) con.close(); }catch (SQLException e){} } } //給參數賦值 public void initParams(PreparedStatement pstmt,Object... params) throws SQLException { for (int i = 0; i < params.length; i++) { pstmt.setObject(i+1,params[i]); } } public T query(String sql,RsHandler<T> rh,Object... params) throws SQLException { Connection con=null; PreparedStatement pstmt=null; ResultSet rs=null; try { con=dataSource.getConnection();//經過鏈接池獲得鏈接對象 pstmt=con.prepareStatement(sql); initParams(pstmt,params);//給出參數 rs=pstmt.executeQuery();//調用update執行增、刪、該 return rh.handle(rs); }catch (Exception e) { throw new RuntimeException(e); }finally { if (rs!=null) rs.close(); if (pstmt!=null) pstmt.close(); if (con!=null) con.close(); } } interface RsHandler<T> { public T handle(ResultSet rs); } } |
這樣咱們之後對數據庫進行增、刪、改操做時,只需寫如下代碼便可:
1 2 3 4 5 |
1.QueryRunner qr=new QueryRunner(JdbcUtils.getDataSource);//建立QueryRunner對象,並傳入鏈接池對象 2.String sql="insert into user values(?,?,?,?);//給出sql語句模板 3.Object[] params={參數1,參數2,參數3,參數4};//傳入參數 4.qr.update(sql,params);//調用qr方法。 |
經過這簡單的四步就能夠對數據庫進行增刪改了。
對數據庫進行查詢操做時,只需寫如下代碼:
1 2 3 4 5 6 7 8 9 10 |
1.QueryRunner qr=new QueryRunner(JdbcUtils.getDataSource);//建立QueryRunner對象,並傳入鏈接池對象 2.String sql="select * from user where id=?";//給出sql語句模板 3. Object[] params={參數};//傳入參數 //4. ResultSetHandler<Object> rsh=new ResultSetHandler(){ // @Override // public Object handle(Result rs) throws SQLException{ // return null; // } // }; 5.Object object=qr.query(sql,new BeanHandler<Object>(Object.class),params); |
經過這幾步便可實現對數據的查詢操做了。
下面的解釋寫給本身看的:關於connection是否關閉的問題
在jar包中,QueryRunner類的update(沒有connection參數的)方法,在finally中將connection進行了關閉;在update(有connection參數的)方法中,在finally中沒有對connection進行關閉(暫時這麼記吧,否則要是進行關閉了的話,在傳智播客寫的小工具封裝類TxQueryRunner中將connection傳入JdbcUtils的releaseConnecion()方法中對connection進行關閉時會出現報錯)。
在講到事務時,咱們會對QueryRunner進行再次封裝。上述寫出的QueryRunner的代碼只是包中的QueryRunner源碼方法的一部分(由於源碼中還有不少的重載方法),咱們會經過另外一個類TxQueryRunner(較QueryRunner多出的一個功能就是它支持事務)繼承該類,在TxQueryrunner類中,對connection進行了判斷:若connection爲事務中的connection則在TxqueryRunner的update()方法中不對connection進行關閉,而是在commitTransaction()即提交事務時進行關閉;若connection爲普通鏈接,則將connection進行關閉。那麼之後咱們在DAO中要獲取的就不是QueryRunner對象,而是經過QueryRunner qr=new TxQueryRunner();
獲取TxQueryRunner對象了。