使用Apache commons-pool2实现高效的FTPClient连接池的方法
一. 连接池概述
       频繁的建立和关闭连接,会极大的降低系统的性能,而连接池会在初始化的时候会创建一定数量的连接,每次访问只需从连接池里获取连接,使用完毕后再放回连接池,并不是直接关闭连接,这样可以保证程序重复使用同一个连接而不需要每次访问都建立和关闭连接, 从而提高系统性能。有些对象的创建开销是比较大的,比如数据库连接等。为了减少频繁创建、销毁对象带来的性能消耗,我们可以利用对象池的技术来实现对象的复用。对象池提供了一种机制,它可以管理对象池中对象的生命周期,提供了获取和释放对象的方法,可以让客户端很方便的使用对象池中的对象。
二. commons-pool2介绍
2.1 pool2的引入
<dependency>
	<groupId>commons-lang</groupId>
	<artifactId>commons-lang</artifactId>
	<version>2.5</version>
</dependency>
	<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-pool2</artifactId>
	<version>2.8.0</version>
</dependency>
<dependency>
	<groupId>commons-net</groupId>
	<artifactId>commons-net</artifactId>
	<version>3.6</version>
</dependency>
<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.6</version>
</dependency>
2.2 pool2的组成
PooledObject(池化对象) PooledObjectFactory(对象工厂) ObjectPool (对象池)
对应为: FTPClient(池化对象) FTPClientFactory(对象工厂) FTPClientPool(对象池)
关系图:
关系图
三. 实现连接池
3.1 配置FtpClient
我们已经有现成的池化对象(FtpClient)了,只需要添加配置即可,FTPClientConfig【FTP连接配置类】
/** 
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.tompai.ftp.pool;
 
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
 
/**
 * @desc: demo
 * @name: FTPClientConfig.java
 * @author: tompai
 * @email:liinux@qq.com
 * @createTime: 2019年12月31日 下午12:53:48
 * @history:
 * @version: v1.0
 */
 
public class FTPClientConfig extends GenericObjectPoolConfig<FTPClient> {
 
	private String host;// 主机名
	private int port = 21;// 端口
	private String username;// 用户名
	private String password;// 密码
 
	private int connectTimeOut = 5000;// ftp 连接超时时间 毫秒
	private String controlEncoding = "utf-8";
	private int bufferSize = 1024;// 缓冲区大小
	private int fileType = 2;// 传输数据格式 2表binary二进制数据
	private int dataTimeout = 120 * 1000;
	private boolean useEPSVwithIPv4 = false;
	private boolean passiveMode = true;// 是否启用被动模式
	private int threadNum=1;//开启线程数
	private int transferFileType=FTPClient.BINARY_FILE_TYPE;//传输文件类型
	private boolean renameUploaded=false;//是否上传文件重命名;
	private int retryTimes=3;//重试次数
 
	public String getHost() {
 
		return host;
	}
 
	public void setHost(String host) {
 
		this.host = host;
	}
 
	public int getPort() {
 
		return port;
	}
 
	public void setPort(int port) {
 
		this.port = port;
	}
 
	public String getUsername() {
 
		return username;
	}
 
	public void setUsername(String username) {
 
		this.username = username;
	}
 
	public String getPassword() {
 
		return password;
	}
 
	public void setPassword(String password) {
 
		this.password = password;
	}
 
	public int getConnectTimeOut() {
 
		return connectTimeOut;
	}
 
	public void setConnectTimeOut(int connectTimeOut) {
 
		this.connectTimeOut = connectTimeOut;
	}
 
	public String getControlEncoding() {
 
		return controlEncoding;
	}
 
	public void setControlEncoding(String controlEncoding) {
 
		this.controlEncoding = controlEncoding;
	}
 
	public int getBufferSize() {
 
		return bufferSize;
	}
 
	public void setBufferSize(int bufferSize) {
 
		this.bufferSize = bufferSize;
	}
 
