最近学习了一下代理发现,代理其实一个蛮有用的,主要是用在动态的实现接口中的某一个方法而不去继承这个接口所用的一种技巧,首先是自定义的一个连接池

代码如下

  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3. import java.lang.reflect.Proxy;
  4. import java.sql.Connection;
  5. import java.sql.DriverManager;
  6. import java.sql.SQLException;
  7. import java.util.LinkedList;
  8. /**
  9. * 自定义连接池, 管理连接
  10. * 代码实现:
  11. 1. MyPool.java 连接池类,
  12. 2. 指定全局参数: 初始化数目、最大连接数、当前连接、 连接池集合
  13. 3. 构造函数:循环创建3个连接
  14. 4. 写一个创建连接的方法
  15. 5. 获取连接
  16. ------> 判断: 池中有连接, 直接拿
  17. ------> 池中没有连接,
  18. ------> 判断,是否达到最大连接数; 达到,抛出异常;没有达到最大连接数,
  19. 创建新的连接
  20. 6. 释放连接
  21. -------> 连接放回集合中(..)
  22. *
  23. */
  24. public class TestMyPool {
  25. private int init_count = 3; // 初始化连接数目
  26. private int max_count = 6; // 最大连接数
  27. private int current_count = 0; // 记录当前使用连接数
  28. // 连接池 (存放所有的初始化连接)
  29. private LinkedList<Connection> pool = new LinkedList<Connection>();
  30.  
  31. //1. 构造函数中,初始化连接放入连接池
  32. public TestMyPool() {
  33. // 初始化连接
  34. for (int i=0; i<init_count; i++){
  35. // 记录当前连接数目
  36. current_count++;
  37. // 创建原始的连接对象
  38. Connection con = createConnection();
  39. // 把连接加入连接池
  40. pool.addLast(con);
  41. }
  42. }
  43.  
  44. //2. 创建一个新的连接的方法
  45. private Connection createConnection(){
  46. try {
  47. Class.forName("com.mysql.jdbc.Driver");
  48. // 原始的目标对象
  49. final Connection con = DriverManager.getConnection("jdbc:mysql:///jdbc_demo", "root", "root");
  50.  
  51. /**********对con对象代理**************/
  52.  
  53. // 对con创建其代理对象
  54. Connection proxy = (Connection) Proxy.newProxyInstance(
  55.  
  56. con.getClass().getClassLoader(), // 类加载器
  57. //con.getClass().getInterfaces(), // 当目标对象是一个具体的类的时候
  58. new Class[]{Connection.class}, // 目标对象实现的接口
  59.  
  60. new InvocationHandler() { // 当调用con对象方法的时候, 自动触发事务处理器
  61. public Object invoke(Object proxy, Method method, Object[] args)
  62. throws Throwable {
  63. // 方法返回值
  64. Object result = null;
  65. // 当前执行的方法的方法名
  66. String methodName = method.getName();
  67.  
  68. // 判断当执行了close方法的时候,把连接放入连接池
  69. if ("close".equals(methodName)) {
  70. System.out.println("begin:当前执行close方法开始!");
  71. // 连接放入连接池 (判断..)
  72. pool.addLast(con);
  73. System.out.println("end: 当前连接已经放入连接池了!");
  74. } else {
  75. // 调用目标对象方法
  76. result = method.invoke(con, args);
  77. }
  78. return result;
  79. }
  80. }
  81. );
  82. return proxy;
  83. } catch (Exception e) {
  84. throw new RuntimeException(e);
  85. }
  86. }
  87.  
  88. //3. 获取连接
  89. public Connection getConnection(){
  90.  
  91. // 3.1 判断连接池中是否有连接, 如果有连接,就直接从连接池取出
  92. if (pool.size() > 0){
  93. return pool.removeFirst();
  94. }
  95.  
  96. // 3.2 连接池中没有连接: 判断,如果没有达到最大连接数,创建;
  97. if (current_count < max_count) {
  98. // 记录当前使用的连接数
  99. current_count++;
  100. // 创建连接
  101. return createConnection();
  102. }
  103.  
  104. // 3.3 如果当前已经达到最大连接数,抛出异常
  105. throw new RuntimeException("当前连接已经达到最大连接数目 !");
  106. }
  107.  
  108. //4. 释放连接
  109. public void realeaseConnection(Connection con) {
  110. // 4.1 判断: 池的数目如果小于初始化连接,就放入池中
  111. if (pool.size() < init_count){
  112. pool.addLast(con);
  113. } else {
  114. try {
  115. // 4.2 关闭
  116. current_count--;
  117. con.close();
  118. } catch (SQLException e) {
  119. throw new RuntimeException(e);
  120. }
  121. }
  122. }
  123.  
  124. public static void main(String[] args) throws SQLException {
  125. TestMyPool pool = new TestMyPool();
  126. System.out.println("当前连接: " + pool.current_count); // 3
  127.  
  128. // 使用连接
  129. pool.getConnection();
  130. pool.getConnection();
  131. Connection con4 = pool.getConnection();
  132. Connection con3 = pool.getConnection();
  133. Connection con2 = pool.getConnection();
  134. Connection con1 = pool.getConnection();
  135.  
  136. // 释放连接, 连接放回连接池
  137. // pool.realeaseConnection(con1);
  138. /*
  139. * 希望:当关闭连接的时候,要把连接放入连接池!【当调用Connection接口的close方法时候,希望触发pool.addLast(con);操作】
  140. * 把连接放入连接池
  141. * 解决1:实现Connection接口,重写close方法
  142. * 解决2:动态代理
  143. */
  144. con1.close();
  145.  
  146. // 再获取
  147. pool.getConnection();
  148.  
  149. System.out.println("连接池:" + pool.pool.size()); // 0
  150. System.out.println("当前连接: " + pool.current_count); // 3
  151. }
  152.  
  153. }

