在項目中看到有用到數據庫的連接池,心里就思考著為什么需要數據庫連接池,只用一個連接會造成什么影響?(只用一個connection)?
1 猜想:jdbc的事務是基于connection的,如果多線程共用一個connection,會造成多線程之間的事務相互干擾。(connection.setAutoCommit(false);//connection.commit())
2 于是就模仿以下場景來做一個測試:
在多用戶請求的情況下,只用一個數據庫connection。
1)獲取connection工具類:
package jdbcPool.util;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;public class ConnectorUtil { public static final String user="root"; public static final String pwd="123456"; public static final String driver="com.MySQL.jdbc.Driver"; public static final String url ="jdbc:mysql://localhost:3306/test"; PRivate static Connection conn; private static int connectCount=0; static { try { Class.forName(driver); } catch (ClassNotFoundException e) { System.out.println("找不到數據庫驅動.."); e.printStackTrace(); } } /** * 獲取數據庫連接實例 * @return */ public synchronized static Connection getInstance(){ if(conn==null){ try { conn=DriverManager.getConnection(url,user, pwd); conn.setAutoCommit(false);//設置為不自動提交。。。 connectCount++; System.out.println("連接數據庫次數:"+connectCount); } catch (SQLException e) { System.out.println("連接數據庫失敗...."); e.printStackTrace(); } } return conn; }}
2) 業務接口實現類:
package jdbcPool.business;import java.sql.Connection;import java.sql.SQLException;import java.sql.Statement;import jdbcPool.util.ConnectorUtil;public class StudentService { private Connection conn; private static StudentService studentService; private StudentService(){ conn=ConnectorUtil.getInstance(); } public static synchronized StudentService getInstance(){ if(studentService==null){ studentService=new StudentService(); } return studentService; } public void insert(String id,String name,String no) throws Exception { String addStr ="insert into student(id,name,no) values('"+id+"','"+name+"','"+no+"')"; Statement statement=null; try { statement = conn.createStatement(); statement.execute(addStr); if("1350".equals(id)){//模仿某個線程執行service某個方法中某個步驟出現異常 Thread.sleep(3000);//模仿當前線程執行時間較長。。。。。 System.out.println("發生異常。。。。。"); System.out.println("記錄"+id+"插入失敗。。。。"); conn.rollback(); //出現異常事務回滾。。。 throw new Exception(); }else{ conn.commit(); System.out.println("記錄"+id+"插入成功。。。。"); } } catch (SQLException e) { System.out.println("創建statement失敗"); e.printStackTrace(); }finally{ if(statement!=null){ try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } } } }}
3)模擬用戶請求的線程類:
package jdbcPool.thread;import jdbcPool.business.StudentService;public class Request implements Runnable{ private String id; public Request(String id) { this.id=id; } @Override public void run() { //模仿service的單例模式 try { StudentService.getInstance().insert(this.id, "name"+id, "no"+id); } catch (Exception e) { e.printStackTrace(); } }}
4) 測試類:
package jdbcPool.test;import jdbcPool.thread.Request;
public class Main { //兩百個線程并發訪問同一個connection public static void main(String[] args){ for(int i=1300;i<1500;i++){ Thread th=new Thread(new Request(String.valueOf(i))); th.start(); } }}
5)結果分析:
打印臺出現的結果:
記錄1489插入成功。。。。記錄1490插入成功。。。。記錄1491插入成功。。。。記錄1495插入成功。。。。記錄1492插入成功。。。。記錄1493插入成功。。。。記錄1494插入成功。。。。記錄1496插入成功。。。。記錄1497插入成功。。。。記錄1498插入成功。。。。記錄1499插入成功。。。。記錄1300插入成功。。。。發生異常。。。。。記錄1350插入失敗。。。。java.lang.Exception at jdbcPool.business.StudentService.insert(StudentService.java:38) at jdbcPool.thread.Request.run(Request.java:18) at java.lang.Thread.run(Unknown Source)
數據庫中的表數據:

id為1350的記錄竟然成功的添加進數據庫了,造成這一現象的原因顯然是
在添加id為1350的記錄的線程遇到異常還沒有來得及數據回滾時,
別的線程先調用了 connection.commit()方法,以至于把不該提交的數據提交到數據庫了。
6) 總結:在多線程的環境中,在不對connection做線程安全處理的情況下,使用單個connection會引起事務的混亂....影響jdbc事務的使用。。。
新聞熱點
疑難解答