	public int getFileType() {
 
		return fileType;
	}
 
	public void setFileType(int fileType) {
 
		this.fileType = fileType;
	}
 
	public int getDataTimeout() {
 
		return dataTimeout;
	}
 
	public void setDataTimeout(int dataTimeout) {
 
		this.dataTimeout = dataTimeout;
	}
 
	public boolean isUseEPSVwithIPv4() {
 
		return useEPSVwithIPv4;
	}
 
	public void setUseEPSVwithIPv4(boolean useEPSVwithIPv4) {
 
		this.useEPSVwithIPv4 = useEPSVwithIPv4;
	}
 
	public boolean isPassiveMode() {
 
		return passiveMode;
	}
 
	public void setPassiveMode(boolean passiveMode) {
 
		this.passiveMode = passiveMode;
	}
 
	public int getThreadNum() {
	
		return threadNum;
	}
 
	public void setThreadNum(int threadNum) {
	
		this.threadNum = threadNum;
	}
 
	public int getTransferFileType() {
	
		return transferFileType;
	}
 
	public void setTransferFileType(int transferFileType) {
	
		this.transferFileType = transferFileType;
	}
 
	public boolean isRenameUploaded() {
	
		return renameUploaded;
	}
 
	public void setRenameUploaded(boolean renameUploaded) {
	
		this.renameUploaded = renameUploaded;
	}
 
	public int getRetryTimes() {
	
		return retryTimes;
	}
 
	public void setRetryTimes(int retryTimes) {
	
		this.retryTimes = retryTimes;
	}
 
	@Override
	public String toString() {
		return "{\"host\":\"" + host + "\", \"port\":\"" + port + "\", \"username\":\"" + username
				+ "\", \"password\":\"" + password + "\", \"connectTimeOut\":\"" + connectTimeOut
				+ "\", \"controlEncoding\":\"" + controlEncoding + "\", \"bufferSize\":\"" + bufferSize
				+ "\", \"fileType\":\"" + fileType + "\", \"dataTimeout\":\"" + dataTimeout
				+ "\", \"useEPSVwithIPv4\":\"" + useEPSVwithIPv4 + "\", \"passiveMode\":\"" + passiveMode
				+ "\", \"threadNum\":\"" + threadNum + "\", \"transferFileType\":\"" + transferFileType
				+ "\", \"renameUploaded\":\"" + renameUploaded + "\", \"retryTimes\":\"" + retryTimes + "\"}";
	}
 
}
3.2 创建FTPClientFactory
 在commons-pool2中有两种工厂:PooledObjectFactory 和KeyedPooledObjectFactory,在此使用PooledObjectFactory。
/** 
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.tompai.ftp.pool;
 
import java.io.IOException;
 
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
/**
 * @desc: demo
 * @name: FTPClientFactory.java
 * @author: tompai
 * @email:liinux@qq.com
 * @createTime: 2019年12月31日 下午12:52:02
 * @history:
 * @version: v1.0
 */
 
public class FTPClientFactory extends BasePooledObjectFactory<FTPClient> {
 
	private static Logger logger = LoggerFactory.getLogger(FTPClientFactory.class);
	private FTPClientConfig config;
 
	public FTPClientConfig getFtpPoolConfig() {
		return config;
	}
 
	public void setFtpPoolConfig(FTPClientConfig ftpPoolConfig) {
		this.config = ftpPoolConfig;
	}
 
