时间:2021-07-01 10:21:17 帮助过:2人阅读
3) 创建使用JDBC获取数据库连接的类DBConn.java(用于和DBCP连接池对比)
1 package dbcp; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 6 public class DBConn { 7 private static Connection conn = null; 8 9 //获取一个数据库连接 10 public static Connection getConnection() { 11 try { 12 Class.forName("com.mysql.jdbc.Driver"); 13 DriverManager.registerDriver(new com.mysql.jdbc.Driver()); 14 String dbUrl = "jdbc:mysql://127.0.0.1:3306/mydb"; 15 conn = DriverManager.getConnection(dbUrl, "sa", "123456"); 16 // System.out.println("========数据库连接成功========"); 17 } catch (Exception e) { 18 e.printStackTrace(); 19 // System.out.println("========数据库连接失败========"); 20 return null; 21 } 22 return conn; 23 } 24 }
4) 创建测试类DBCPTest.java
测试类中采用3中方法将2000个数据插入数据库同一张表中,每次插入数据之前,先清空表,并对结果进行了对比。
3中插入数据方法如下:
(1) 每次插入一条数据前,就创建一个连接,该条数据插入完成后,关闭该连接;
(2) 使用DBCP连接池,每次插入一条数据前,从DBCP连接池中获取一条连接,该条数据插入完成后,该连接交由DBCP连接池管理;
(3) 在插入数据之前创建一条连接,2000个数据全部使用该连接,2000个数据插入完毕后,关闭该连接。
1 package dbcp; 2 3 import java.sql.Connection; 4 import java.sql.SQLException; 5 import java.sql.Statement; 6 7 import org.junit.Test; 8 9 public class DBCPTest { 10 11 //测试,每写一条数据前,就新建一个连接 12 @Test 13 public void testWriteDBByEveryConn() throws Exception{ 14 for(int i = 0; i < 2000; i++){ 15 writeDBByEveryConn(i); 16 } 17 System.out.println("DONE"); 18 19 } 20 21 //测试,使用连接池,每写一条数据前,从连接池中获取一个连接 22 @Test 23 public void testWriteDBByDBCP() throws Exception{ 24 for(int i = 0; i < 2000; i++){ 25 writeDBByDBCP(i); 26 } 27 System.out.println("DONE"); 28 } 29 30 //测试,只建一条连接,写入所有数据 31 @Test 32 public void testWriteDBByOneConn() throws Exception{ 33 Connection conn = DBConn.getConnection(); 34 Statement stat = conn.createStatement(); 35 for(int i = 0; i < 2000; i++){ 36 writeDBByOneConn(i, stat); 37 } 38 conn.close(); 39 System.out.println("DONE"); 40 } 41 42 //不使用连接池写数据库,每写一条数据创建一个连接 43 public void writeDBByEveryConn(int data){ 44 String sql = "insert into dbcp values (" + data + ")"; 45 Connection conn = DBConn.getConnection(); 46 try{ 47 Statement stat = conn.createStatement(); 48 stat.executeUpdate(sql); 49 }catch(Exception e){ 50 e.printStackTrace() ; 51 }finally{ 52 try { 53 conn.close(); 54 } catch (SQLException e) { 55 e.printStackTrace(); 56 } 57 58 } 59 } 60 61 //不使用连接池写数据库,只用一个连接,写所有数据 62 public void writeDBByOneConn(int data, Statement stat){ 63 String sql = "insert into dbcp values (" + data + ")"; 64 try{ 65 stat.executeUpdate(sql); 66 }catch(Exception e){ 67 e.printStackTrace() ; 68 } 69 } 70 71 //通过DBCP连接池写数据库 72 public void writeDBByDBCP(int data){ 73 String sql = "insert into dbcp values (" + data + ")"; 74 try { 75 Connection conn = KCYDBCPUtil.getConnection(); 76 Statement stat = conn.createStatement(); 77 stat.executeUpdate(sql); 78 conn.commit(); 79 conn.close(); 80 } catch (SQLException e) { 81 e.printStackTrace(); 82 } 83 } 84 85 }
测试结果如下:
(1) 每次插入一条数据前,就创建一个连接,该条数据插入完成后,关闭该连接。耗时158.318秒
(2) 使用DBCP连接池,每次插入一条数据前,从DBCP连接池中获取一条连接,该条数据插入完成后,该连接交由DBCP连接池管理。耗时122.404秒
(3) 在插入数据之前创建一条连接,2000个数据全部使用该连接,2000个数据插入完毕后,关闭该连接。耗时117.87秒
通过对比结果看出,向同一个表中插入2000条数据,每插入一条数据前创建一个新连接,会非常耗时,而使用DBCP连接池和使用同一个连接操作,耗时比较接近。
3、相关问题
1) 应用程序中,使用完一个数据库连接后,DBCP连接池如何管理该连接。
分两种情况:
(1) 应用程序中主动关闭该连接,即DBCPTest.java中第79行 conn.close();
这种情况并不是手动将该连接关闭,而是将该连接交回给DBCP连接池,由连接池管理该连接。即用完连接后显示的将数据库连接提交至DBCP连接池。
(2) 应用程序中不关闭该连接,即将DBCPTest.java中第79行 conn.close()注释掉
这种情况DBCP配置文件dbcp.properties中的配置项(注意jar包版本,低版本中使用removeAbandoned=true配置项)
removeAbandonedOnMaintenance=true
removeAbandonedOnBorrow=true
removeAbandonedTimeout=1
会起作用,removeAbandonedOnMaintenance=true和removeAbandonedOnBorrow=true表示DBCP连接池自动管理应程序中使用完毕的连接,removeAbandonedTimeout=1表示一个连接在程序中使用完毕后,若在1秒之内没有再次使用,则DBCP连接池回收该连接(通常removeAbandonedTimeout不会配置1,此处为了测试使用)。
(3) 验证removeAbandonedOnMaintenance=true、removeAbandonedOnBorrow=true和removeAbandonedTimeout=1配置项的作用
将测试类DBCPTest.java的writeDBByDBCP(int data)方法修改为如下:
1 //通过DBCP连接池写数据库 2 public void writeDBByDBCP(int data){ 3 String sql = "insert into dbcp values (" + data + ")"; 4 try { 5 Connection conn = KCYDBCPUtil.getConnection(); 6 Statement stat = conn.createStatement(); 7 stat.executeUpdate(sql); 8 conn.commit(); 9 // conn.close(); 10 } catch (SQLException e) { 11 e.printStackTrace(); 12 } 13 }
重新执行testWriteDBByDBCP()方法,结果如下:
可见writeDBByDBCP(int data)方法修改后和修改前作用相同,说明连接使用完后,由DBCP连接池管理。
而如果将修改配置项removeAbandonedTimeout=180,即一个连接用完后会等待180秒,超过180秒后才由DBCP连接池回收,重新执行testWriteDBByDBCP()方法,执行一段时间后报错,如下:
此时,查询数据表,发现正好插入了30条数据,如下:
这说明在插入第31条数据的时候报错,错误原因是连接池中没有可用的连接了。这是因为DBCP连接池初始化连接数为30,removeAbandonedTimeout设为180秒,所以30个连接用完后,程序运行还未 到180秒,程序中用完的连接都还没有被DBCP连接池回收,所以DBCP连接池中没有可用的连接了,才会在插入第31条数据时报错。
DBCP数据库连接池的简单使用
标签: