发表于: 2017-12-29 21:33:25
1 612
今天完成的事情:
今天学习了一下关于连接池的相关运用。大概如下:
首先创建maven项目,在pom中添加相关的依赖。
在数据库建立相应的数据库以及数据表。
然后在resource文件夹中建立关于数据源以及连接池的相关配置文件:jdbc.properties
#数据库账户名
userName=root
#数据库密码
password=lucifer
#初始化连接数
initCount=10
#步进数量
stepSize=4
#最大连接池个数
poolMaxSize=100
然后,可以正式开始编写相关的java代码了。
首先呢,在数据库建立连接池ImyPool接口以及相应的实现类MyPoolImpl:
package com.lcma.pools;
import com.lcma.conn.PooledConnection;
/**
* <p>Description: 连接池接口</p>
* <p>Copyright : Copyright (c) 2017</p>
* @author : lcma
* @version : 1.0
*/
public interface IMyPool {
/**
* <p>Discription:创建连接</p>
* @param count
* @author : lcma
* @update : 2016年12月4日下午1:11:46*/
public void createConnection(int count);
/**
* <p>Discription:获取连接</p>
* @return
* @author : lcma
* @update : 2016年12月4日下午1:11:34
*/
public PooledConnection getConnection();
}
package com.lcma.pools.impl;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import java.util.Vector;
import com.lcma.conn.PooledConnection;
import com.lcma.pools.IMyPool;
/**
* <p>Title : 连接池接口实现类</p>
* <p>Description: [子应用名]_[模块名]</p>
* <p>Copyright : Copyright (c) 2016</p>
* <p>Company : 科大讯飞</p>
* @author : lcma
* @version : 1.0
*/
public class MyPoolImpl implements IMyPool {
/**
* 驱动名称
*/
private String jdbcDriver;
/**
* 连接地址
*/
private String jdbcUrl;
/**
* 用户名
*/
private String userName;
/**
* 密码
*/
private String password;
/**
* 初始化连接数
*/
private int initCount;
/**
* 步进连接数
*/
private int stepSize;
/**
* 最大连接数
*/
private int poolMaxSize;
/**
* 连接池容器
*/
private static Vector<PooledConnection> pooledConnections = new Vector<PooledConnection>();
/**
* 构造函数,执行初始化方法
*/
public MyPoolImpl() {
init();
}
/**
* <p>Discription:初始化连接池</p>
* @author : lcma
* @update : 2016年12月5日下午8:42:37
*/
private void init(){
InputStream is = this.getClass().getClassLoader().getResourceAsStream("jdbc.properties");
Properties pro = new Properties();
try {
pro.load(is);
} catch (IOException e) {
e.printStackTrace();
}
jdbcDriver = pro.getProperty("jdbcDriver");
jdbcUrl = pro.getProperty("jdbcUrl");
userName = pro.getProperty("userName");
password = pro.getProperty("password");
initCount = Integer.parseInt(pro.getProperty("initCount"));
stepSize = Integer.parseInt(pro.getProperty("stepSize"));
poolMaxSize = Integer.parseInt(pro.getProperty("poolMaxSize"));
try {
Driver driver = (Driver)Class.forName(jdbcDriver).newInstance();
//将driver注册
DriverManager.registerDriver(driver);;
} catch (Exception e) {
e.printStackTrace();
}
//创建连接
createConnection(initCount);
}
/**
* <p>Discription:创建连接</p>
* @param count
* @author : lcma
* @update : 2016年12月4日下午1:11:46
*/
@Override
public void createConnection(int count) {
if(poolMaxSize<=0 || pooledConnections.size()+count > poolMaxSize){
System.out.println("创建连接失败,超过最大连接数");
throw new RuntimeException("创建连接失败,超过最大连接数");
}
try {
//循环创建连接
for(int i = 0; i < count; i++){
//创建连接
Connection connection = DriverManager.getConnection(jdbcUrl, userName, password);
//实例化连接池中的连接
PooledConnection pooledConnection = new PooledConnection(connection, false);
//存入连接池容器
pooledConnections.add(pooledConnection);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* <p>Discription:获取连接</p>
* @return
* @author : lcma
* @update : 2016年12月4日下午1:11:34
*/
@Override
public PooledConnection getConnection() {
if(pooledConnections.size()<=0){
System.out.println("获取连接失败,连接池为空");
throw new RuntimeException("获取连接失败,连接池为空");
}
PooledConnection connection = getRealConnection();
//判断是否为空
while(connection == null){
//创建connection,步进数
createConnection(stepSize);
//重新获取连接,有可能获取的还为空,采用while循环判断
getRealConnection();
//防止其他线程过来拿连接
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return connection;
}
//判断我们是否拿到有效的连接对象
private synchronized PooledConnection getRealConnection(){
//先判断连接池是不是有我们需要的空闲连接对象
for(PooledConnection connection : pooledConnections){
//未处于繁忙状态
if(!connection.isBusy()){
Connection conn = connection.getConn();
try {
//判断这个连接是不是有效,isValid就是创建了一个statement,执行sql语句,看是否成功
if(!conn.isValid(2000)){
Connection validConn = DriverManager.getConnection(jdbcUrl, userName, password);
connection.setConn(validConn);
}
} catch (SQLException e) {
e.printStackTrace();
}
//设置为繁忙
connection.setBusy(true);
return connection;
}
}
return null;
}
public String getJdbcDriver() {
return jdbcDriver;
}
public void setJdbcDriver(String jdbcDriver) {
this.jdbcDriver = jdbcDriver;
}
public String getJdbcUrl() {
return jdbcUrl;
}
public void setJdbcUrl(String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
}
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 getInitCount() {
return initCount;
}
public void setInitCount(int initCount) {
this.initCount = initCount;
}
public int getStepSize() {
return stepSize;
}
public void setStepSize(int stepSize) {
this.stepSize = stepSize;
}
public int getPoolMaxSize() {
return poolMaxSize;
}
public void setPoolMaxSize(int poolMaxSize) {
this.poolMaxSize = poolMaxSize;
}
}
然后用单例模式对连接池进行管理PoolManager:
package com.lcma.manager;
import com.lcma.pools.impl.MyPoolImpl;
/**
* <p>Title : 利用内部类单例模式解决多线程问题</p>
* <p>Description: [子应用名]_[模块名]</p>
* <p>Copyright : Copyright (c) 2016</p>
* <p>Company : 科大讯飞</p>
* @author : lcma
* @version : 1.0
*/
public class PoolManager {
private static class creatPool{
private static MyPoolImpl poolImpl = new MyPoolImpl();
}
//多个线程在加载内部类的时候线程是互斥的,所以用单例模式的内部类形式避免线程混乱
public static MyPoolImpl getInstace(){
return creatPool.poolImpl;
}
}
然后在连接池中创建数据库链接DatabaseConnection:
package com.lcma.conn;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;
public class DatabaseConnection {
//配置数据库
private static final String CREATE_TABLE_TWITTER = "CREATE TABLE IF NOT EXISTS twitter (id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, msg varchar(300) not null) DEFAULT CHARSET=utf8";
final static String HOST = "host";
final static String PORT = "port";
final static String DB_NAME = "dbname";
final static String USERNAME = "username";
final static String PASSWORD = "password";
final static String url = "jdbc:mysql://" + HOST + ":" + PORT + "/" + DB_NAME
+ "?useUnicode=true&characterEncoding=utf-8";
private static final DatabaseConnection instance = new DatabaseConnection();
private final int INIT_COUNT = 5;
private final int MAX_COUNT = 30;
private int count = 0;
private final Object wait = new Object();
private LinkedList<Connection> CONN_POOL;
//创建数据库连接池
private DatabaseConnection() {
CONN_POOL = new LinkedList<Connection>();
try {
Class.forName("com.mysql.jdbc.Driver");
for (int i = 0; i < INIT_COUNT; i++) {
Connection connection = createConnection();
if (connection != null) {
CONN_POOL.add(createConnection());
count++;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static DatabaseConnection getInstance() {
return instance;
}
//创建数据库链接
private static Connection createConnection() {
try {
return DriverManager.getConnection(url, USERNAME, PASSWORD);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
//获取数据库链接
public Connection getConnection() {
synchronized (CONN_POOL) {
while (CONN_POOL.size() > 0) {
Connection conn = CONN_POOL.removeLast();
try {
if (conn.isValid(1000)) {
return conn;
} else {
count--;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
if (count < MAX_COUNT) {
count++;
return createConnection();
}
synchronized (wait) {
try {
wait.wait(3000);
if (CONN_POOL.size() > 0) {
return CONN_POOL.removeLast();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return null;
}
//释放闲置链接
public void releaseConnection(Connection connection) {
CONN_POOL.add(connection);
synchronized (wait) {
wait.notify();
}
}
}
建立使用链接的SQL执行类这里以查询为例证PooledConnection:
package com.lcma.conn;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* <p>Title : 存储连接池中对象属性</p>
* <p>Description: [子应用名]_[模块名]</p>
* <p>Copyright : Copyright (c) 2016</p>
* <p>Company : 科大讯飞</p>
* @author : lcma
* @version : 1.0
*/
public class PooledConnection {
/**
* 连接管道对象
*/
private Connection conn;
/**
* 连接状态,true-繁忙,false-空闲
*/
private boolean isBusy = false;
public PooledConnection(Connection conn, boolean isBusy){
this.conn = conn;
this.isBusy = isBusy;
}
public void close(){
this.isBusy = false;
}
public Connection getConn() {
return conn;
}
public void setConn(Connection conn) {
this.conn = conn;
}
public boolean isBusy() {
return isBusy;
}
public void setBusy(boolean isBusy) {
this.isBusy = isBusy;
}
/**
* <p>Discription:创建查询方法,用于测试使用</p>
* @param sql
* @return
* @author : lcma
* @update : 2016年12月5日下午11:19:18
*/
public ResultSet queryBySql(String sql){
ResultSet rs = null;
Statement sm = null;
try {
sm = conn.createStatement();
rs = sm.executeQuery(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return rs;
}
}
最后对程序进行测试MyPoolMain:
package com.lcma.main;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.lcma.conn.PooledConnection;
import com.lcma.manager.PoolManager;
import com.lcma.pools.impl.MyPoolImpl;
/**
* <p>Description: 测试类</p>
* <p>Copyright : Copyright (c) 2017</p>
*
* @author : lcma
* @version : 1.0
*/
public class MyPoolMain {
/**
* 获取连接池容器实现类
*/
private static MyPoolImpl poolImpl = PoolManager.getInstace();
/**
* 单个连接查询测试
*/
public synchronized static void selectData() {
PooledConnection connection = poolImpl.getConnection();
ResultSet rs = connection.queryBySql("select * from class");
try {
while (rs.next()) {
System.out.print(rs.getString("ID") + "\t\t");
System.out.print(rs.getString("NAME") + "\t\t");
System.out.print(rs.getString("TEACHER") + "\t");
System.out.println();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
connection.close();
}
}
/**
* <p>Discription:测试200个线程</p>
*
* @param args
* @author : lcma
* @update : 2016年12月5日下午11:44:18
*/
public static void main(String[] args) {
for (int i = 0; i < 2000; i++) {
try {
new Thread(new Runnable() {
public void run() {
selectData();
System.out.println();
}
}).start();
} catch (Exception e) {
System.out.println(e);
}
}
}}
开启测试结果如下:
还有尝试着向数据库插入一百万条数据,用时一个小时。
建立索引前查询速度:
建立索引后查询速度:
查阅了一下关于任务的步骤,感觉整体上已经完成了任务一的学习。
明天计划的事情:准备写任务小结,好好总结一下这一个月的学习,对这一个月的学习进行最后一次的梳理。最迟看后天能不能结束任务一。
遇到的问题:
1.在向师兄请教关于mvc以及WEB开发的入门时,进入浏览器总是申报500错误。
收获:
1.正向反馈对于学习是一件很重要的事情,如果把学习当做一个系统,那么持续的向自我学习这一系统注入良性刺激,保持知识的活跃度,能够让自我更快的成长。
2.有困难,如果迷茫,向他人求助是很有必要的事情,特别在你已经清醒得决定自己要走一条路的时候。在成长的路上,时间是很宝贵的事情,而他人的看到的往往能够让你节约大量的时间,而且学习表达沟通的技巧是很重要的事情。
3.
进度:进度很迷,完全把握不到自己的进度。
评论