	/**
	 * 新建对象
	 */
	@Override
	public FTPClient create() throws Exception {
		FTPClient ftpClient = new FTPClient();
		ftpClient.setConnectTimeout(config.getConnectTimeOut());
		try {
			logger.info("连接ftp服务器:" + config.getHost() + ":" + config.getPort());
			ftpClient.connect(config.getHost(), config.getPort());
			int reply = ftpClient.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftpClient.disconnect();
				logger.error("FTPServer 拒绝连接!");
				return null;
			}
			boolean result = ftpClient.login(config.getUsername(), config.getPassword());
			if (!result) {
				logger.error("ftpClient登录失败!");
				throw new Exception(
						"ftpClient登录失败! userName:" + config.getUsername() + ", password:" + config.getPassword());
			}
 
			ftpClient.setControlEncoding(config.getControlEncoding());
			ftpClient.setBufferSize(config.getBufferSize());
			ftpClient.setFileType(config.getFileType());
			ftpClient.setDataTimeout(config.getDataTimeout());
			ftpClient.setUseEPSVwithIPv4(config.isUseEPSVwithIPv4());
			if (config.isPassiveMode()) {
				logger.info("进入ftp被动模式");
				ftpClient.enterLocalPassiveMode();// 进入被动模式
			}
		} catch (IOException e) {
			logger.error("FTP连接失败:", e);
		}
		return ftpClient;
	}
 
	@Override
	public PooledObject<FTPClient> wrap(FTPClient ftpClient) {
		return new DefaultPooledObject<FTPClient>(ftpClient);
	}
 
	/**
	 * 销毁对象
	 */
	@Override
	public void destroyObject(PooledObject<FTPClient> p) throws Exception {
		FTPClient ftpClient = p.getObject();
		if (ftpClient != null && ftpClient.isConnected()) {
			ftpClient.logout();
			ftpClient.disconnect();
			super.destroyObject(p);
		}
	}
 
	/**
	 * 验证对象
	 */
	@Override
	public boolean validateObject(PooledObject<FTPClient> p) {
		FTPClient ftpClient = p.getObject();
		boolean connect = false;
		try {
			connect = ftpClient.sendNoOp();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return connect;
	}
 
	/**
	 * No-op.
	 *
	 * @param p ignored
	 */
	@Override
	public void activateObject(PooledObject<FTPClient> p) throws Exception {
		// The default implementation is a no-op.
	}
 
	/**
	 * No-op.
	 *
	 * @param p ignored
	 */
	@Override
	public void passivateObject(PooledObject<FTPClient> p) throws Exception {
		// The default implementation is a no-op.
	}
}
3.3 实现FTPClientPool
 在commons-pool2中预设了三个可以直接使用的对象池:GenericObjectPool、GenericKeyedObjectPool和SoftReferenceObjectPool,在此使用GenericObjectPool<FTPClient>
/** 
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.tompai.ftp.pool;
 
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
/**
 * @desc: demo
 * @name: FTPClientPool.java
 * @author: tompai
 * @email:liinux@qq.com
 * @createTime: 2019年12月31日 下午12:54:10
 * @history:
 * @version: v1.0
 */
 
public class FTPClientPool {
 
	private static Logger logger =LoggerFactory.getLogger(FTPClientPool.class);
	private GenericObjectPool<FTPClient> pool;
	private FTPClientFactory factory;
 
	public FTPClientPool(FTPClientFactory clientFactory) {
		this.factory = clientFactory;
		pool = new GenericObjectPool<FTPClient>(clientFactory, clientFactory.getFtpPoolConfig());
	}
 
	public FTPClientFactory getClientFactory() {
		return factory;
	}
 
	public GenericObjectPool<FTPClient> getPool() {
		return pool;
	}
 
	/**
	 * 借 获取一个连接对象
	 * 
	 * @return
	 * @throws Exception
	 */
	public FTPClient borrowObject() throws Exception {
		FTPClient client = pool.borrowObject();
		if (!client.sendNoOp()) {
			// 使池中的对象无效
			client.logout();
			client.disconnect();
			pool.invalidateObject(client);
			client = factory.create();
			pool.addObject();
		}
		return client;
 
	}
 
