JDBC

1. Driver接口
注册数据库驱动程序,分别为:
DriverManager.registerDriver(new Driver());
Class.forName("com.mysql.jdbc.Driver");

推荐采用第二种方式,因为它本身采用静态代码块
如果采用第一种的方式,会注册两次

2. url:即连接协议
jdbc:mysql:///127.0.0.1:3306/db9?useUnicode=true&characterEncoding=UTF8
3. Connection
Statement及其子类
ResulSet
select * from someTable   --N+2 查询结果永远是N+2条,因为包括行首,行尾

连接池的引入

创建Connection的过程是非常耗时的,为保证Connection可以重用,应该对其进行池管理.

传统的连接只有一个,我们把它比作公路,我们连接创建后进行sql操作后再关闭连接,就相当于你从高速公路到达某个地方后,把走过的那条高速公路拆了,过河拆桥,别人就不能访问了,别人只好重修修建公路(自己再重新new 一个连接)

于是,传统解决办法:创建一个静态工厂方法(多次使用,防止重复new),但是只有一个连接

所以还是不行,于是引入了连接池,我们可以把它比作抽奖箱里面的小球,具体自己可以琢磨一下

连接池的基本实现

         为什么要有连接池

          1:维护多个连接。必须要保证每一个线程获取到的是不同的connection对象。

          2:提供一个方法可以回收连接。

而程序员,总是调用close方法,所以为了回收连接。我们应该重写close方法。对close方法增强。一下是三种实现方式:

子类。(继承的体现)

包装。

代理。

动态代理实现连接池

动态代理:

作用:1.对某个方法增强.

2.在不污染原类的情况下,修改原类的行为.

代理类,与被代理类,两个不同的实体

要求:

所有被代理的类,都必须要拥有一个接口.

本质上是对方法的修改,但其实它是通过反射执行的某个方法.

代理是代理接口

代理的任务

1.在内存中创建某个接口的子类.

2.拦截所有在代理上知心的方法(出了getClass方法)

用动态代理书写连接池

设计:

代理的目标:原生的Connection

代理的目的:修改close方法,让close方法不可以关闭连接,且主动回收连接

小技巧:在myeclipse中,资源文件创建时默认是iso 8859-1编码(不管你项目创建的是以什么编码方式的)

具体代码实现:

 1 public class ConnUtils{
 2     //第一步:声明连接池维护所有的连接
 3     private static List<Connection> pool = new ArrayList<Connection>();
 4     //第二步:静态代码块中创建多个连接
 5     static{
 6         try{
 7             Class.forName("com.mysql.jdbc.Driver");
 8             String url = "jdbc:mysql:///db909?characterEncoding=UTF8";
 9             for(int i=0;i<3;i++){
10                 final Connection con = DriverManager.getConnection(url,"root","1234");//com.mysql.jdbc.Jdbc4Connection@
11                 //对con对象进行动态代理
12                 Object proxyedCon = 
13                         Proxy.newProxyInstance(
14                                 ConnUtils4.class.getClassLoader(),
15                                 new Class[]{Connection.class},
16                                 //声明执行句柄,只对close方法设置拦截
17                                 new InvocationHandler() {
18                                     public Object invoke(Object proxy, Method method, Object[] args)
19                                             throws Throwable {
20                                         if(method.getName().equals("close")){
21                                             System.err.println("有人想关闭连接,不能关,还连接");
22                                             //将proxy再加到pool中,这个proxy就是proxyedCon
23                                             synchronized (pool) {
24                                                 pool.add((Connection) proxy);
25                                                 pool.notify();
26                                             }
27                                             return null;
28                                         }else{
29                                             System.err.println("放行"+method.getName());
30                                             return method.invoke(con, args);
31                                         }
32                                     }
33                                 });
34                 //一定要将代理对象添加到池中去。
35                 pool.add((Connection) proxyedCon);
36             }
37         }catch(Exception e){
38             throw new RuntimeException(e.getMessage(),e);
39         }
40     }
41     /**
42      * 提供一个静态工厂方法返回一个连接
43      */
44     public static Connection getCon(){
45         synchronized (pool) {
46             if(pool.size()==0){
47                 try {
48                     pool.wait();
49                 } catch (InterruptedException e) {
50                     e.printStackTrace();
51                 }
52                 return getCon();
53             }
54             Connection con = pool.remove(0);//返回一个代理的connection对象
55             System.err.println("还有几个:"+pool.size());
56             return con;
57         }
58     }
59 }

以上代码可以优化

通过类加载器读取一个资源文件:

SomeClass.class.getResourcre(xxx) --获取与SomeClass字节码同一个目录下的xxx文件.

SomeClass.class.getClassLoader().getResource(xxxxx)  --获取classpath根上下的xxxxx文件

1.将url,driver,name,pwd写到一个配置文件中去

2.通过LinkedList来维护池.

优化后的代码:

 1 public class ConnUtils3 {
 2     private static LinkedList<Connection> pool = new LinkedList<Connection>();
 3     static{
 4         try {
 5             //声明资源器类 - 
 6             Properties prop = new Properties();
 7             //获取这个文件的路径
 8             URL url = ConnUtils3.class.getClassLoader().getResource("jdbc.properties");
 9             String path = url.getPath();
10             //为了防止有中文或是空格
11             path = URLDecoder.decode(path,"UTf-8");
12             File file = new File(path);
13             //加载jdbc.properties这个文件
14             prop.load(new FileInputStream(file));
15             //获取信息
16             String driver = prop.getProperty("driver");
17             Class.forName(driver);
18             String jdbcurl = prop.getProperty("url");
19             String nm = prop.getProperty("name");
20             String pwd = prop.getProperty("pwd");
21             //创建三个原生的连接,都将它们代理
22             String poolSize = prop.getProperty("poolSize");
23             int size = Integer.parseInt(poolSize);
24             for(int i=0;i<size;i++){
25                 final Connection con = DriverManager.getConnection(jdbcurl,nm,pwd);
26                 //对con进行动态代理
27                 Object proxyedObj = 
28                         Proxy.newProxyInstance(ConnUtils3.class.getClassLoader(),
29                                     new Class[]{Connection.class},
30                                     new InvocationHandler() {
31                                         public Object invoke(Object proxy, Method method, Object[] args)
32                                                 throws Throwable {
33                                             //是否是close方法
34                                             if(method.getName().equals("close")){
35                                                 synchronized (pool) {
36                                                     pool.addLast((Connection) proxy);
37                                                     pool.notify();
38                                                 }
39                                                 return null;//如果调用的是close则不会调用被代理类的方法。
40                                             }
41                                             return method.invoke(con, args);
42                                         }
43                                     });
44                 //将代理对象放到pool中
45                 pool.add((Connection) proxyedObj);
46             }
47         } catch (Exception e) {
48             e.printStackTrace();
49         }
50     }
51     
52     public static Connection getConn(){
53         synchronized (pool) {
54             if(pool.size()==0){
55                 try {
56                     pool.wait();
57                 } catch (InterruptedException e) {
58                     e.printStackTrace();
59                 }
60                 return getConn();
61             }else{
62                 Connection con = pool.removeFirst();
63                 System.err.println("还有几个:"+pool.size());
64                 return con;
65             }
66         }
67     }
68     
69     
70 }

什么时候可以使用statement而不使用Perpstatement呢?

在用户不需要输入的时候,可以采用statement,其他建议全部使用Perpstatement

最后,附上开发开发分层图

原文地址:https://www.cnblogs.com/ylfeiu/p/3621886.html