自定义一个简单的JDBC连接池实现方法
一、什么是jdbc连接池?
在传统的jdbc连接中,每次获得一个connection连接都需要加载通过一些繁杂的代码去获取,例如以下代码:
public static connection getconn(){ connection conn = null; string url = "jdbc:mysql://localhost:3306/test"; string user = "root"; string password = "root"; try { class.forname("com.mysql.jdbc.driver"); conn = drivermanager.getconnection(url, user, password); } catch (classnotfoundexception e) { e.printstacktrace(); } catch (sqlexception e) { e.printstacktrace(); } return conn; }
这样繁杂的操作只为了获取一次连接,当然,我们可以将其封装成一个工具类来访问(上图以封装好connection的连接),但是每一次连接都需要取加载一次是不是很浪费性能,为了优化性能,那么就出现了连接池。
连接池在初始化的时候就创建了几个连接供我们使用,当我们需要连接时只需要从连接池中获取已存在的连接,当初始化的几个连接都没有时,会重新创建一个连接,使用完连接后不会去销毁连接,而是归还给连接池供后面需要连接的使用。(当然,连接池不仅仅只是这么简单,这里就只做这些介绍)
常用的连接池有dbcp、c3p0,现在最主流是好像是阿里的druid连接池,还有tomcat的自带的jndi连接池
二、自定义一个简单的连接池
对自定义连接池的分析:
1.2.因为是连接池 ,我们需要实现datasource接口,并实现其中的方法,基于我们的情况,我们关于与getconnection()方法;
2.既然要存放几个连接对象,那么我们用一个集合来存放它,基于会经常操作增加和删除那么选用linkedlist;
3.连接的销毁并不是销毁连接,而是将连接归还给连接池
编码:
1.创建一个类mydatasource 并实现datasource接口
当此类加载时它就需要有一个容器来存放connection,所以定义一个静态的属性:
private static list<connection> connectionlist = new linkedlist<>();
2.因为需要取获得数据库连接,所以我们封装一个获取数据库连接的方法
public connection getoneconnection(){ connection conn = null; try{ //此处通过外部的properties文件来获取的数据,这样更加灵活。 inputstream in = mydatasource.class.getclassloader(). getresourceasstream("jdbc/jdbc.properties"); properties pro = new properties(); pro.load(in); driver = pro.getproperty("driver"); url = pro.getproperty("url"); username = pro.getproperty("user"); password = pro.getproperty("password"); class.forname(driver); conn = drivermanager.getconnection(url,username,password); }catch (exception e){ e.getstacktrace(); } return conn; }
注意的是我这里通过propertie文件的获取的数据,可根据实际情况来选择
3.初始化几个连接放入容器中。可以使用静态代码块来实现,但是如果没有使用此数据源那么就造成了资源的浪费,所以我考虑将初始化几个连接的实现放到他的构造方法中,即当需要此连接池的时候他才会随之创建几个连接。如下:
public mydatasource() { for (int i = 0; i < 5; i++) { connection conn = getoneconnection();//调用创建连接的方法 connectionlist.add(conn); } }
4.现在开始重写外部从此连接池中获取连接的方法getconnection()
@override public connection getconnection() throws sqlexception { connection conn = null; if(connectionlist == null || connectionlist.size() <= 0){ connection connection = getconnection(); connectionlist.add(connection); } conn = connectionlist.remove(0); return conn; }
5.创建一个对象返回的方法,即将用完的连接放入归还到连接池中
public void backconnection(connection conn){ connectionlist.add(conn); }
ok,这样就完成了一个简单的自定义连接池,测试代码如下:
public static void main( string[] args ) throws sqlexception { mydatasource datasource = new mydatasource(); connection conn = datasource.getconnection(); string sql = "select * from user where u_id = ?"; preparedstatement ps = null; resultset rs = null; try { ps = conn.preparestatement(sql); ps.setint(1, 1); rs = ps.executequery(); while (rs.next()) { system.out.println("id="+rs.getint(1)); system.out.println("username="+rs.getstring(2)); system.out.println("password="+rs.getstring(3)); } } catch (sqlexception e) { e.printstacktrace(); } finally { datasource.backconnection(conn); } }
因为忽略,我的代码中没有关闭其他两个对象。
现在有一个小问题就是,我们的关闭连接是通过连接池的方法来实现的,但是,如果用户调用connection对象的close方法,那么连接时被销毁了,并没有返回给连接池,那么我们来优化它,让用户使用close()方法不会去销毁连接,而是去归还连接。
方案有很多中,这里采用装饰着模式的一种。
优化:
1.新建一个类myconnection来实现connection接口,其中他有属性类型为connection conn和一个liis<connection>。
private connection conn; private list<connection> pool; public myconnection(connection conn, list<connection> pool) { this.conn = conn; this.pool = pool; }
2.然后实现接口的close方法
@override public void close() throws sqlexception { system.out.println("回收连接"); pool.add(conn); }
3.然后实现他获取statement的方法,如果不实现那么获取此statement会出现空指针错误,我这里就只实现了preparedstatement的获取方法
@override public preparedstatement preparestatement(string sql) throws sqlexception { system.out.println("获得statement"); return conn.preparestatement(sql); }
4.然后删除掉mydatasource类中归还连接的方法backconnection,并将构造方法和获取连接的方法做如下改造
public mydatasource2() { for (int i = 0; i < 5; i++) { connection conn = getoneconnection(); myconnection myconn = new myconnection(conn, connectionlist); connectionlist.add(myconn); } }
@override public connection getconnection() throws sqlexception { connection conn = null; if(connectionlist == null || connectionlist.size() <= 0){ connection connection = getconnection(); myconnection myconn = new myconnection(connection, connectionlist); connectionlist.add(myconn); } conn = connectionlist.remove(0); return conn; }
好了,这样用户直接调用我们的connection的close方法就不会去销毁连接了,会正确的归还给了连接池了,对测试代码稍做修改即可测试。
以上这篇自定义一个简单的jdbc连接池实现方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。