	/**
	 * 还 归还一个连接对象
	 * 
	 * @param ftpClient
	 */
	public void returnObject(FTPClient ftpClient) {
 
		if (ftpClient != null) {
			pool.returnObject(ftpClient);
		}
	}
}
3.4 连接池使用工具类FTPClientHelper
/** 
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.tompai.ftp.pool;
 
import java.io.IOException;
import java.io.InputStream;
 
import org.apache.commons.io.IOUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
/**
 * @desc: demo
 * @name: FTPClientHelper.java
 * @author: tompai
 * @email:liinux@qq.com
 * @createTime: 2019年12月31日 下午1:14:20
 * @history:
 * @version: v1.0
 */
 
public class FTPClientHelper implements AutoCloseable {
 
	private static Logger logger = LoggerFactory.getLogger(FTPClientHelper.class);
	private FTPClientPool pool;
 
	public void setFtpClientPool(FTPClientPool ftpClientPool) {
		this.pool = ftpClientPool;
	}
 
	/**
	 * 列出目录下的所有文件
	* @author: tompai
	* @createTime: 2019年12月31日 下午1:56:02
	* @history:
	* @param pathname
	* @return
	* @throws Exception FTPFile[]
	 */
	public FTPFile[] listFiles(String pathname) {
		FTPClient client = getClient();
		try {
			return client.listFiles(pathname);
		} catch (IOException e) {
			//TODO Auto-generated catch block
			logger.error(e.getMessage());
			e.printStackTrace();
		}finally {
			pool.returnObject(client);
		}
		return null;
	}
	
	/**
	 * 下载 remote文件流
	* @author: tompai
	* @createTime: 2019年12月31日 下午1:52:07
	* @history:
	* @param remote
	* @return byte[]
	 */
	public byte[] retrieveFileStream(String remote) {
		FTPClient client = getClient();
		InputStream in = null;
		//byte[] result=new Byte[]
		try {
			in = client.retrieveFileStream(remote);
			return IOUtils.toByteArray(in);
		} catch (IOException e) {
			logger.error(e.getMessage());
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			pool.returnObject(client);
		}
		return null;
	}
 
	/**
	 * 上传文件
	* @author: tompai
	* @createTime: 2019年12月31日 下午1:53:07
	* @history:
	* @param remote
	* @param local
	* @return
	* @throws Exception boolean
	 */
	public boolean storeFile(String remote, InputStream local) throws Exception {
		FTPClient client = getClient();
		try {
			return client.storeFile(remote, local);
		} finally {
			pool.returnObject(client);
		}
	}
 
	/**
	 * 创建目录 单个不可递归
	* @author: tompai
	* @createTime: 2019年12月31日 下午1:52:24
	* @history:
	* @param pathname
	* @return
	* @throws Exception boolean
	 */
	public boolean makeDirectory(String pathname) throws Exception {
		FTPClient client = getClient();
		try {
			return client.makeDirectory(pathname);
		} finally {
			pool.returnObject(client);
		}
	}
 
	/**
	 * 删除目录,单个不可递归
	* @author: tompai
	* @createTime: 2019年12月31日 下午1:52:42
	* @history:
	* @param pathname
	* @return
	* @throws Exception boolean
	 */
	public boolean removeDirectory(String pathname) throws Exception {
		FTPClient client = getClient();
		try {
			return client.removeDirectory(pathname);
		} finally {
			pool.returnObject(client);
		}
	}
 
	/**
	 * 删除文件 单个 ,不可递归
	* @author: tompai
	* @createTime: 2019年12月31日 下午1:52:54
	* @history:
	* @param pathname
	* @return
	* @throws Exception boolean
	 */
	public boolean deleteFile(String pathname) throws Exception {
 
		FTPClient client = getClient();
		try {
			return client.deleteFile(pathname);
		} finally {
			pool.returnObject(client);
		}
	}
	
