JDBC
JDBC工具类的抽取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
| import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties;
public class JDBCUtils { private static final String driverClassName; private static final String url; private static final String username; private static final String password; static{ Properties properties = new Properties(); try { properties.load(new FileInputStream("src/db.properties")); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } driverClassName=properties.getProperty("driverClassName"); url=properties.getProperty("url"); username=properties.getProperty("username"); password=properties.getProperty("password"); }
public static void loadDriver(){ try { Class.forName(driverClassName); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
public static Connection getConnection(){ Connection conn = null; try { loadDriver(); conn = DriverManager.getConnection(url,username,password); } catch (Exception e) { e.printStackTrace(); } return conn; }
public static void release(Statement stmt, Connection conn){ if(stmt != null){ try{ stmt.close(); }catch(SQLException e){ e.printStackTrace(); } stmt = null; } if(conn != null){ try{ conn.close(); }catch(SQLException e){ e.printStackTrace(); } conn = null; } } public static void release(ResultSet rs, Statement stmt, Connection conn){ if(rs != null){ try{ rs.close(); }catch(SQLException e){ e.printStackTrace(); } rs = null; } if(stmt != null){ try{ stmt.close(); }catch(SQLException e){ e.printStackTrace(); } stmt = null; } if(conn != null){ try{ conn.close(); }catch(SQLException e){ e.printStackTrace(); } conn = null; } } }
|
JDBC的配置信息提取到配置文件
配置文件
- 属性文件
- 格式:拓展名是.properties
- 内容:key=value(键值对)
- XML文件
提取信息到配置文件
定义一个配置文件
- driverClassName:驱动名,5.8.0版本的为:com.mysql.jdbc.Driver
8.0.12版本的为:com.mysql.cj.jdbc.Driver
- url:驱动链接:以图中为例,格式为:jdbc:mysql://本机名:端口号/数据库名?是否采用SSL链接(一般为false)&Unicode编码&编码格式为UTF-8&时区设置(不加会出错)
- username:mysql用户名
- password:数据库连接密码
![JDBC出现乱码问题](https://img-blog.csdnimg.cn/20201002224931796.png#pic_center)
在工具类中解析属性文件
获取到具体内容为常量赋值
注:红框为配置文件路径
数据库连接池
连接池的概述
什么是连接池
连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的进程使用。
连接池是装有连接的容器,使用连接的话,可从连接中进行获取,使用完成之后将连接归还给连接池。
为什么要学习连接池
连接对象创建和是需要耗费时间的,在服务器初始化的时候就初始化一些连接。把这些连接放入到内存中,使用的时候可以从内存中获取,使用完成之后将连接放入连接池中。从内存中获取和归还的效率要远远高于创建和销毁的效率。(提升性能)
连接池原理
自定义连接池
自定义连接池的实现
- 编写一个类实现DataSource接口
- 重写getConnection方法
- 初始化多个连接在内存中
- 编写归还连接的方法
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| package com.jdbc.connectpool;
import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger;
import javax.sql.DataSource;
import com.jdbc.utils.JDBCUtils;
public class MyDataSourse implements DataSource { private List<Connection> connList = new ArrayList<Connection>(); public MyDataSourse(){ for(int i = 1;i<=3;i++){ connList.add(JDBCUtils.getConnection()); } } @Override public Connection getConnection() throws SQLException { Connection conn = connList.remove(0); return conn; } public void addBack(Connection conn){ connList.add(conn); }
@Override public PrintWriter getLogWriter() throws SQLException { return null; }
@Override public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override public void setLoginTimeout(int seconds) throws SQLException {
}
@Override public int getLoginTimeout() throws SQLException { return 0; }
@Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; }
@Override public <T> T unwrap(Class<T> iface) throws SQLException { return null; }
@Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; }
@Override public Connection getConnection(String username, String password) throws SQLException { return null; }
}
|
代码测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| package com.jdbc.connectpool;
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException;
import org.junit.Test;
import com.jdbc.utils.JDBCUtils;
public class DataSourseDemo1 {
@Test
public void demo1(){ Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; MyDataSource dataSource = null; try{ dataSource = new MyDataSource(); conn = dataSource.getConnection(); String sql = "select * from user"; pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); while(rs.next()){ System.out.println(rs.getInt("id")+rs.getString("username")+" "+rs.getString("password")); } }catch(Exception e){ e.printStackTrace(); }finally{ if(rs != null){ try{ rs.close(); }catch(SQLException e){ e.printStackTrace(); } } if(pstmt != null){ try{ pstmt.close(); }catch(SQLException e){ e.printStackTrace(); } } dataSource.addBack(conn); } } }
|
自定义连接池的问题
使用接口的实现类完成的构造
1
| MyDatasource dataSource = new MyDatasource();
|
这种写法不方便程序的扩展。
额外提供了方法归还连接
1 2
| daraSource.addBack(conn);
|
这种方式增加使用连接池的用户的难度。
自定义连接池的问题解决
如果不提供自定义的方法就可以解决这个问题,但是连接要如何归还到连接池呢?
解决分析的思路
原来在 Connection中是有一个close方法的,close方法完成了连接的销毁。能不能做一个事情,将原有的连接的 close方法改为归还。
- 现在要做的事情就是将原有的close方法的逻辑改为归还。(增强一个类中的方法)
如何增强一个类中的方法
1 2 3 4 5 6 7 8 9 10 11 12
| *****维承这种增强是最简单,但是是有使用条件的:必须能够控制这个类的构造!!! class Man{ public void run(){ System.out.ptintln(“跑….”); } }
class SuperMan extends Man{ public void run(){ System.out.println(“飞….”); } }
|
*****装饰者模式使用条件:
*一、增强的类和被增强的类实现相同的接口
*二、在增强的类中获得被增强的类的引用
使用装饰者模式增强Connection中的close方法:
为了简化编程,提供一个模板类(模板类原封不动的将接口中的所有方法都实现,但是都没有增强,即所有方法又重新调用了一遍)。编写一个装饰类模板类。在装饰类中只需要增强某个方法即可。
代码修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import java.sql.Connection; import java.sql.SQLException; import java.util.List;
public class MyConnectionWrapper extends ConnectionWrapper{
private Connection conn; private List<Connection> connList;
public MyConnectionWrapper(Connection conn, List<Connection> connList) { super(conn); this.conn = conn; this.connList = connList; }
@Override public void close() throws SQLException { connList.add(conn); } }
|
对另外两个文件的修改如下:
开源连接池的介绍和使用
Druid的概述
Druid是阿里旗下开源连接池产品,使用非常简单,可以与Spring框架进行快速整合。配置文件使用属性文件(.properties)。
C3P0的连接池概述
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等。配置文件可用属性文件(.properties),也可使用XML文件,一般用XML文件。
JDBCUtils的优化改写
将数据库连接的工具类改写为以数据库连接池的形式,这里以C3P0为例,也可使用Druid。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JDBCUtils2 { private static final ComboPooledDataSource dataSource = new ComboPooledDataSource();
public static Connection getConnection() throws SQLException{ return dataSource.getConnection(); }
public static DataSource getDataSource(){ return dataSource; }
public static void release(Statement stmt, Connection conn){ if(stmt != null){ try{ stmt.close(); }catch(SQLException e){ e.printStackTrace(); } stmt = null; } if(conn != null){ try{ conn.close(); }catch(SQLException e){ e.printStackTrace(); } conn = null; } } public static void release(ResultSet rs, Statement stmt, Connection conn){ if(rs != null){ try{ rs.close(); }catch(SQLException e){ e.printStackTrace(); } rs = null; } if(stmt != null){ try{ stmt.close(); }catch(SQLException e){ e.printStackTrace(); } stmt = null; } if(conn != null){ try{ conn.close(); }catch(SQLException e){ e.printStackTrace(); } conn = null; } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import org.junit.Test; import com.jdbc.utils.JDBCUtils; import com.jdbc.utils.JDBCUtils2;
public class C3P0Demo2 { @Test
public void demo1(){ Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = JDBCUtils2.getConnection(); String sql = "select * from user"; pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); while(rs.next()){ System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password")); } } catch (Exception e) { e.printStackTrace(); }finally { JDBCUtils.release(rs, pstmt, conn); } } }
|
其中C3P0的配置文件如下: