一个基本成熟的数据库连接池
最近,本人着手开发要有一个有强大后台的网站,在使用连接池时,觉得使用服务器自带的连接池总有些受限制。同时,为了加深对Java的学习和研究。写下了下面的连接池类。
该连接池主要有一下功能;
1)初始化一次,到处使用。
2)强大的日志功能,记录每一个sql动作,包括Connection、ResultSet 和Statement
3)根据连接的数量,定时自动回收已经释放或超时的连接。
4)配置灵活,可以使用各种JDBC驱动程序,支持多驱动程序。
更新说明:
1)新增了字符集配置项。
2) 新增了调试开关,便于使用前调试。
3)更改了日志日期输出格式。
4)排除了createStatement l里的一个bug (感谢rouselion的使用反馈)
5)修正了被封装类的getXXX函数的潜在的问题。
源代码:
- //file : *****< ConnectionManager.java >****
- /*
- * @Title 连接池
- * @Author: zxg
- * @Version 2.5
- * @Memo:定义数据库连接及其数据库连接池等
- */
- package com.dbaccess.dbpool;
- import java.io.*;
- import java.sql.*;
- import java.util.*;
- import com.mysql.jdbc.Driver;
- public class ConnectionManager {
- static private ConnectionManager instance; // 唯一实例
- // static private int clients;
- static private long checkperiod=0;
- private Vector drivers = new Vector();
- private Hashtable pools = new Hashtable();
- private Timer checkConnTimer=new Timer();
- //调试模式开关
- private static boolean debug=false;
- //字符集哈西表
- static private Hashtable Characters= new Hashtable();
- static private PrintWriter log;
- /**
- * 返回唯一实例.如果是第一次调用此方法,则创建实例
- *
- * @return ConnectionManager 唯一实例
- */
- static synchronized public ConnectionManager getInstance() {
- if (instance == null) {
- instance = new ConnectionManager();
- }
- // clients++;
- return instance;
- }
- /**
- * 建构函数私有以防止其它对象创建本类实例
- */
- private ConnectionManager() {
- init();
- }
- /**
- * 读取属性完成初始化
- */
- private void init() {
- Properties dbProps=null;
- try {
- InputStream is = getClass().getResourceAsStream("db.properties");
- dbProps = new Properties();
- dbProps.load(is);
- }
- catch (Exception e) {
- e.printStackTrace();
- System.err.println("不能读取属性文件= " +
- "请确保db.properties在CLASSPATH指定的路径中");
- return;
- }
- String logFile = dbProps.getProperty("logfile", "log.txt");
- String logPath=System.getProperty("user.dir");
- if(!logPath.endsWith("/"))logPath=logPath+"/";
- logFile=logPath+logFile;
- if(debug){
- System.out.println(logFile);
- System.out.println("===============DEBUG====================");
- }
- try {
- log = new PrintWriter(new FileWriter(logFile, true), true);
- }
- catch (IOException e) {
- System.err.println("无法打开日志文件: " + logFile);
- log = new PrintWriter(System.err);
- }
- String ckPeriod=dbProps.getProperty("checkperiod","5");
- try {
- checkperiod= Long.valueOf(ckPeriod).longValue()*60*1000;
- }
- catch (NumberFormatException e) {
- log("错误的最大连接数限制: " + ckPeriod + " 连接池: ");
- log("使用默认值 5 分钟");
- checkperiod = 5*60*1000;
- }
- loadDrivers(dbProps);
- createPools(dbProps);
- }
- /**
- * 装载和注册所有JDBC驱动程序
- *
- * @param props 属性
- */
- private void loadDrivers(Properties props) {
- String driverClasses = props.getProperty("drivers");
- StringTokenizer st = new StringTokenizer(driverClasses);
- while (st.hasMoreElements()) {
- String driverClassName = st.nextToken().trim();
- try {
- Driver driver = (Driver)Class.forName(driverClassName).newInstance();
- if(driver!=null){
- DriverManager.registerDriver(driver);
- drivers.addElement(driver);
- log("Begin");
- log("成功注册JDBC驱动程序" + driverClassName);
- }
- else{
- log("Begin");
- log("注册JDBC驱动程序" + driverClassName+"失败");
- }
- }
- catch (Exception e) {
- log("Begin");
- log("无法注册JDBC驱动程序: " + driverClassName + ", 错误: " + e);
- }
- }
- }
- /**
- * 根据指定属性创建连接池实例.
- *
- * @param props 连接池属性
- */
- private void createPools(Properties props) {
- Enumeration propNames = props.propertyNames();
- while (propNames.hasMoreElements()) {
- String name = (String) propNames.nextElement();
- if (name.endsWith(".url")) {
- String poolName=name.substring(0,name.indexOf("."));
- //记录该连接池的字符集设置
- String character=props.getProperty(poolName+".character","gb2312");
- Characters.put(poolName,character);
- try{
- PoolInfoObject pio=new PoolInfoObject(poolName,props);
- ConnectionPool pool = new ConnectionPool(pio);
- pools.put(poolName, pool);
- //1分钟后开始每隔checkperiod分钟检查一次连接池情况
- checkConnTimer.schedule(pool,60*1000,checkperiod);
- log("成功创建连接池" + poolName);
- }catch(Exception e){
- log(e,"创建DBConnectionPool出错");
- }
- }
- }
- }
- /**
- * 将连接对象返回给由名字指定的连接池
- *
- * @param name 在属性文件中定义的连接池名字
- * @param con 连接对象
- */
- public void freeConnection(String name, Connection conn) {
- ConnectionPool pool = (ConnectionPool) pools.get(name);
- if (pool != null) {
- pool.freeConnection(conn);
- }
- }
- /**
- * 获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数
- * 限制,则创建并返回新连接
- *
- * @param name 在属性文件中定义的连接池名字
- * @return Connection 可用连接或null
- */
- public Connection getConnection(String name) {
- ConnectionPool pool = (ConnectionPool) pools.get(name);
- if (pool != null) {
- return pool.getConnection();
- }
- return null;
- }
- /**
- * 获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制,
- * 则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接.
- *
- * @param name 连接池名字
- * @param time 以毫秒计的等待时间
- * @return Connection 可用连接或null
- */
- public Connection getConnection(String name, long time) {
- ConnectionPool pool = (ConnectionPool) pools.get(name);
- if (pool != null) {
- return pool.getConnection(time);
- }
- return null;
- }
- /**
- * 关闭所有连接,撤销驱动程序的注册
- */
- public synchronized void release() {
- // 等待直到最后一个客户程序调用
- // if (--clients != 0) {
- // return;
- // }
- checkConnTimer.cancel();
- Enumeration allPools = pools.elements();
- while (allPools.hasMoreElements()) {
- ConnectionPool pool = (ConnectionPool) allPools.nextElement();
- pool.cancel();
- pool.release();
- }
- Enumeration allDrivers = drivers.elements();
- while (allDrivers.hasMoreElements()) {
- Driver driver = (Driver) allDrivers.nextElement();
- try {
- DriverManager.deregisterDriver(driver);
- log("撤销JDBC驱动程序 " + driver.getClass().getName()+"的注册");
- }
- catch (SQLException e) {
- log(e,"无法撤销下列JDBC驱动程序的注册: " + driver.getClass().getName());
- }
- }
- }
- /**
- * 取字符集设置参数。
- * @param poolName
- * @return String
- */
- static public String getCharacter(String poolName) {
- return (String)Characters.get(poolName);
- }
- /**
- * 将文本信息写入日志文件
- */
- static public void log(String msg) {
- if(debug==true) System.out.println( getLocalTime()+ " " + msg);
- else log.println( getLocalTime()+ " " + msg);
- }
- /**
- * 将文本信息与异常写入日志文件
- */
- static public void log(Throwable e, String msg) {
- if(debug==true){
- System.err.println( getLocalTime()+ " " + msg);
- e.printStackTrace(log);
- }else{
- log.println(getLocalTime() + " " + msg);
- e.printStackTrace(log);
- }
- }
- /**
- * 获取当前系统时间
- * @return String
- */
- private static String getLocalTime(){
- int tt[];
- String TT[];
- tt= new int[6];
- TT=new String[6];
- Calendar cl=Calendar.getInstance();
- tt[5]=cl.get(Calendar.SECOND);
- tt[4]=cl.get(Calendar.MINUTE);
- tt[3]=cl.get(Calendar.HOUR_OF_DAY);
- tt[2]=cl.get(Calendar.DAY_OF_MONTH);
- tt[1]=cl.get(Calendar.MONTH)+1;
- tt[0]=cl.get(Calendar.YEAR);
- for(int i=0;i<6 ;i++){
- if(tt[i]<10)
- TT[i]="0"+Integer.toString(tt[i]);
- else
- TT[i]=Integer.toString(tt[i]);
- }
- String t="";
- //连接日期 //连接时间
- t+=TT[0]+"-"+TT[1]+"-"+TT[2]+" "+TT[3]+":"+TT[4]+":"+TT[5];
- return t;
- }
- //test==========================================test
- /**
- * Method main
- *
- *
- * @param args
- *
- */
- public static void main(String[] args) {
- ConnectionManager dcm=null;
- try{
- dcm=ConnectionManager.getInstance();
- Connection conn=dcm.getConnection("mysql");
- Connection conn1=dcm.getConnection("mysql");
- Connection conn2=dcm.getConnection("mysql");
- ResultSet rs;
- System.out.println("start");
- String sql="select * from user ";
- System.out.println(":::::::::1");
- Statement st=conn.createStatement();
- if(st==null) {
- ConnectionManager.log("main--error while get \"Statement\"");
- return; }
- System.out.println("执行第"+1+"次检索");
- rs=st.executeQuery(sql);
- if(rs==null){
- ConnectionManager.log("main--error while get \"ResultSet\"");
- return;
- }
- System.out.println("\r\n");
- while(rs.next()){
- System.out.println(rs.getString(1));
- System.out.println(rs.getString(2));
- System.out.println(rs.getString(3));
- System.out.println();
- }
- rs.close();
- st.close();
- //rs=null;
- //st=null;
- System.out.println(":::::::::2");
- st = conn.createStatement();
- System.out.println("执行第"+2+"次检索");
- sql="select * from user";
- rs=st.executeQuery(sql);
- if(rs==null){
- ConnectionManager.log("main--error while get \"ResultSet\"");
- return;
- }
- while(rs.next()){
- System.out.println("TTT:::TTT");
- System.out.println(rs.getString(1));
- System.out.println(rs.getString(2));
- System.out.println(rs.getString(3));
- System.out.println();
- }
- rs.close();
- st.close();
- rs=null;
- st=null;
- dcm.freeConnection("mysql",conn);
- conn1.close();
- conn2.close();
- conn=null;
- conn1=null;
- conn2=null;
- dcm.release();
- }catch(SQLException e){
- ConnectionManager.log(e,"main--error");
- }
- }
- }
- //===========================================================================//
- //file : *****< ConnectionPool.java >****
- /***************连接池类***********/
- /**
- * 此类定义了一个连接池.它能够根据要求创建新连接,直到预定的最
- * 大连接数为止.在返回连接给客户程序之前,它能够验证连接的有效性.
- * 它继承自 TimerTask 被 ConnectionManager 类的timer成员调度
- */
- package com.dbaccess.dbpool;
- import java.sql.*;
- import java.util.*;
- import java.util.Date;
- public class ConnectionPool extends TimerTask{
- private int countConn;
- private Vector freeConns = new Vector();
- private Vector usingConns = new Vector();
- private long maxUseTime;//使用中的连接最大空闲时间
- private long maxFreeTime;//空闲的连接最大空闲时间(在连接数未小于最小连接数时,关闭此连接)
- private long maxConn;//最大连接数
- private long minConn;//最小连接数
- private long OnlineFreeTime ;//最大在线时间
- private long maxNoneOnlineTime;//无人在线最大保留时间
- private String name;//连接池名(name)
- private String url;
- private String user;
- private String password;
- private String option;
- /**
- * 创建新的连接池
- *
- * @param pio 连接池信息
- */
- public ConnectionPool(PoolInfoObject pio) {
- this.name = pio.poolName;
- this.url = pio.url;
- this.user = pio.user;
- this.password = pio.password;
- this.option=pio.optionConnection;
- this.maxConn = pio.maxConnection;
- this.minConn = pio.minConnection;
- this.OnlineFreeTime = pio.maxOnlineFreeTime;
- this.maxNoneOnlineTime = pio.maxNoneOnlineTime;
- if(this.minConn<=0) this.minConn=10;
- log("End One Part\r\n");
- for(int i=0; i newConnection();
- }
- }
- /**
- * 将新建的连接添加到连接池
- *
- * @param connobj 新建的连接
- */
- public synchronized void freeConnection(ConnectionObject connobj) {
- // 将指定连接加入到向量末尾
- try{
- connobj.setInUse(false);
- freeConns.addElement(connobj);
- usingConns.removeElement(connobj);
- log("成功记录一个新建连接或者回收一个已释放连接");
- notifyAll();
- }catch(ArrayIndexOutOfBoundsException e){
- log(e,"freeConnection(ConnectionObject connobj) --失败");
- }
- }
- /**
- * 将不再使用的连接返回给连接池
- *
- * @param conn 客户程序主动释放的连接
- */
- public synchronized void freeConnection(Connection conn) {
- // 将指定连接加入到向量末尾
- ConnectionObject connobj=null;
- int i;
- for(i=0;i {
- connobj=(ConnectionObject)usingConns.get(i);
- if(connobj.getConnection(false)==conn)
- break;
- }
- if(i try{
- connobj.setInUse(false);
- freeConns.addElement(connobj);
- usingConns.removeElement(connobj);
- log("客户程序主动释放连接--成功回收一个连接");
- notifyAll();
- }catch(Exception e){
- log(e,"客户程序主动释放连接--回收一个连接--失败");
- }
- }
- }
- /**
- * 从连接池获得一个可用连接.如没有空闲的连接且当前连接数小于最大连接
- * 数限制,则创建新连接.如原来登记为可用的连接不再有效,则从向量删除之,
- * 然后递归调用自己以尝试新的可用连接.
- * @return Connection
- */
- public synchronized Connection getConnection() {
- ConnectionObject connobj = null;
- Connection conn=null;
- // 获取向量中第一个可用连接
- try {
- connobj = (ConnectionObject) freeConns.get(0);
- }
- catch (Exception e) {
- log("End One Part\r\n");
- log("从连接池" + name+"获取一个连接失败");
- if( maxConn == 0 || countConn < maxConn) {
- connobj = newConnection();
- conn=connobj.getConnection(true);
- }
- }
- //如没有空闲的连接且当前连接数小于最大连接数限制,则创建新连接
- if(connobj==null && ( maxConn == 0 || countConn < maxConn)) {
- log("从连接池" + name+"获取一个连接失败");
- log("End One Part\r\n");
- connobj = newConnection();
- conn=connobj.getConnection(true);
- }else if(connobj!=null)
- {
- conn=connobj.getConnection(false);
- if (conn==null) conn=connobj.getConnection(true);
- }
- if (conn != null) {
- connobj.setLastAccessTime(new Date().getTime());
- connobj.setInUse(true);
- usingConns.addElement(connobj);
- freeConns.removeElementAt(0);
- return conn;
- }else{
- log("获取连接" + name+"失败--连接数量已达最大上限");
- return null;
- }
- }
- /**
- * 从连接池获取可用连接.可以指定客户程序能够等待的最长时间
- * 参见前一个getConnection()方法.
- *
- * @param timeout 以毫秒计的等待时间限制
- */
- public synchronized Connection getConnection(long timeout) {
- long startTime = new Date().getTime();
- Connection conn=null;
- while ((conn = getConnection()) == null) {
- try {
- wait(timeout);//??????????????
- }
- catch (InterruptedException e){
- }
- if ((new Date().getTime() - startTime) >= timeout) {
- // wait()返回的原因是超时?????????
- return null;
- }
- }
- return conn;
- }
- /**
- * 关闭所有连接
- */
- public synchronized void release() {
- // cancel();
- Enumeration allConnections = freeConns.elements();
- while (allConnections.hasMoreElements()) {
- ConnectionObject connobj = (ConnectionObject) allConnections.nextElement();
- try {
- connobj.close();
- connobj=null;
- log("关闭连接池" + name+"中的一个连接");
- }
- catch (SQLException e) {//SQLException
- log(e, "无法关闭连接池" + name+"中的连接");
- }
- }
- freeConns.removeAllElements();
- //
- allConnections = usingConns.elements();
- while (allConnections.hasMoreElements()) {
- ConnectionObject connobj = (ConnectionObject) allConnections.nextElement();
- try {
- connobj.close();
- connobj=null;
- log("关闭连接池" + name+"中的一个连接");
- }
- catch (SQLException e) {//SQLException
- log(e, "无法关闭连接池" + name+"中的连接");
- }
- }
- usingConns.removeAllElements();
- }
- /**
- * 创建新的连接
- */
- private ConnectionObject newConnection() {
- ConnectionObject connobj= null;
- try {
- log("连接池" + name+"创建一个新的连接对象");
- String URL=url+option;
- log("URL=" +URL );
- Connection conn = DriverManager.getConnection(URL,user,password);
- connobj=new ConnectionObject(conn,false);
- connobj.setPoolName(name);
- freeConnection(connobj);
- countConn++;
- }
- catch (SQLException e) {
- log(e, "无法创建下列URL的连接: " + url+" for User= " +user+" Password="+password);
- return null;
- }
- return connobj;
- }
- //检查各连接状态(每checkperiod分钟一次)
- public synchronized void run (){
- ConnectionObject connobj=null;
- //是否在maxNoneOnlineTime长时间内没有任何连接被使用。
- if(usingConns.size()==0 && (freeConns.size()==minConn || countConn==1)){
- boolean bCanFree=true;
- if(countConn==1)
- return;
- else{
- for(int j=0;j connobj=(ConnectionObject)freeConns.get(j);
- long lt=new Date().getTime()-connobj.getLastAccessTime();
- if(lt bCanFree=false;
- break;
- }
- }
- }
- if(bCanFree){
- log("run--连接池里的连接太闲--现在关闭部分连接,保持一个连接 ");
- while(freeConns.size()>1){
- try{
- connobj=(ConnectionObject)freeConns.get(0);
- connobj.close();
- connobj=null;
- freeConns.removeElementAt(0);
- countConn--;
- }catch(SQLException e){
- log(e,"run--连接池的连接太闲--关闭部分连接,保持一个连接--失败");
- }
- }
- log("关闭连接数量"+Long.toString(minConn-1));
- }
- return;
- }
- //回收 正在使用中的已经"关闭"(释放)的连接 和 使用时间已经超时的连接
- int i=0;
- while(i
- connobj=(ConnectionObject)usingConns.get(i);
- if(connobj.isInUse()==false){
- try{
- log("run--回收 正在使用中的已经\"关闭\"(释放)的连接");
- freeConnection(connobj);
- i--;
- }catch(ArrayIndexOutOfBoundsException e){
- log(e,"run--回收 正在使用中的已经\"关闭\"(释放)的连接--失败");
- }
- }else{
- long nowtime=new Date().getTime();
- long t=nowtime-connobj.getLastAccessTime();
- try{
- if(t>OnlineFreeTime){//超时时间为OnlineFreeTime分钟
- log("run--回收 使用时间已经超时的连接");
- freeConnection(connobj);
- i--;
- }
- }catch(ArrayIndexOutOfBoundsException e ){
- log(e,"run--回收 使用时间已经超时的连接--失败");
- }
- }
- i++;
- }
- //删除 空闲的已经被意外关闭的连接
- i=0;
- while(i
- connobj= (ConnectionObject)freeConns.get(i);
- try{
- if(connobj.isClosed()){
- connobj=null;
- freeConns.removeElementAt(i);
- countConn--;
- i--;
- log("run--删除 空闲的已经被意外关闭的连接");
- }
- }catch(Exception e){
- log(e,"run--删除 空闲的已经被意外关闭的连接-失败");
- }
- i++;
- }
- //删除 从空闲连接中多余的(大于最小连接数的)连接
- long cc=countConn-minConn;
- i=0;
- while(i1){
- try{
- connobj=(ConnectionObject)freeConns.get(0);
- connobj.close();
- connobj=null;
- freeConns.removeElementAt(0);
- countConn--;
- log("run--删除 从空闲连接中多余的(大于最小连接数的)连接 ");
- }catch(SQLException e){
- log(e,"run--从空闲连接中多余的(大于最小连接数的)连接--失败");
- }
- i++;
- }
- //增加连接 保持要求的最小连接数
- if(cc<0){
- cc=-cc;
- log("End One Part\r\n");
- log("run--增加连接 保持要求的最小连接数");
- for(i=0;i newConnection();
- }
- }
- //增加连接 保持至少有一个可用连接
- if(freeConns.size()<1){
- log("End One Part\r\n");
- log("run--增加连接 保持至少有一个可用连接");
- newConnection();
- }
- log("run--once");
- // notifyAll();
- }
- /**
- * 将文本信息写入日志文件
- */
- private void log(String msg) {
- msg="POOLMSG:Name:["+name+"];Msg:"+msg;
- ConnectionManager.log(msg);
- }
- /**
- * 将文本信息与异常写入日志文件
- */
- private void log(Throwable e, String msg) {
- msg="POOLERR:Name:["+name+"];Msg:"+msg;
- ConnectionManager.log(e,msg);
- }
- }
- //file : *****< PoolInfoObject .java >****
- /***************连接池信息类***********/
- package com.dbaccess.dbpool;
- import java.util.*;
- public class PoolInfoObject {
- public String poolName="";
- public String url="";
- public String user="";
- public String password="";
- public String optionConnection="";//连接选项
- public long maxConnection=0;//最大连接数
- public long minConnection=0;// 最小连接数
- public long maxOnlineFreeTime=0;//最大在线空闲时间
- public long maxNoneOnlineTime=0;//最大无人在线时间。超过此时间后仅保持一个连接
- public PoolInfoObject(String poolName,Properties props) throws Exception
- {
- this.poolName=poolName;
- url = props.getProperty(poolName + ".url");
- if (url == null) {
- log("没有为连接池" + poolName + "指定URL");
- throw new Exception("没有为连接池" + poolName + "指定URL");
- }
- this.user = props.getProperty(poolName + ".user");
- this.password = props.getProperty(poolName + ".password");
- this.optionConnection=props.getProperty(poolName+".option","");
- String maxconn = props.getProperty(poolName + ".maxconn", "0");
- String minconn = props.getProperty(poolName + ".minconn", "10");
- String maxoft=props.getProperty(poolName + ".maxonlinefreetime", "30");
- String maxnot=props.getProperty(poolName + ".maxnoneonlinetime", "180");
- try {
- maxConnection = Long.valueOf(maxconn).longValue();
- }
- catch (NumberFormatException e) {
- log("错误的最大连接数限制: " + maxconn + " 连接池: " + poolName);
- log("使用默认值 0(无限制)");
- maxConnection = 0;
- }
- try {
- minConnection = Long.valueOf(minconn).longValue();
- }
- catch (NumberFormatException e) {
- log("错误的最小连接数限制: " + minconn + " 连接池: " + poolName);
- log("使用默认值 10 个");
- minConnection = 10;
- }
- try {
- maxOnlineFreeTime =Long.valueOf(maxoft).longValue()*60*1000;
- }
- catch (NumberFormatException e) {
- log("错误的最大在线空闲时间: " + maxoft + " 连接池: " + poolName);
- log("使用默认值 30 分钟");
- maxOnlineFreeTime = 30*60*1000;
- }
- try {
- maxNoneOnlineTime = Long.valueOf(maxnot).longValue()*60*1000;
- }
- catch (NumberFormatException e) {
- log("错误的最大空闲时间: " + maxnot + " 连接池: " + poolName);
- log("使用默认值 1 小时");
- maxNoneOnlineTime = 60*60*1000;
- }
- }
- /**
- * 将文本信息写入日志文件
- */
- private void log(String msg) {
- msg="POOLMSG:Name:["+poolName+"];Msg:"+msg;
- ConnectionManager.log(msg);
- }
- /**
- * 将文本信息与异常写入日志文件
- */
- private void log(Throwable e, String msg) {
- msg="POOLERR:Name:["+poolName+"];Msg:"+msg;
- ConnectionManager.log(e,msg);
- }
- }
- //file : *****< db.properties >****#pool info
- //典型的连接池配置文件
- #日志文件
- logfile=log.txt
- #检测连接的频率 单位:分钟次
- checkperiod=5
- #如果有多个驱动可以以“:”分开如drivers=com.mysql.jdbc.Driver:com.oracle.jdbc.Driver
- drivers=com.mysql.jdbc.Driver
- #指明你的数据库所使用的字符集(新添项)
- mysql.character=gb2312
- mysql.url=jdbc:mysql://localhost:3306/test?
- mysql.option=useUnicode=true&&characterEncoding=GB2312&autoReconnect=true
- mysql.user=zxg
- mysql.password=333444
- #连接池数量限制
- mysql.maxconn=0
- mysql.minconn=10
- #超时参数 单位:分钟
- #最大在线空闲时间
- mysql.maxonlinefreetime=30
- #最大无人在线时间
- mysql.maxnoneonlinetime=60