在这里使用代理主要是为了监测Connection 中的close()方法,当然也可以检测Connection中的其他方法,顺便值得一提的是还有Jdbc的两个开源连接数据库的框架可以为连接数据库省去一些代码:例如dbcp和c3p0这两个框架实现代码分别如下,但前提必须将对应的jar包导入

  1. import java.io.InputStream;
  2. import java.sql.Connection;
  3. import java.util.Properties;
  4.  
  5. import javax.sql.DataSource;
  6.  
  7. import org.apache.commons.dbcp.BasicDataSource;
  8. import org.apache.commons.dbcp.BasicDataSourceFactory;
  9. import org.junit.Test;
  10.  
  11. public class App_Dbcp {
  12.  
  13. public App_Dbcp() {
  14. // TODO Auto-generated constructor stub
  15. }
  16.  
  17. /**
  18. * 硬编码方式
  19. */
  20. @Test
  21. public void testDbcp()
  22. {
  23. //DBCP中的核心类
  24. BasicDataSource dataSource = new BasicDataSource();
  25. //连接池配置参数,初始化连接参数,最大连接参数,连接的驱动名
  26.  
  27. dataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
  28. dataSource.setUrl("jdbc:sqlserver://localhost:1433;DatabaseName=教学库");
  29. dataSource.setUsername("sa");
  30. dataSource.setPassword("****");
  31.  
  32. dataSource.setInitialSize(3);//设置初始化连接参数
  33. dataSource.setMaxActive(6);//设置最大连接数
  34. dataSource.setMaxIdle(3000);//设置最大空闲时间
  35. //获取连接
  36. try {
  37. Connection con = dataSource.getConnection();
  38. con.prepareStatement("delete from tb_user where id=3").executeUpdate();
  39. //关闭
  40. con.close();
  41. } catch (Exception e) {
  42. // TODO Auto-generated catch block
  43. e.printStackTrace();
  44. throw new RuntimeException(e);
  45. }
  46.  
  47. }
  48.  
  49. @Test
  50. public void testDBCP()
  51. {
  52. /**
  53. * 使用配置方式来获取参数
  54. */
  55.  
  56. try
  57. {
  58. Properties props = new Properties();
  59.  
  60. InputStream in = App_Dbcp.class.getResourceAsStream("/db.properties");
  61. //读取流文件
  62. props.load(in);
  63.  
  64. //根据Props配置文件直接产生数据对象
  65.  
  66. DataSource dataSource = BasicDataSourceFactory.createDataSource(props);
  67.  
  68. //创建连接对象
  69. Connection con = dataSource.getConnection();
  70. con.prepareStatement("delete from tb_user where id=4").executeUpdate();
  71. con.close();
  72. }catch(Exception e)
  73. {
  74. throw new RuntimeException(e);
  75. }
  76. }
  77. }

