JDBC存在的问题

代码的冗余:在对数据库进行增删改查时,每个操作的JDBC流程和SQL执行代码的流程都一样,造成代码的冗余,所以我们可以把冗余的部分封装起来,封装之后,我们就不用再去写JDBC流程,只需要些SQL语句---这一部分的封装下一篇文章描述

性能问题:每一次对数据库的操作都要建立连接,操作完之后又要释放连接,如果数据库访问次数不多时性能还可以,但当我们的程序有很多人使用时,对数据库的操作次数也会越来越多,每一次操作都要建立和关闭连接,势必会降低性能,本篇文章主要解决这部分的问题

如何解决性能问题

我们先用一个例子来描述一下这个JDBC性能问题。

比如说,当两个地方本来互相不通,分别是A和B两个地方。这时我们就需要在A和B之间修一条路能让他们连通,有人在这条路上通行的时候就处于连接状态,但是当这条路可能有段时间没人走了我们就把它炸掉了。但是每当有人需要从A去到B时,又需要再修一条路,而每一次修一条路的时间都需要非常久。所以我们不能一不用这条路就把它炸掉,这样非常浪费时间和资金。那我们该怎么解决呢?我们在A和B两地之间多修几条路,在每条路的路口设置关卡,当有人在其中一条路上通行时,那么这个关卡就不允许其他人在这条路上通行,当路上没人通行时那么关卡允许其他人通行。(可能这举的例子和实际生活不是特别恰当,但也希望大家能够理解,实在想不到一个更为贴切的例子)

解决JDBC性能问题也是这个道理,一开始我们就创建几个连接通道,用完之后不关闭,而是用一个标志位来表示当前通道是否可用,建立的这几条通道放在统一的一个地方进行管理,看起来就像个池子一样,所以就叫JDBC连接池

封装JDBC的步骤

1、为了更好的管理项目,我们把连接数据库用到的驱动类、url地址、用户名和密码都放到一个properties文件里,之后改起来也方便,一处改动全部都跟着改动。需要一个类来帮我们读取配置文件的信息

配置信息如下(Configuration.properties)

driver=com.mysql.cj.jdbc.Driver

url=jdbc:mysql://localhost:3306/bank?serverTimezone=CST

user=root

password=123456

minConnectCount=5

waitTime=5

ConfigReader类

package util;

import java.io.IOException;

import java.io.InputStream;

import java.util.Enumeration;

import java.util.HashMap;

import java.util.Map;

import java.util.Properties;