	/**
	 * 获取一个连接对象
	 * 
	 * @author: tompai
	 * @createTime: 2019年12月31日 下午1:45:46
	 * @history:
	 * @return FTPClient
	 */
	private FTPClient getClient() {
		FTPClient client = null;
		try {
			client = pool.borrowObject();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return client;
	}
 
	/**
	 * 释放连接
	 * 
	 * @author: tompai
	 * @createTime: 2019年12月31日 下午1:45:03
	 * @history:
	 * @param client void
	 */
	private void releaseClient(FTPClient client) {
		if (client == null) {
			return;
		}
		try {
			pool.returnObject(client);
		} catch (Exception e) {
			logger.error("Could not return the ftpClient to the pool", e);
			// destoryFtpClient
			if (client.isAvailable()) {
				try {
					client.logout();
					client.disconnect();
					pool.getPool().invalidateObject(client);
				} catch (Exception io) {
					logger.error(io.getMessage());
				}
			}
		}
	}
 
	@Override
	public void close() throws Exception {
		// TODO Auto-generated method stub
		logger.info("---Resources Closed---.");
	}
}
3.5 连接池测试类FTPLinkPoolTest
在此可以自己使用FileZilla Server for Windows搭建一个简单的FTP服务器;
/** 
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.tompai.ftp.pool;
 
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
/**
* @desc: demo
* @name: FTPLinkPoolTest.java
* @author: tompai
* @email:liinux@qq.com
* @createTime: 2019年12月31日 下午1:13:51
* @history:
* @version: v1.0
*/
 
public class FTPLinkPoolTest {
 
	private static Logger logger =LoggerFactory.getLogger(FTPClientPool.class);
	/**
	* @author: tompai
	* @createTime: 2019年12月31日 下午1:13:51
	* @history:
	* @param args void
	*/
 
