数据库连接池实例-1(基础线程池)
前言
数据库连接池进行由浅到深的分项,打算进行三个模块,分别为:基础线程池(自己写了解基本原理),主流线程池配置使用,线程池比较与优化
一、数据库连接池存在原因
我们都了解到,数据库获取连接与关闭连接是非常消耗内存的,所以这样不如创建多个连接,将连接放入到一起,在需要使用的时候,拿出连接,进行使用,能够极大的减少内存消耗,同时提高效率。 具体的,设计模式中有一个 资源池设计模式,就是针对池进行设计的,可参考链接 https://www.cnblogs.com/shoshana-kong/p/11249000.html
二、例子
我是使用ArrayList用来存放我的连接,首先创建抽象类,AbsrtDataBase<T>,它的属性主要由两个:lockedList,UnlockedList分别存放,被使用的连接,和空闲的连接。
创建类:DataBase 继承AbsrtDataBase<T> 抽象类,在实现具体的代码。DataBase 类我设置成为单例模式,我们只需要一个数据库连接池没有必要多个。checkOut(),checkIn() 进行线程上锁,ArrList 为线程不安全的,必须上锁。
代码如下:
AbsrtDataBase<T>抽象类代码
import java.util.ArrayList;
/*
* 抽象类
* 资源连接池
*/
public abstract class AbsrtDataBase<T> {
ArrayList<T> lockedList, UnlockedList; // 存放的 连接对象
public AbsrtDataBase() {
}
/**
* 批量添加
*/
public void batchadd() {
for (int i = 0; i < 10; i++) {
T t = add();
this.UnlockedList.add(t);
}
}
/*
* 从UnlockedList中取出使用
*/
public abstract T checkOut() throws Exception;
/**
* 把数据库连接放回池中(UnlockedList中)
*
* @param t
* @return
* @throws Exception
*/
public abstract boolean checkedIn(T t) throws Exception;
// 往池中添加连接
public abstract T add();
// 移除即关闭连接
public abstract boolean remove(T t);
}
DataBase的代码: 主要通过读取文件,赋值,创建实例,创建线程进行读取。
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Properties;
public class DataBase extends AbsrtDataBase<Connection> {
private Long expiredTime=(long) 30000;//逾期时间
protected int initCon = 20;//初始默认值
private int maxCon =300;// 最大值
private int idleCon = 20;//空闲值
private int addnum = 0;
private int removenum =0;
private String url;
private String name;
private String password;
private String type;
private File proFile;
private String unCode = "gbk";
private String fileUrl = "C:/Users/DELL/Desktop/setting.property";
private static DataBase database ;
public static void main(String[] args){
DataBase database = null ;
try {
database = DataBase.getInstance();
database.getinit();
database.init();
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
for(int i = 0;i<10;i++){
Thread thread1 = new TestThread(database);//创建线程
Thread thread2 = new TestThread2(database);//创建线程
//启动线程
thread1.start();
thread2.start();
}
}
public void getinit() throws Exception {
proFile = new File(fileUrl);
if (proFile.exists()) {
FileInputStream fileinputStream = new FileInputStream(proFile);
InputStreamReader streamReader = new InputStreamReader(
fileinputStream, unCode);
Properties props = new Properties();
props.load(streamReader);
Field[] fields = DataBase.class.getDeclaredFields();
// 进行赋值
for (Field field : fields) {
String name = field.getName();// 获取类属性
String value = props.getProperty(name); // 查找到对应的值
Object type = field.getType();// 获取参数属性
String typeName = type.toString();// 获取参数类的名称属性;
System.out.println(typeName);
if (value != null) {
// 校验是否为String类型
if (typeName.indexOf("String") > 0) {
field.set(database, value);
}
// 检验是否为整形
if (typeName.indexOf("Int") > 0) {
int valueint = Integer.parseInt(value);
field.set(database, valueint);
}
// 检验是否为长整形
if (typeName.indexOf("long") > 0) {
Long valuelong = Long.getLong(value);
field.set(database, valuelong);
}
}
}
}
};
/*
* 单例模式只允许使用一个实例
*/
public static synchronized DataBase getInstance() throws Exception {
if (database == null) {
database = new DataBase();
}
return database;
}
private DataBase() throws Exception {
super();
}
public void init(){
lockedList = new ArrayList<Connection>(initCon);
UnlockedList = new ArrayList<Connection>(idleCon);
for(int i=0;i<this.initCon;i++){
Connection t = add();
super.UnlockedList.add(t);
}
}
@Override
public Connection add() {
// TODO 自动生成的方法存根
Connection connection = null;
try {
connection = DriverManager.getConnection(url, name, password);
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
return connection;
}
@Override
public boolean remove(Connection t) {
// TODO 自动生成的方法存根
boolean flage = true; // 标志是否成功
if (t != null) {
try {
t.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
flage = false;
}
}
return flage;
}
/**
* 将不使用的连接重新放入到 UnlockedList 中
*/
@Override
public synchronized boolean checkedIn(Connection t) throws Exception {
removenum++;
System.out.println("当前执行数检入"+removenum);
int currentLocked = lockedList.size();
//lockedList不为空的情况下转入
if(currentLocked!=0){
//将 UnlockedList 中的数据转出到 LockedList 中
t = lockedList.get(currentLocked-1);
UnlockedList.add(t);
lockedList.remove(currentLocked-1);
boolean flage = remove( t);
return flage;
}else{
throw new Exception("数据量较小不能转出");
}
}
/**
* 将要被使用的 connection 从池中进行拿出来。
*/
@Override
public Connection checkOut() throws Exception {
// TODO 自动生成的方法存根
addnum++;
if(UnlockedList.size()==0){
batchadd();
};
System.out.println("当前执行数检出"+addnum);
int currentUnlocked = UnlockedList.size();
Connection t = UnlockedList.get(currentUnlocked-1);
int currentLocked = lockedList.size();
//将unlockedList 的放入到 LockedList中
if(currentLocked<maxCon){
lockedList.add(t);
UnlockedList.remove(t);
return t;
}else{
throw new Exception("已经超出了最大连接数");
}
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public File getProFile() {
return proFile;
}
public void setProFile(File proFile) {
this.proFile = proFile;
}
public String getUnCode() {
return unCode;
}
public void setUnCode(String unCode) {
this.unCode = unCode;
}
public String getFileUrl() {
return fileUrl;
}
public void setFileUrl(String fileUrl) {
this.fileUrl = fileUrl;
}
}
总结
自己写一个简单的线程池才能了解到,如何去实现线程池,虽然例子很简单,但是可以加深印象。