




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、从零开始实现Java多线程数据库连接池(附一个神秘的问题)本例采用mysql数据库,因此请先下载mysql-connectionjar在我们的实际开发中,离不开和数据库打交道。而和数据库的通信,离不开数据库连接。通常用JDBC连接数据库时,需要加载数据驱动,然后再通过接口返回数据库连接。一般分为两步:1、加载驱动至内存Class.forName(“com.mysql.jdbc.Driver”);2、创建并获取连接,返回的是JDBC中的ConnectionDriverManager.getConnection(url,user,password)示例:要连接的数据库URLStringurl=jd
2、bc:mysql:/localhost:3306/tangwmdb;连接的数据库时使用的用户名Stringusername=root;连接的数据库时使用的密码Stringpassword=root;/1加载驱动DriverManager.registerDriver(newcom.mysql.jdbc.Driver();不推荐使用这种方式来加载驱动Class.forName(com.mysql.jdbc.Driver);推荐使用这种方式来加载驱动/2获取与数据库的链接Connectionconn=DriverManager.getConnection(url,username,password
3、);/3.获取用于向数据库发送sql语句的statementStatementst=conn.createStatement();Stringsql=selectid,name,passwordfrommembers;/4.向数据库发sql,并获取代表结果集的resultsetResultSetrs=st.executeQuery(sql);/5.取出结果集的数据while(rs.next()System.out.println(id=+rs.getObject(id);System.out.println(name=+rs.getObject(name);System.out.println
4、(password=+rs.getObject(password);/6.关闭链接,释放资源rs.close();st.close();conn.close();众所周知,创建数据库连接需要消耗较多的资源,且创建时间也较长。如果网站一天100万PV(假设每个页面都有DB读取或修改操作),程序就需要创建100万次连接,极大的浪费资源。事实上,同一时间需要创建数据库连接的请求数量并不多,一般几百个足够了。那么我们可以根据需要创建一个连接池,它负责分配、管理和释放数据库连接,它允许应用程序重复使用同一个现有的数据库连接,而不是重新建立一个。这里用到了设计模式中的一个模式:享元模式(Flyweight
5、)。比如我们的连接池中有1000条连接,请求来时,连接池从池中分配一条给请求,用完后收回,而不是销毁,等到下次有请求来时,又可以重复分配使用。应用樹f1r应用歸+VnnectonnecLion.rnecLion;连接迪为谙求魅中玉际E勺讎圭分虱_鲁二于当前总用当使用了数据库连接池之后,在项目的实际开发中就不需要编写连接数据库的代码了;接从数据源获得数据库的连接。比如:/DBCP数据库连接池DataSourceds=BasicDataSourceFactory.createDataSource(prop);Connectionconn=ds.getConnection();可以看到创建连接的工作
6、很简单,因为复杂的分配、回收功能都交给了连接池去处理。当前有一些开源的数据连接池实现:DBCP数据库连接池C3P0数据库连接池另外阿里开源项目Druid(整个项目由数据库连接池、插件框架和SQL解析器组成)中的数据库连接池被很多互联网公司都采用在生产环境中。编写自己的数据库连接池编写的连接池需要做到以下几个基本点:1、可配置并管理多个连接节点的连接池nodenajne=defa口It;,testdb设罡数据库连妾节点default.driver=oom.mysqljdbcDrivrdefaultirl=jdbc:mysql:/lozalhost:3305/tangweniungdbdefaul
7、t.iser=iLOotdefault.psssword=rcatdefault.umjccomnectian.s=10defaultminccntiiecticns=2default,initcon.necticns=2default.default.imEOirt=50D0testdbdriver=co(n.ny=ql.jdbz.Driveetestdb:Z/7:3306/t=stestdbuser=r3OT;testdbpasssctr-d=ract2testdb.maxccnnecticn=LC1testdbmirtccnrieaticn=2testdb1mitcomnection.s
8、=22、始使化时根据配置中的初始连接数创建指定数量的连接3、在连接池没有达到最大连接数之前,如果有可用的空闲连接就直接使用空闲连接,如果没有,就创建新的连接。4、当连接池中的活动连接数达到最大连接数,新的请求进入等待状态,直到有连接被释放。5、由于数据库连接闲置久了会超时关闭,因此需要连接池采用机制保证每次请求的连接都是有效可用的。6、线程安全7、连接池内部要保证指定最小连接数量的空闲连接。对于最小连接数在实际应用中的效果以及与初始连接数的区别,其实理解的不是很透。在程序中我采用的方式是,如动连接数+空闲连接数最小连接数,就补齐对应数量最小连接数-活动连接数-空闲连接数)的空闲连接摘录一段:数
9、据库连接池的最小连接数和最大连接数的设置要考虑到以下几个因素:最小连接数:是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费。最大连接数:是连接池能申请的最大连接数,如果数据库连接请求超过次数,后面的数据库连接请求将被加入到等待队列中,这会影响以后的数据库操作。如果最小连接数与最大连接数相差很大,那么最先连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接。不过,这些大于最小连接数的数据库连接在使用完不会马上被释放,它将被放到连接池中等待重复使用或是超时后被释放。系统结构:1连接池接口IConnectionPool:
10、里面定义一些基本的获取连接的一些方法。2.连接池接口实现ConnectionPool3连接池管理DBConnectionManager:管理不同的连接池,所有的连接都是通过这里获得。4.其它工具类,诸如属性读取类PropertiesManager,属性保存类DBPropertyBean。连挂泄管理:nBctnPlMaaagerKDrrectcrpoQls4gEtInstanoeOHnitfl麼顶连多:gstCDTrecta-C荒讦连多:El空连多迪:+最门连騒:ntj+从豔址梦51生倍:getGcrnectionO+莪取耳前寥逹的淫援:圭+创崖新曲连毘:nsflCannednQ廨啟吕前连溟:抵
11、伽町请越蹇述需精睡看:destrjyO我戲接池靓:工应啊J:.4TDEConnBczionP&o鑑src止舟com.ttvm.TDB匚crinE&icmPchol丄EConnc-ctionMnager.jvaConnectionPdcl.js3-|T|DBPropeirtyBean.java!:工T匚cmnectionPoolja/a*曲cam.hvm.TDBCannGctionPaol.runI:-.fteEool.java-mcom.hMTn.TDBCannectionPaol.LftilI:-TPiropertiesManagjawa丿已ConfigsDB.prDp&rtiM国Ipert
12、ies虽JRJELibraryJa-jaSE-l.Tk.HIccNl;T17_n.klAfA01Ti工程代码:DBPropertyBean.javapackagecom.twm.TDBConnectionPool;publicclassDBPropertyBeanprivateStringnodeName;数据连接驱动privateStringdriverName;数据连接urlprivateStringurl;数据连接usernameprivateStringusername;数据连接密码privateStringpassword;连接池最大连接数privateintmaxConnectio
13、ns;连接池最小连接数privateintminConnections;连接池初始连接数privateintinitConnections;重连间隔时间,单位毫秒privateintconninterval;获取连接超时时间,单位毫秒,0永不超时privateinttimeout;构造方法publicDBPropertyBean()super();下面是getterandsetter/*获取数据库连接节点名称return*/publicStringgetNodeName()returnnodeName;/*设置数据库连接节点名称paramnodeName*/publicvoidsetNodeN
14、ame(StringnodeName)this.nodeName=nodeName;/*获取数据库驱动return*/publicStringgetDriverName()returndriverName;/*设置数据库驱动*paramdriverName*/publicvoidsetDriverName(StringdriverName)this.driverName=driverName;/*/*获取数据库urlreturn*/publicStringgetUrl()returnurl;/*设置数据库urlparamurl*/publicvoidsetUrl(Stringurl)this.
15、url=url;/*获取用户名return*/publicStringgetUsername()returnusername;/*设置用户名paramusername*/publicvoidsetUsername(Stringusername)this.username=username;/*获取数据库连接密码return*/publicStringgetPassword()returnpassword;/*设置数据库连接密码parampassword*/publicvoidsetPassword(Stringpassword)this.password=password;/*获取最大连接数r
16、eturn*/publicintgetMaxConnections()returnmaxConnections;/*设置最大连接数parammaxConnections*/publicvoidsetMaxConnections(intmaxConnections)this.maxConnections=maxConnections;/*获取最小连接数(也是数据池初始连接数)*获取最小连接数(也是数据池初始连接数)return*/publicintgetMinConnections()returnminConnections;/*设置最小连接数(也是数据池初始连接数)paramminConnec
17、tions*/publicvoidsetMinConnections(intminConnections)this.minConnections=minConnections;/*获取初始加接数return*/publicintgetInitConnections()returninitConnections;/*设置初始连接数paraminitConnections*/publicvoidsetInitConnections(intinitConnections)this.initConnections=initConnections;/*获取重连间隔时间,单位毫秒return*/publi
18、cintgetConninterval()returnconninterval;/*设置重连间隔时间,单位毫秒paramconninterval*/publicvoidsetConninterval(intconninterval)this.conninterval=conninterval;/*获取连接超时时间,单位毫秒return*/publicintgetTimeout()returntimeout;/*设置连接超时时间,单位毫秒,0-无限重连paramtimeout*/publicvoidsetTimeout(inttimeout)this.timeout=timeout;IConne
19、ctionPool.javapackagecom.twm.TDBConnectionPool;importjava.sql.Connection;importjava.sql.SQLException;publicinterfaceIConnectionPool/*获取一个数据库连接,如果等待超过超时时间,将返回nullreturn数据库连接对象*/publicConnectiongetConnection();/*获得当前线程的连接库连接return数据库连接对象*/publicConnectiongetCurrentConnecton();/*释放当前线程数据库连接paramconn数据库
20、连接对象throwsSQLException*/publicvoidreleaseConn(Connectionconn)throwsSQLException;/*销毁清空当前连接池*/publicvoiddestroy();/*连接池可用状态return连接池是否可用*/publicbooleanisActive();/*定时器,检查连接池*/publicvoidcheckPool();/*获取线程池活动连接数return线程池活动连接数*/publicintgetActiveNum();/*获取线程池空闲连接数return线程池空闲连接数*/publicintgetFreeNum();Co
21、nnectionPool.javapackagecom.twm.TDBConnectionPool;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;importjava.sql.Connection;importjava.sql.Driver;importjava.sql.Driver;importjava.sql.DriverManager;importjava.sql.SQLException;importjava.util.Link
22、edList;importjava.util.List;importjava.util.TimerTask;importjava.util.concurrent.Executors;importjava.util.concurrent.ScheduledExecutorService;importjava.util.concurrent.TimeUnit;importorg.apache.log4j.Logger;/*类说明:友元类,包内可见,不提供给客户程序直接访问。*/classConnectionPoolimplementsIConnectionPoolprivatestaticfina
23、lLoggerlog=Logger.getLogger(ConnectionPool.class);privateDBPropertyBeanpropertyBean=null;连接池可用状态privateBooleanisActive=true;/空闲连接池。由于List读写频繁,使用LinkedList存储比较合适privateLinkedListfreeConnections=newLinkedList();/活动连接池。活动连接数=允许最大连接数(maxConnections)privateLinkedListactiveConnections=newLinkedList();当前线程
24、获得的连接privateThreadLocalcurrentConnection=newThreadLocal();构造方法无法返回null,所以取消掉。在下面增加了CreateConnectionPoo静态方法。privateConnectionPool()super();publicstaticConnectionPoolCreateConnectionPool(DBPropertyBeanpropertyBean)ConnectionPoolconnpool=newConnectionPool();pertyBean=propertyBean;加载驱动在多节点环境配置下,因为在这里无法判
25、断驱动是否已经加载可能会造成多次重复加载相同驱动。因此加载驱动的动作,挪到connectionManager管理类中去实现了。/*tryClass.forName(pertyBean.getDriverName();(加载JDBC驱动+pertyBean.getDriverName()+成功”);catch(ClassNotFoundExceptione)(未找到JDBC驱动+pertyBean.getDriverName()+,请引入相关包);returnnull;*/基本点2、始使化时根据配置中的初始连接数创建指定数量的连接for(inti=0;ipertyBean.getInitConn
26、ections();i+)tryConnectionconn=connpool.NewConnection();connpool.freeConnections.add(conn);catch(SQLException|ClassNotFoundExceptione)log.error(pertyBean.getNodeName()+节点连接池初始化失败);returnnull;connpool.isActive=true;connpool.isActive=true;returnconnpool;/*检测连接是否有效param数据库连接对象returnBoolean*/privateBool
27、eanisValidConnection(Connectionconn)throwsSQLExceptiontryif(conn=null|conn.isClosed()returnfalse;catch(SQLExceptione)thrownewSQLException(e);returntrue;/*创建一个新的连接return数据库连接对象throwsClassNotFoundExceptionthrowsSQLException*/privateConnectionNewConnection()throwsClassNotFoundException,SQLExceptionConn
28、ectionconn=null;tryif(pertyBean!=null)Class.forName(pertyBean.getDriverName();conn=DriverManager.getConnection(pertyBean.getUrl(),pertyBean.getUsername(),pertyBean.getPassword();catch(SQLExceptione)thrownewSQLException(e);returnconn;OverridepublicsynchronizedConnectiongetConnection()Connectionconn=n
29、ull;if(this.getActiveNum()0)/分支1.1:如果空闲池中有连接,就从空闲池中直接获取(分支1.1:如果空闲池中有连接,就从空闲池中直接获取);conn=this.freeConnections.pollFirst();连接闲置久了也会超时,因此空闲池中的有效连接会越来越少,需要另一个进程进行扫描监测,不断保持一定数量的可用连接。在下面定义了checkFreepools的TimerTask类,在checkPool()方法中进行调用。基本点5、由于数据库连接闲置久了会超时关闭,因此需要连接池采用机制保证每次请求的连接都是有效可用的。tryif(this.isValidCo
30、nnection(conn)if(this.isValidConnection(conn)this.activeConnections.add(conn);currentConnection.set(conn);elseconn=getConnection();同步方法是可重入锁catch(SQLExceptione)e.printStackTrace();else/分支1.2:如果空闲池中无可用连接,就创建新的连接(分支1.2:如果空闲池中无可用连接,就创建新的连接,);tryconn=this.NewConnection();this.activeConnections.add(conn)
31、;catch(ClassNotFoundException|SQLExceptione)e.printStackTrace();else/分支2:当前已到达最大连接数/基本点4、当连接池中的活动连接数达到最大连接数,新的请求进入等待状态,直到有连接被释放。(分支2:当前已到达最大连接数);longstartTime=System.currentTimeMillis();进入等待状态。等待被notify(),notifyALL()唤醒或者超时自动苏醒trythis.wait(pertyBean.getConninterval();catch(InterruptedExceptione)log.e
32、rror(线程等待被打断);若线程超时前被唤醒并成功获取连接,就不会走到returnnull。若线程超时前没有获取连接,则返回null。如果timeout设置为0,就无限重连。if(pertyBean.getTimeout()!=0)if(System.currentTimeMillis()-startTimepertyBean.getTimeout()returnnull;conn=this.getConnection();returnconn;OverridepublicConnectiongetCurrentConnecton()Connectionconn=currentConnect
33、ion.get();tryif(!isValidConnection(conn)conn=this.getConnection();catch(SQLExceptione)e.printStackTrace();returnconn;OverridepublicsynchronizedvoidreleaseConn(Connectionconn)throwsSQLException(Thread.currentThread().getName()+关闭连接:activeConnections.remove:+conn);this.activeConnections.remove(conn);t
34、his.currentConnection.remove();this.currentConnection.remove();活动连接池删除的连接,相应的加到空闲连接池中tryif(isValidConnection(conn)freeConnections.add(conn);elsefreeConnections.add(this.NewConnection();catch(ClassNotFoundException|SQLExceptione)e.printStackTrace();唤醒getConnection()中等待的线程this.notifyAll();Overridepubl
35、icsynchronizedvoiddestroy()for(Connectionconn:this.freeConnections)tryif(this.isValidConnection(conn)conn.close();catch(SQLExceptione)e.printStackTrace();for(Connectionconn:this.activeConnections)tryif(this.isValidConnection(conn)conn.close();catch(SQLExceptione)e.printStackTrace();this.isActive=fal
36、se;this.freeConnections.clear();this.activeConnections.clear();OverridepublicbooleanisActive()returnthis.isActive;OverridepublicvoidcheckPool()finalStringnodename=pertyBean.getNodeName();ScheduledExecutorServiceses=Executors.newScheduledThreadPool(2);功能一:开启一个定时器线程输出状态ses.scheduleAtFixedRate(newTimerTask()Overridepub
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 【正版授权】 IEC 62074-1:2025 EN-FR Fibre optic interconnecting devices and passive components - Fibre optic WDM devices - Part 1: Generic specification
- 系统阐述经验管理思想
- 广东汕头澄海数学试卷
- 海宁南苑中学数学试卷
- 哈尔滨九年级下数学试卷
- 针刺板行业深度研究分析报告(2024-2030版)
- 志高空调检验报告
- 2025年中国钻孔攻牙机市场竞争策略及行业投资潜力预测报告
- 2025年中国存储部件行业发展前景预测及投资战略研究报告
- 中国ETC行业市场发展现状及投资方向研究报告
- 消毒供应室专科理论考试题库(单选、多选共500题)
- 城市道路无障碍设施课件
- 询价单(表格模板)
- 教师政审个人现实表现材料范文(通用5篇)
- QC降低矿山法围岩隧道爆破超挖量
- 2023年5月FDA口服速释制剂根据BCS分类系统的生物利用度与生物等效性研究及生物等效性豁免
- 校园文化建设方案(共60张PPT)
- 蓝色海洋经济海事航海渔业水产养殖港口码头海运PPT模板
- 不饱和聚酯树脂化学品安全技术说明书MSDS
- 机动车排放检验比对试验报告
- 一级二级三级医养结合机构服务质量评价标准(试行)
评论
0/150
提交评论