首页 > 学院 > 开发设计 > 正文

探索多线程使用同一个数据库connection的后果

2019-11-14 23:26:39
字体:
来源:转载
供稿:网友
探索多线程使用同一个数据库connection的后果

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


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表