c3p0连接池的测试代码

  1. package gz.itcast.b_c3p0;
  2.  
  3. import java.beans.PropertyVetoException;
  4. import java.sql.Connection;
  5. import java.sql.SQLException;
  6.  
  7. import org.junit.Test;
  8.  
  9. import com.mchange.v2.c3p0.ComboPooledDataSource;
  10.  
  11. public class App {
  12.  
  13. public App() {
  14. // TODO Auto-generated constructor stub
  15. }
  16.  
  17. //硬编码方式,使用c3p0连接池来管理连接数目
  18. @Test
  19. public void testCode() throws Exception {
  20. //创建c3p0核心类
  21. ComboPooledDataSource dataSource = new ComboPooledDataSource();
  22.  
  23. dataSource.setDriverClass("com.microsoft.sqlserver.jdbc.SQLServerDriver");
  24. dataSource.setJdbcUrl("jdbc:sqlserver://localhost:1433;DatabaseName=教学库");
  25. dataSource.setUser("sa");
  26. dataSource.setPassword("***");
  27. dataSource.setInitialPoolSize(3);
  28. dataSource.setMaxPoolSize(6);
  29. dataSource.setMaxIdleTime(3000);
  30.  
  31. Connection con = dataSource.getConnection();
  32.  
  33. con.prepareStatement("delete from tb_user where id=3").executeUpdate();
  34. con.close();
  35. }
  36.  
  37. //c3p0使用xml配置文件来管理连接方式
  38.  
  39. @Test
  40. public void testXml() throws Exception
  41. {
  42. //c3p0核心类,在new 一个对象时就会自动的加载c3p0-config.xml文件
  43. ComboPooledDataSource dataSource = new ComboPooledDataSource();
  44.  
  45. Connection con = dataSource.getConnection();
  46. con.prepareStatement("delete from tb_user where id=2").executeUpdate();
  47.  
  48. //关闭连接
  49. con.close();
  50. }
  51. }

对应的xml配置文件

  1. <c3p0-config>
  2. <default-config>
  3. <property name="driverClass">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
  4. <property name="url">jdbc:sqlserver://localhost:1433;DatabaseName=教学库</property>
  5. <property name="username">sa</property>
  6. <property name="password">****</property>
  7. <property name="initialPoolSize">3</property>
  8. <property name="maxPoolSize">6</property>
  9. <property name="maxIdleTime">3000</property>
  10. <!--
  11. <user-overrides user="swaldman">
  12. <property name="debugUnreturnedConnectionStackTraces">true</property>
  13. </user-overrides>
  14. -->
  15.  
  16. </default-config>
  17.  
  18. <!--
  19. <named-config name="dumbTestConfig">
  20. <property name="maxStatements">200</property>
  21. <property name="jdbcUrl">jdbc:test</property>
  22. <user-overrides user="poop">
  23. <property name="maxStatements">300</property>
  24. </user-overrides>
  25. </named-config>
  26. -->
  27.  
  28. </c3p0-config>

最后就到为止了

