在项目中看到有用到数据库的连接池,心里就思考着为什么需要数据库连接池,只用一个连接会造成什么影响?(只用一个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)

数据库中的表数据:

787f78290665a6f94125a58567cf423a.png

id为1350的记录竟然成功的添加进数据库了,造成这一现象的原因显然是

在添加id为1350的记录的线程遇到异常还没有来得及数据回滚时,

别的线程先调用了 connection.commit()方法,以至于把不该提交的数据提交到数据库了。

6)  总结:在多线程的环境中,在不对connection做线程安全处理的情况下,使用单个connection会引起事务的混乱....影响jdbc事务的使用。。。

Logo

一站式 AI 云服务平台

更多推荐