>>分享Java编程技术,对《Java面向对象编程》等书籍提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 23692 个阅读者 刷新本主题
 * 贴子主题:  Java中用动态代理实现标准的DataSource数据源连接池 回复文章 点赞(0)  收藏  
作者:日月光华    发表时间:2020-06-07 09:46:32     消息  查看  搜索  好友  邮件  复制  引用

Java中用动态代理实现标准的DataSource数据源连接池

版权声明:本文遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文转自:https://blog.csdn.net/ju_362204801/article/details/78886102

首先简单谈谈为什么要用连接池?

大家知道,我们平常连接数据库的时候,首先需要获取到数据库的连接,在Java中对应的是 Connection,建立获取数据库连接是比较消耗资源的,而且每次建立获取连接也比较浪费时间,可以试想,如果每次请求过来,需要访问数据库时,都去重新建立并获取新的连接,会浪费大量的资源和时间,此时客户端的响应时间肯定会较长,这并不是我们想看到的。因此这时候我们就要想办法避免这种现象,所以这时候就可以用连接池来解决。
其实简单的说,连接池实现的主要目的就是,获取连接的时候从池中获取已经初始化好的连接,这样做就不用每次都建立新的连接,就能节省资源的消耗,也能提高效率。然后在用完连接以后,调用conn.close( ); 关闭连接的时候并不是真去把这个连接关闭掉,而是应该把这个连接放回到池中,下次请求过来了,可以继续使用。
Java中连接池具体的实现一般有两种方式,一种是用包装类来实现,另一种是用动态代理来实现
现在常见的开源的Java连接池有DBCP和C3P0等,其中DBCP就是上边说的利用包装类来实现的,而C3P0是动态代理实现的。
今天讲一下动态代理的实现,关于包装类的实现方法,我也简单总结了一下,写了一篇博客
Java中用包装模式实现标准的DataSource数据源连接池
有兴趣的可以点击看一下
ok,下面我们简单讲一下动态代理的实现,用动态代理写一个简单的连接池,供新同学参考,高手请自动忽略。
首先贴一下为这次例子我建的一个简单的学生表,数据库是自己电脑虚拟机Linux上装的MySql数据库
点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小
超级的简单的一个表,就不多解释了。下面开始进入正题...
第一步:我们需要写一个标准的数据源DataSource,Java中DataSource是一个标准的数据源接口
/**

*

* @author caoju

*

*/


public class MyDataSource implements DataSource{



private static LinkedList<Connection> pool = new LinkedList<Connection>();

private static final String name = "com.mysql.jdbc.Driver";

private static final String url = "jdbc:mysql://192.168.199.188:3306/cj";

private static final String user = "root";

private static final String password = "123456";

    

    static{//利用静态代码块儿在类一加载的时候就初始化10个连接到池中

try {

Class.forName(name);

for(int i=0;i<10;i++){

Connection conn = DriverManager.getConnection(url, user, password);

pool.add(conn);

}

} catch (Exception e) {

e.printStackTrace();

}

}

    

@Override

public Connection getConnection() throws SQLException {

if(pool.size()>0){

final Connection conn = pool.remove();

//返回动态代理对象

return (Connection)Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler() {

@Override

public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable {

if("close".equals(method.getName())){

return pool.add(conn);

}else {

return method.invoke(conn, args);

}

}

});

}else{

throw new RuntimeException("对不起,服务器忙...");

}

}

@Override

public PrintWriter getLogWriter() throws SQLException {

return null;

}



@Override

public void setLogWriter(PrintWriter out) throws SQLException {

// TODO Auto-generated method stub



}



@Override

public void setLoginTimeout(int seconds) throws SQLException {

// TODO Auto-generated method stub



}



@Override

public int getLoginTimeout() throws SQLException {

// TODO Auto-generated method stub

return 0;

}



@Override

public Logger getParentLogger() throws SQLFeatureNotSupportedException {

// TODO Auto-generated method stub

return null;

}



@Override

public <T> T unwrap(Class<T> iface) throws SQLException {

// TODO Auto-generated method stub

return null;

}



@Override

public boolean isWrapperFor(Class<?> iface) throws SQLException {

// TODO Auto-generated method stub

return false;

}





@Override

public Connection getConnection(String username, String password)

throws SQLException {

// TODO Auto-generated method stub

return null;

}



}

返回动态代理对象需要注意几点:一,代理对象需要和被代理的对象用一个类加载器;二,代理对象需要和被代理的对象实现同样的接口;三,需要new InvocationHandler()来处理对象中具体的方法
第二步:建一个实体类对象,用来接收封装查询出来的数据


public class Student implements Serializable{



private static final long serialVersionUID = -1672204456370247243L;



private String id;



private String name;



public String getId() {

return id;

}



public void setId(String id) {

this.id = id;

}



public String getName() {

return name;

}



public void setName(String name) {

this.name = name;

}



@Override

public String toString() {

return "Student [id=" + id + ", name=" + name + "]";

}

}

这就是个普通的bean对象,很简单,没啥可说的。
第三步:写一个调用端来测试写的连接池


/**

*

* @author caoju

*

*/


public class Client {



public static void main(String[] args) {

DataSource ds = new MyDataSource();



Connection conn = null;

PreparedStatement ps = null;

try {

conn = ds.getConnection();

ps = conn.prepareStatement("select * from student");

ResultSet rs = ps.executeQuery();

List<Student> stuList = new ArrayList<Student>();

while(rs.next()){

Student student = new Student();

String id = rs.getString("id");

String name = rs.getString("name");

student.setId(id);

student.setName(name);

stuList.add(student);

}

for (Student student : stuList) {

System.out.println(student);

}



} catch (Exception e) {

e.printStackTrace();

}finally{

if(ps!=null){

try {

ps.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if(conn!=null){

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}
}

}

可以打断点看一下,返回的 conn 对象已经是$Proxy0,说明返回的已经是代理的对象了,而不是conn自身,而在返回的代理的对象里,我们已经对Close方法做了处理,所以就简单的实现了调用close的时候,不是真正的关闭数据库连接资源,而是把使用完的连接资源还回池中,供别的请求使用或者下次继续使用。
点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小
最后运行结果

好了,一个简单的连接池就实现了,虽然代码比较简陋,但是能讲清楚里边的原理就好啦,哈哈。
大家可以动手试一试,过程中需要导入MySQL的驱动包,不要忘记啦。



程序猿的技术大观园:www.javathinker.net
  Java面向对象编程-->图形用户界面(上)
  JavaWeb开发-->使用Session(Ⅰ)
  JSP与Hibernate开发-->Spring、JPA与Hibernate的整合
  Java网络编程-->通过JavaMail API收发邮件
  精通Spring-->组合(Composition)API
  Vue3开发-->创建综合购物网站应用
  [求助] 如何观看孙老师的课程视频
  面试官问:如何排除Java虚拟机的GC引起的CPU飙高?
  使用策略模式优化代码实践,如何让项目快速起飞
  [讨论]书中多线程章节的语言表述有误?
  Java设计模式中的工厂模式和策略模式范例
  volatile 实现原理
  java.util.logging.Logger使用详解
  超详细的Java运算符修炼手册(优秀程序员不得不知道的运算技...
  Java设计模式:抽象工厂模式
  java NIO示例以及流程详解
  Java读取大文件的高效率实现_java大文件
  Java Scoket之java.io.EOFException解决方案
  Java入门实用代码: List 列表中元素的替换
  Java入门实用代码: 集合中添加元素
  JDBC使用8.0驱动包连接mysql设置时区serverTimezone
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。