java通过代理创建Conncection对象与自定义JDBC连接池的更多相关文章

  1. 自定义JDBC链接池

    上篇简单介绍了jdbc链接数据库: 本篇就说一下自定义连接池以及增删改查的测试: 自定义连接池 自定义链接池的原因 JDBC连接中用到Connection   在每次对数据进行增删查改 都要 开启  ...

  2. JDBC连接池-自定义连接池

    JDBC连接池 java JDBC连接中用到Connection   在每次对数据进行增删查改 都要 开启  .关闭  ,在实例开发项目中 ,浪费了很大的资源 ,以下是之前连接JDBC的案例 pack ...

  3. 自定义一个简单的JDBC连接池

    一.什么是JDBC连接池? 在传统的JDBC连接中,每次获得一个Connection连接都需要加载通过一些繁杂的代码去获取,例如以下代码: public static Connection getCo ...

  4. Java之JDBC连接池

    数据库连接池 连接池的概述 概念:其实就是一个容器(集合),存放数据库连接的容器. 当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时, 从容器中获取连接对象,用户访问完之后 ...

  5. Java中JDBC连接池&JDBCTemplate

    数据库连接池 概念:其实就是一个容器(集合),存放数据库连接的容器. 当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归 ...

  6. c3p0数据库连接池 原创: Java之行 Java之行 5月8日 一、连接池概述 实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程

    c3p0数据库连接池 原创: Java之行 Java之行 5月8日 一.连接池概述 实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程 DB连接池HikariCP为什么如此快 原创: D ...

  7. Java反射机制(创建Class对象的三种方式)

    1:SUN提供的反射机制的类: java.lang.Class<T> java.lang.reflect.Constructor<T> java.lang.reflect.Fi ...

  8. 透析Java本质-谁创建了对象,this是什么

    是构造方法创建的对象吗 package com.java.essence_36; import java.util.ArrayList; import java.util.List; /** * Cr ...

  9. Java基础之创建实例化对象的方式

    Java中创建(实例化)对象的五种方式  1.用new语句直接创建对象,这是最常见的创建对象的方法. 2.通过工厂方法返回对象,如:String str = String.valueOf(23); 3 ...

随机推荐

  1. Android环境配置(Eclipse全开发环境下载)

    Android环境配置 前期准备 Android环境的Eclipse: 网站链接:https://www.runoob.com/w3cnote/android-tutorial-eclipse-adt ...

  2. 7.解决在python中用selenium启动FireFox浏览器启动不了的方法

    首次在利用python中的selenium启动FireFox浏览器时可能碰到如下问题 当输入如下代码时: from selenium import webdriver brower=webdriver ...

  3. Solr7.0搭建过程

    小李经过Elasticsearch和solr之我为什么选择solr之后决定使用使用Solr作为项目的搜索引擎,然后和同事们开始讨论细节问题. 小李:虽然我会solr4.7版本的搭建,但是人总要有点梦想 ...

  4. 你真的了解MyBatis中${}和#{}的区别吗?

    动态sql是mybatis的主要特性之一.在mapper中定义的参数传到xml中之后,在查询之前mybatis会对其进行动态解析. mybatis提供了两种支持动态sql的语法:#{} 和 ${}. ...

  5. 玲珑杯”ACM比赛 Round #18 A -- 计算几何你瞎暴力(瞎暴力)

    题目链接:http://www.ifrog.cc/acm/problem/1143?contest=1020&no=0 题解:就是瞎暴力具体多暴力看一下代码就知道了. #include < ...

  6. axios跨域访问eggjs的坑egg-cors egg-passport passport-local session传递问题

    在同一机器上写前端和后端,前端使用webpack-dev-server启动,后端直接在eggjs项目目录下使用npm run dev启动,这种情况下,前端访问后端就是跨域访问.eggjs提供了一个跨域 ...

  7. Scrum团队的最佳规模?

    无论你在小型创业公司工作还是在大公司的新产品线工作,当团队人数越来越多时总会达到一个临界点.尽早识别这个临界点可以让您的团队避免进入低效阶段.每个产品都是不同的,团队合作也是如此.因此,拆分团队也需要 ...

  8. Python批量删除mysql中千万级大量数据

    场景描述 线上mysql数据库里面有张表保存有每天的统计结果,每天有1千多万条,这是我们意想不到的,统计结果咋有这么多.运维找过来,磁盘占了200G,最后问了运营,可以只保留最近3天的,前面的数据,只 ...

  9. 每天学会一点点(重写equals一定要重写hashcode)

    package com.example.demo.javaError; import java.util.HashMap; /** * Created by yyy on 2019/01/24. */ ...

  10. Factory Method工厂方法模式

    定义一个用于创建对象的接口,让子类决定将哪一个类实例化.Factory Method使一个类的实例化延迟到其子类,属于创建型模式 在此模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类负责生产 ...