	public static void main(String[] args) {
		//TODO Auto-generated method stub
		FTPClientConfig conf=new FTPClientConfig();
		conf.setHost("127.0.0.1");
		conf.setUsername("test");
		conf.setPassword("test");
		
		FTPClientFactory factory=new FTPClientFactory();
		factory.setFtpPoolConfig(conf);
		
		FTPClientPool pool=new FTPClientPool(factory);
		
		FTPClientHelper clientHelper=new FTPClientHelper();
		clientHelper.setFtpClientPool(pool);
		
		String pathname="/0821";
		FTPFile[] files=clientHelper.listFiles(pathname);
		for(FTPFile file:files) {
			String name=file.getName();
			logger.info("name:{}",name);
		}
	}
 
}
 
3.6 测试结果
使用Apache commons-pool2实现高效的FTPClient连接池的方法的更多相关文章
- Java--对象池化技术 org.apache.commons.pool2.ObjectPool
		
org.apache.commons.pool2.ObjectPool提供了对象池,开发的小伙伴们可以直接使用来构建一个对象池 使用该对象池具有两个简单的步骤: 1.创建对象工厂,org.apache ...
 - Apache Commons Pool2 源码分析 | Apache Commons Pool2 Source Code Analysis
		
Apache Commons Pool实现了对象池的功能.定义了对象的生成.销毁.激活.钝化等操作及其状态转换,并提供几个默认的对象池实现.在讲述其实现原理前,先提一下其中有几个重要的对象: Pool ...
 - Lettuce连接池——解决“MXBean already registered with name org.apache.commons.pool2:type=GenericObjectPool,name=pool”
		
LettuceConfig: package com.youdao.outfox.interflow.config; import io.lettuce.core.support.Connection ...
 - springboot集成redis报错-ClassNotFoundException: org.apache.commons.pool2.impl.GenericObjectPoolConfig
		
当使用Springboot 2.0以上版本集成redis的时候遇到报错信息如下: Application run failed org.springframework.beans.factory.Un ...
 - Caused by: java.lang.NoClassDefFoundError: org/apache/commons/pool2/impl/GenericObjectPoolConfig
		
Caused by: java.lang.NoClassDefFoundError: org/apache/commons/pool2/impl/GenericObjectPoolConfig at ...
 - java.lang.ClassNotFoundException: org.apache.commons.pool2.impl.GenericObjectPoolConfig
		
问题描述: Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with n ...
 - Failed to unregister the JMX name: org.apache.commons.dbcp2:name=xxx,type=BasicDataSource
		
把datesource的bean的class由 org.apache.commons.dbcp2.BasicDataSource 改成 org.apache.tomcat.dbcp.dbcp.Basi ...
 - Apache Commons 系列简介 之 Pool
		
一.概述 Apache Commons Pool库提供了一整套用于实现对象池化的API,以及若干种各具特色的对象池实现.2.0版本,并非是对1.x的简单升级,而是一个完全重写的对象池的实现,显著的提升 ...
 - Apache common pool2 对象池
		
对象池的容器:包含一个指定数量的对象.从池中取出一个对象时,它就不存在池中,直到它被放回.在池中的对象有生命周期:创建,验证,销毁,对象池有助于更好地管理可用资源,防止JVM内部大量临时小对象,频繁触 ...
 - Dbcp2抛出org.apache.commons.dbcp2.LifetimeExceededException
		
三月 24, 2016 5:16:33 下午 org.apache.commons.dbcp2.BasicDataSource onSwallowException 警告: An internal o ...
 
随机推荐
- 调查报告解读之国外数据库篇:MySQL国内使用率第一,多少企业有意替换国外产品?
			
为了解数据库行业以及从业人员的现状.数据库选型.中国数据库的发展趋势等,墨天轮于2022年开始进行问卷收集,历时24天,共征集到有效问卷3476份,并于2月10日整理发布了<2022年墨天轮数据 ...
 - iOS工厂模式使用小结
			
一.什么是工厂方法? 正式的解释是:在基类中定义创建对象的一个接口,让子类决定实例化哪个类.工厂方法让一个类的实例化延迟到子类中进行.工厂方法要解决的问题是对象的创建时机,它提供了一种扩展的策略,很好 ...
 - Android复习(三)清单文件中的元素——>uses-configuration、uses-library、uses-permission、uses-permission-sdk-23
			
<uses-configuration> 语法: <uses-configuration android:reqFiveWayNav=["true" | &quo ...
 - SQLServer数据库事务级别
			
EFCore自动创建的数据库在SQLSERVER时是READ_COMMITTED_SNAPSHOT,SQLSERVER创建数据库默认是READ_COMMITTED. 因此记录一下查看和修改的方法,以便 ...
 - [网鼎杯 2020 朱雀组]phpweb
			
打开靶机,抓包分析,获得连个关键参数func和p,根据初始页面提示了解连个参数大概是功能和功能参数 测试func=system&p=ls提示hacker..说明有检测过滤 那么我们先读取源码看 ...
 - IntelliJ IDEA 2024激活码(亲测有效,仅供学习和交流)
			
资源是从官网购买,仅供学习和交流 激活码链接地址
 - Go语言单元测试的执行
			
Go 语言推荐测试文件和源代码文件放在同一目录下,测试文件以 _test.go 结尾.比如,当前 package 有 calc.go 一个文件,我们想测试 calc.go 中的 Add 和 Mul 函 ...
 - rce临时文件上传[RCE1]P8
			
rce临时文件上传[RCE1]P8 /[A-Za-z0-9!~^|&]+/i 匹配了我能想到的所有绕过方法,想到临时文件上传,是否可以执行/tmp/?????????这个文件呢 /tmp/?? ...
 - 鸿蒙NEXT开发案例:年龄计算
			
 [引言] 本案例的目标是开发一款年龄计算器应用,该应用能够根据用户输入的出生日期,计算出用户的实际年龄.虚岁.星座.生肖等信息.同时,应用还将提供距离下次公历和农历生日的天数及星期等信息.为了实现 ...
 - NASA的食物计划
			
NASA的食物计划 题目传送门 题目告诉我们要在体积和重量都不超过的情况下输出最大卡路里,稍微思考一下就可以发现这题是一道01背包的变形题(01背包不会的点这里). 并且01背包需要空间优化. 那我们 ...