public class ConfigReader {

private static Properties properties;

//用Map集合存放properties文件下的配置信息

private static Map configMap;

//配置文件只加载一次

static {

properties = new Properties();

configMap = new HashMap<>();

InputStream inputStream = null;

try {

inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("configuration.properties");

properties.load(inputStream);

Enumeration en = properties.propertyNames();

while (en.hasMoreElements()){

String key = (String) en.nextElement();

String value = properties.getProperty(key);

configMap.put(key, value);

}

} catch (IOException e) {

e.printStackTrace();

}finally {

if (inputStream != null){

try {

inputStream.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

//获取配置文件里面的value值

public static String getPropertyValue(String key){

return configMap.get(key);

}

}

2、在连接JDBC的时候我们用DriverManager.getConnection()方法获取连接,返回了Connection对象,成功获取后也表明和数据库连接成功,当我们不需要用的时候调用close()方法关闭连接。为了实现用完之后不关闭连接,我们需要自己封装一个类,这个类下有一个Connection属性,还有一个标志位,用来判断该连接可用还是不可用。为了能够让自己封装的类和Connection类的使用起来是一样的,我们自己创建一个AdapterConnection抽象类,这个类实现了Connection接口,我们自己封装的Connection类继承了这个抽象类,并重写了其中的三个方法,分别用来创建状态参数以及关闭连接。(这部分的设计思想体现出缺省适配器模式)

AdapterConnection类

package pool;

import java.sql.*;

import java.util.Map;

import java.util.Properties;

import java.util.concurrent.Executor;

public abstract class AdapterConnection implements Connection {

//这里将这三个写为抽象方法,是为了当子类继承这个抽象类的时候提示子类必须重写这个三个方法

@Override

public abstract Statement createStatement() throws SQLException;

@Override

public abstract PreparedStatement prepareStatement(String sql) throws SQLException ;

@Override

public abstract void close() throws SQLException;

@Override

public CallableStatement prepareCall(String sql) throws SQLException {

return null;

}

@Override

public String nativeSQL(String sql) throws SQLException {

return null;

}

@Override

public void setAutoCommit(boolean autoCommit) throws SQLException {

}

@Override

public boolean getAutoCommit() throws SQLException {

return false;

}

@Override

public void commit() throws SQLException {

}

@Override

public void rollback() throws SQLException {

}

@Override

public boolean isClosed() throws SQLException {

return false;

}

@Override

public DatabaseMetaData getMetaData() throws SQLException {

return null;

}

@Override

public void setReadOnly(boolean readOnly) throws SQLException {

}

@Override

public boolean isReadOnly() throws SQLException {

return false;

}

@Override

public void setCatalog(String catalog) throws SQLException {

}

@Override

public String getCatalog() throws SQLException {

return null;

}

@Override

public void setTransactionIsolation(int level) throws SQLException {

}

@Override

public int getTransactionIsolation() throws SQLException {

return 0;

}

@Override

public SQLWarning getWarnings() throws SQLException {

return null;

}

@Override

public void clearWarnings() throws SQLException {

}

@Override

public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {

return null;

}

@Override

public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {

return null;

}

@Override

public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {

return null;

}

@Override

public Map> getTypeMap() throws SQLException {

return null;

}

@Override

public void setTypeMap(Map> map) throws SQLException {

}

@Override

public void setHoldability(int holdability) throws SQLException {

}

@Override

public int getHoldability() throws SQLException {

return 0;

}

@Override

public Savepoint setSavepoint() throws SQLException {

return null;

}

@Override

public Savepoint setSavepoint(String name) throws SQLException {

return null;

}

@Override

public void rollback(Savepoint savepoint) throws SQLException {

}

@Override

public void releaseSavepoint(Savepoint savepoint) throws SQLException {

}

@Override

public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {

return null;

}

@Override

public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {

return null;

}

@Override

public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {

return null;

}

@Override

public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {

return null;

}

@Override

public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {

return null;

}

@Override

public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {

return null;

}

@Override

public Clob createClob() throws SQLException {

return null;

}

@Override

public Blob createBlob() throws SQLException {

return null;

}

@Override

public NClob createNClob() throws SQLException {

return null;

}

@Override

public SQLXML createSQLXML() throws SQLException {

return null;

}

@Override

public boolean isValid(int timeout) throws SQLException {

return false;

}

@Override

public void setClientInfo(String name, String value) throws SQLClientInfoException {

}

@Override

public void setClientInfo(Properties properties) throws SQLClientInfoException {

}

@Override

public String getClientInfo(String name) throws SQLException {

return null;

}

@Override

public Properties getClientInfo() throws SQLException {

return null;

}

@Override

public Array createArrayOf(String typeName, Object[] elements) throws SQLException {

return null;

}

@Override

public Struct createStruct(String typeName, Object[] attributes) throws SQLException {

return null;

}

@Override

public void setSchema(String schema) throws SQLException {

}

@Override

public String getSchema() throws SQLException {

return null;

}

@Override

public void abort(Executor executor) throws SQLException {

}

@Override

public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {

}

@Override

public int getNetworkTimeout() throws SQLException {

return 0;

}

@Override

public T unwrap(Class iface) throws SQLException {

return null;

}

@Override

public boolean isWrapperFor(Class> iface) throws SQLException {

return false;

}

}

MyConnection类

package pool;

import util.ConfigReader;

import java.sql.*;

public class MyConnection extends AdapterConnection{

private Connection conn;

//标志位,true表示被占用,false表示该通道可用

private boolean used = false;

private static String driver;

private static String url;

private static String user;

private static String password ;

//静态块,让加载类的步骤只执行一次,并初始化四个属性

static {

try {

driver = ConfigReader.getPropertyValue("driver");

url = ConfigReader.getPropertyValue("url");

user = ConfigReader.getPropertyValue("user");

password = ConfigReader.getPropertyValue("password");

Class.forName(driver);

}catch (ClassNotFoundException e){

e.printStackTrace();

}

}

//用来初始化连接通道,每一次被创建时都进行初始化

{

try {

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

}catch (SQLException e){

e.printStackTrace();

}

}

//获取连接通道

public Connection getConn() {

return conn;

}

//判断该连接通道是否可用

public boolean isUsed() {

return used;

}

//设置标志位

public void setUsed(boolean used) {

this.used = used;

}

@Override

public Statement createStatement() throws SQLException {

return this.conn.createStatement();

}

//重写了继承自AdapterConnection类的方法

//该方法是为了获取状态参数,本质上还是调用了PreparedStatement

@Override

public PreparedStatement prepareStatement(String sql) throws SQLException {

PreparedStatement pstate = this.conn.prepareStatement(sql);

return pstate;

}

//重写了继承自AdapterConnection类的方法

//该方法的目的是为了将连接通道设置为可用,看起来就像关闭流一样

@Override

public void close() throws SQLException {

this.used = false;

}

}

3、我们需要一个连接池对象来帮我们管理连接对象,我们需要把连接对象放到一个List集合中,当我们需要的时候就从集合里取。连接对象的个数我们也放置在properties文件里,便于管理。由于连接对象有限,当有多个用户同时访问时,可能有的用户拿不到连接对象,这里用了一个等待机制,当用户拿不到连接对象时,就让它等一会,如果超出等待时间还拿不到,就抛出一个异常通知用户。

ConnectionPool类

package pool;

import util.ConfigReader;

import javax.swing.*;

import java.io.InputStream;

import java.sql.Connection;

import java.util.ArrayList;

import java.util.List;

public class ConnectionPool {

//将ConnectionPool设计成单例模式

private ConnectionPool(){}

private static volatile ConnectionPool connectionPool;

public static ConnectionPool getInstance(){

if (connectionPool == null){

synchronized (ConnectionPool.class){

if (connectionPool == null){

connectionPool = new ConnectionPool();

}

}

}

return connectionPool;

}

//获取最小连接个数以及等待时间

private int minConnectCount = Integer.parseInt(ConfigReader.getPropertyValue("minConnectCount"));

private int waitTime = Integer.parseInt(ConfigReader.getPropertyValue("waitTime"));

//属性---List集合,用来存储连接对象

private List pool = new ArrayList<>();

//往pool集合里面存放连接对象

{

for (int i = 1; i <= minConnectCount; i ++){

pool.add(new MyConnection());

}

}

//方法,获取连接对象

private Connection getMC(){

Connection result = null;

//遍历连接池中的对象

for (Connection conn : pool){

MyConnection mc = (MyConnection) conn;

if (!mc.isUsed()){//表示连接是可使用的

synchronized (ConnectionPool.class){

if (!mc.isUsed()){

mc.setUsed(true);

result = mc;

}

}

break;

}

}

return result;

}

//该方法是为了获取连接对象,并增加了等待机制

public Connection getConnection(){

Connection result = this.getMC();

int count = 0;//记录循环的次数

while (result == null && count < waitTime*10){

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

result = this.getMC();

count++;

}

if (result == null){

throw new SystemBusyException("当前系统繁忙,请稍后再试");

}

return result;

}

}

自定义异常类SystemBusyException

package pool;

public class SystemBusyException extends RuntimeException {

public SystemBusyException(){}

public SystemBusyException(String msg){

super(msg);

}

}

这样整个JDBC连接池就封装好了,整体的功能也比较简单,代码是经过测试的了,所以运行起来应该是没有什么问题,如果有什么问题还望指正。

jdbc封装mysql_用Java手动封装JDBC连接池(一)相关推荐

  1. java中常用的连接池_java数据库连接池

    编写标准的数据源(规范) Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口.这样应用程序可以方便的切换不同厂商的连接池! 常见的 ...

  2. java操作mongodb(连接池)(转)

    原文链接: java操作mongodb(连接池) Mongo的实例其实就是一个数据库连接池,这个连接池里默认有10个链接.我们没有必要重新实现这个链接池,但是我们可以更改这个连接池的配置.因为Mong ...

  3. Java Web(十) JDBC的增删改查,C3P0等连接池,dbutils框架的使用

    前面做了一个非常垃圾的小demo,真的无法直面它,菜的抠脚啊,真的菜,好好努力把.菜鸡. --WZY 一.JDBC是什么? Java Data Base Connectivity,java数据库连接, ...

  4. 怎么把java源代码封装,如何把JAVA程序封装成EXE文件

    如何把JAVA程序封装成EXE文件 可以把普通的Java程序做成真正的exe,也就是单一个exe就可以在没有安装JVM的机器上运行.这样的工具常见的有JET和gcj.前者是收费的,而且做出来的exe还 ...

  5. 小汤学编程之JDBC(二)——dbutils框架和DataSource连接池

    一.dbutils框架 1.介绍     2.新增/删除/修改     3.各种查询     4.扩展:Bean中属性名与数据表列名的映射 二.DataSource连接池 1.获取DataSource ...

  6. java day55【 Mybatis 连接池与事务深入 、 Mybatis 的动态 SQL 语句、 Mybatis 多表查询之一对多 、 Mybatis 多表查询之多对多】...

    第1章 Mybatis 连接池与事务深入 1.1 Mybatis 的连接池技术 1.1.1 Mybatis 连接池的分类 1.1.2 Mybatis 中数据源的配置 1.1.3 Mybatis 中 D ...

  7. java学习笔记—标准连接池的实现(27)

    javax.sql.DataSource. Java.sql.* DataSource 接口由驱动程序供应商实现.共有三种类型的实现: 基本实现 - 生成标准的 Connection 对象 – 一个D ...

  8. java中的DBCP连接池

    实际开发中"获得连接"或"释放资源"是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采用连接池技术,来共享连接Connection.这样我们就不 ...

  9. java redis集群连接池_(08)redis之使用java客户端、spring连接redis、redis集群示例...

    一.java代码连接 1.新建工程,并引入以下包: jedis-2.7.0.jar.commons-pool2-2.3.jar.junit-4.10.jar 2.单实例连接 /*** 单实例连接*/@ ...

最新文章

  1. python parser count_8 个 Python 实用脚本,早掌握早下班!
  2. Java当中捕获异常
  3. python蟒蛇代码_011 实例2-Python蟒蛇绘制
  4. 1636: Pascal山脉
  5. 5G 时代,将边缘计算进行到底!
  6. 四元数运动学笔记(1)旋转的表示
  7. 大纲2.1 计算机网络
  8. Java设计模式笔记--------工厂模式------抽象工厂模式
  9. 世界 图书 学科 分类
  10. doip 源码_DoIP技术(二)
  11. Linux下修改键盘映射
  12. 逻辑回归算法梳理(从理论到示例)
  13. MPLAB PICKIT3、MPLAB SIM调试
  14. uso oracle,Oracle Database 12c: In-Memory (Parte I)
  15. Orinda无线ap
  16. vitualbox 挂载win7 共享文件夹
  17. 【HUE】问题汇总(持续更新)
  18. 安卓开发之视频播放器
  19. The Accidental HFT Firm
  20. SuMa++:Efficient LiDAR-based Semantic SLAM

热门文章

  1. 聊聊事件驱动的架构模式
  2. 停车30分钟内不收费,程序员远程操控挪车,实现自动免费停车...
  3. 这篇关于Netty底层的大科普,内部分享时被leader表扬了
  4. Spring Security 实战:Spring Boot 下的自动配置
  5. 在Docker中运行Spring Boot的高级功能测试
  6. mysql combat_LICENSE · 爱是与世界平行/mysqlActualCombat - Gitee.com
  7. Python 自动给人脸 戴口罩
  8. onnx.onnx_cpp2py_export.checker.ValidationError
  9. ‘utf-8‘ codec can‘t encode character ‘\udcc0‘ in position 35
  10. pytorch 维度练习