在項目中看到有用到數據庫的連接池,心里就思考着為什么需要數據庫連接池,只用一個連接會造成什么影響?(只用一個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事務的使用。。。
