数据库学习笔记(五)—— BaseDao优化(1) + 数据连接池(举例c3p0)


JDBC优化

优化方法

  • 抽象方法
    代码中具有相同的代码,而且代码描述一个独立的业务
    新建方法,方法中描述相同代码,在需要的地方调用。

  • 抽象带参数的方法
    代码中具有大量相同的代码。(不同代码可以用变量表示)
    新建带参数的方法,使用参数控制变化的内容。

  • 抽象父类
    当多个类中具有相同的属性和方法,切满足is-a关系。
    新建父类,将相同的属性和方法拷贝到父类中,子类extends父类。

1. 变量优化 → 局部变量变为全局变量

在这里插入图片描述

2. 重复的方法,独立业务:

在这里插入图片描述
优化:
2
3
方法重载。在增删改时关两个,而查询时关三个,为了方便调用进行方法重载。(参数不同、方法名相同)

代码:

package dao;

import entity.Student;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class StudentDao {
    String driver ="com.mysql.jdbc.Driver";
    //不同数据库、相同数据库不同版本的driver不同
    String url="jdbc:mysql://localhost:3306/scott?useSSL=false";//连接what数据库
    String name="root";//登录用户,一般是hoot
    String pass="123456";//自己数据库的密码

    public Connection getConnection(){
        Connection connection = null;
        try {
            //注册驱动 (仅仅做一次)
            Class.forName(driver);//反射
            //建立连接(Connection)
            connection= DriverManager.getConnection (url,name,pass);//建立连接需要四个参数
        } catch (Exception e) {//直接父类
            e.printStackTrace();
        }
        return connection;//注意返回
    }


    //方法重载
    //DQL
    public void closeAll(ResultSet resultSet,Statement statement,Connection connection){//正序开、反序关
        //释放资源 (connection、statement、resultset)
        try {//对象不存在关不上,需要加try/catch
            //判断,若resultSet = null 控制真异常
            if (resultSet != null){
                resultSet.close();
            }
            if (statement != null){
                statement.close();
            }
            if (connection != null){
                connection.close();
            }
        }catch (SQLException throwables){
            throwables.printStackTrace();
        }
    }
    //DML
    public void closeAll(Statement statement,Connection connection){//正序开、反序关
        //释放资源 (connection、statement、resultset)
        try {//对象不存在关不上,需要加try/catch
            //判断,若*** = null 控制真异常
            if (statement != null){
                statement.close();
            }
            if (connection != null){
                connection.close();
            }
        }catch (SQLException throwables){
            throwables.printStackTrace();
        }
    }

 public int insert(){//插入方法
        Connection connection = null;
        PreparedStatement statement = null;
        int ret =-1;
        try {
            connection = getConnection();//接下来需要用到,故必须接收返回连接
            //创建运行SQL的语句(Statement)
            statement=connection.prepareStatement("insert into student (student_name,student_no,sex) values(?,?,?)");
            statement.setObject(1 ,"lily");
            statement.setObject(2 ,"202205");
            statement.setObject(3 ,"女");
            //运行语句
            ret = statement.executeUpdate();
            System.out.println(ret);
            //处理运行结果(ResultSet)——只有查询时有,进行增删改操作时没有这一步
        }catch (SQLException e) {
            e.printStackTrace();
        }catch (Exception e) { //多重catch,最后要加一个父类
            e.printStackTrace();
        }finally {
            closeAll(statement,connection);
        }
        return ret;
    }
    public List<Student> queryAllStudent(){//查询方法

        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet rs =null;
        List<Student> list = new ArrayList<>();//list加泛型

        try {
            //创建运行SQL的语句(Statement)
            statement=connection.prepareStatement("select * from student");

            //运行语句
            rs = statement.executeQuery();

            //处理运行结果(ResultSet)——只有查询时有,进行增删改操作时没有这一步
            while (rs.next()){//不知道记录条数,不知循环次数——while。结果集的指针可以向下移动一步时
                Student student = new Student();//实例化对象
                //把rs中的每一个值都放入Student中
                student.setId(rs.getInt(1));
                student.setStudent_name(rs.getString("student_name"));

                list.add(student);
            }

        }catch (SQLException e) {
            e.printStackTrace();
        }catch (Exception e) { //多重catch,最后要加一个父类
            e.printStackTrace();
        }finally {
           closeAll(rs,statement,connection);
        }
        return list;
    }
}

3. 抽象带参方法(DML)优化:

增删改除了创建SQL语句以外,其余都一致 。sql(参数)以及传值(数组)。数组内 存的数据类型不同,int、varchar、data……,故数组是object类型
在这里插入图片描述
在这里插入图片描述

 public int excuteinsert(String sql,Object[] objects){//插入方法
        Connection connection = null;
        PreparedStatement statement = null;
        int ret =-1;
        try {
            connection = getConnection();//接下来需要用到,故必须接收返回连接
            //创建运行SQL的语句(Statement)
            statement=connection.prepareStatement(sql);
            for (int i=0;i< objects.length;i++){
                statement.setObject(i+1,objects[i]);
            }
            
            //运行语句
            ret = statement.executeUpdate();
            System.out.println(ret);
            //处理运行结果(ResultSet)——只有查询时有,进行增删改操作时没有这一步
        }catch (SQLException e) {
            e.printStackTrace();
        }catch (Exception e) { //多重catch,最后要加一个父类
            e.printStackTrace();
        }finally {
            closeAll(statement,connection);
        }
        return ret;
    }

Text

import dao.StudentDao;

public class Text {
    public static void main(String[] args) {
        StudentDao studentDao = new StudentDao();
        studentDao.queryAllStudent().forEach(System.out::println);

        studentDao.excuteinsert("insert into student (student_name,student_no,sex) values(?,?,?)",new Object[]{"baby",202207,"女"});
        studentDao.excuteUpdate("update student set address = ? where id = ?",new Object[]{"北京市",4});

    }
}

show

在这里插入图片描述
在这里插入图片描述

4.可变长度参数——本质:数组

在这里插入图片描述
Text

studentDao.excuteinsert("insert into student (student_name,student_no,sex) values(?,?,?)", "bob",202208,"男");

在这里插入图片描述

5.(DQL)封装优化

反射、泛型类

 public List<T> executeQuery(String sql, Object[] param) {
        Connection conn = null;
        PreparedStatement stat = null;
        ResultSet rs = null;
        List<T> list = new ArrayList<T>();
        try {
            conn = createConnction();
            stat = conn.prepareStatement(sql);
            if (param != null) {
                for (int i = 0; i < param.length; i++) {
                    stat.setObject(i + 1, param[i]);
                }
            }
            rs = stat.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            int columuCount = rsmd.getColumnCount();
            while (rs.next()) {
                T t = (T) clazz.newInstance();
                for (int i = 0; i < columuCount; i++) {
                    Field f = clazz.getDeclaredField(rsmd.getColumnName(i + 1));
                    f.setAccessible(true);
                    f.set(t, rs.getObject(i + 1));
                }
                list.add(t);
            }
            printSql(sql, param);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeAll(conn, stat, null);
        }
        return list;
    }

5. 抽象父类

StudentDao对student表进行操作 / 此时对class表进行操作,entity中新建Clazz.java,Dao中新建clazzDao。
StudentDao与clazzDao……都存在相同的部分——抽象父类——多个类具有相同属性和方法、满足is-a关系
继承

📕 BaseDao优化JDBC 📕 👴

1>父类是抽象父类不可以实例化——abstract
在这里插入图片描述

1>BaseDao放入重复部分(全局变量+方法增删改),没有查询部分代码

package dao;

import java.sql.*;

public abstract class BaseDao {

    String driver ="com.mysql.jdbc.Driver";
    //不同数据库、相同数据库不同版本的driver不同
    String url="jdbc:mysql://localhost:3306/scott?useSSL=false";//连接what数据库
    String name="root";//登录用户,一般是hoot
    String pass="123456";//自己数据库的密码

    public Connection getConnection(){
        Connection connection = null;
        try {
            //注册驱动 (仅仅做一次)
            Class.forName(driver);//反射
            //建立连接(Connection)
            connection= DriverManager.getConnection (url,name,pass);//建立连接需要四个参数
        } catch (Exception e) {//直接父类
            e.printStackTrace();
        }
        return connection;//注意返回
    }


    //方法重载
    //DQL
    public void closeAll(ResultSet resultSet, Statement statement, Connection connection){//正序开、反序关
        //释放资源 (connection、statement、resultset)
        try {//对象不存在关不上,需要加try/catch
            //判断,若resultSet = null 控制真异常
            if (resultSet != null){
                resultSet.close();
            }
            if (statement != null){
                statement.close();
            }
            if (connection != null){
                connection.close();
            }
        }catch (SQLException throwables){
            throwables.printStackTrace();
        }
    }
    //DML
    public void closeAll(Statement statement,Connection connection){//正序开、反序关
        //释放资源 (connection、statement、resultset)
        try {//对象不存在关不上,需要加try/catch
            //判断,若*** = null 控制真异常
            if (statement != null){
                statement.close();
            }
            if (connection != null){
                connection.close();
            }
        }catch (SQLException throwables){
            throwables.printStackTrace();
        }
    }

    public int excuteinsert(String sql,Object... objects){//插入方法
        Connection connection = null;
        PreparedStatement statement = null;
        int ret =-1;
        try {
            connection = getConnection();//接下来需要用到,故必须接收返回连接
            //创建运行SQL的语句(Statement)
            statement=connection.prepareStatement(sql);
            for (int i=0;i< objects.length;i++){
                statement.setObject(i+1,objects[i]);
            }
            //运行语句
            ret = statement.executeUpdate();
            System.out.println(ret);
            //处理运行结果(ResultSet)——只有查询时有,进行增删改操作时没有这一步
        }catch (SQLException e) {
            e.printStackTrace();
        }catch (Exception e) { //多重catch,最后要加一个父类
            e.printStackTrace();
        }finally {
            closeAll(statement,connection);
        }
        return ret;
    }

    public int excuteUpdate(String sql,Object[] objects){ //修改方法
        Connection connection = null;
        PreparedStatement statement = null;
        int ret =-1;
        try {
            connection = getConnection();//接下来需要用到,故必须接收返回连接
            //创建运行SQL的语句(Statement)
            statement=connection.prepareStatement(sql);
            for (int i=0;i<objects.length;i++){     
            statement.setObject(i+1,objects[i]);
            }
            //运行语句
            ret = statement.executeUpdate();
            System.out.println(ret);
            //处理运行结果(ResultSet)——只有查询时有,进行增删改操作时没有这一步
        }catch (SQLException e) {
            e.printStackTrace();
        }catch (Exception e) { //多重catch,最后要加一个父类
            e.printStackTrace();
        }finally {
            closeAll(statement,connection);
        }
        return ret;
    }
}
package dao;

import entity.Student;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class StudentDao extends BaseDao{

    public List<Student> queryAllStudent(){//查询方法

        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet rs =null;
        List<Student> list = new ArrayList<>();//list加泛型

        try {
            connection = getConnection();//接下来需要用到,故必须接收返回连接
            //创建运行SQL的语句(Statement)
            statement=connection.prepareStatement("select * from student");
            //运行语句
            rs = statement.executeQuery();
            //处理运行结果(ResultSet)——只有查询时有,进行增删改操作时没有这一步
            while (rs.next()){//不知道记录条数,不知循环次数——while。结果集的指针可以向下移动一步时
                Student student = new Student();//实例化对象
                //把rs中的每一个值都放入Student中
                student.setId(rs.getInt(1));
                student.setStudent_name(rs.getString("student_name"));

                list.add(student);
            }
        }catch (SQLException e) {
            e.printStackTrace();
        }catch (Exception e) { //多重catch,最后要加一个父类
            e.printStackTrace();
        }finally {
           closeAll(rs,statement,connection);
        }
        return list;
    }
}

package dao;

public class ClazzDao  extends BaseDao{


}
public class Text {
    public static void main(String[] args) {
        StudentDao studentDao = new StudentDao();
       //studentDao.queryAllStudent().forEach(System.out::println);
       //studentDao.excuteinsert("insert into student (student_name,student_no,sex) values(?,?,?)", "bob",202208,"男");
       // studentDao.excuteUpdate("update student set address = ? where id = ?",new Object[]{"北京市",4});

        ClazzDao clazzDao = new ClazzDao();
        clazzDao.excuteinsert("insert into class(class_name) values (?)","班级三");



    }
}

在这里插入图片描述

2> BaseDao 引入泛型(此时查询操作也可以写入,其余表全都继承)


数据连接池原理(线程池)

在这里插入图片描述
大量资源浪费在数据库连接和释放(connection和close)。使用数据连接池——实现性能优化。

常用数据连接池

dbcp:

是一个依赖Jakarta commons-pool对象池机制的数据库连接池,Tomcat的数据源使用的就是DBCP。目前 DBCP 有两个版本分别是 1.3 和 1.4。1.3 版本对应的是 JDK 1.4-1.5 和 JDBC 3,而1.4 版本对应 JDK 1.6 和 JDBC 4。因此在选择版本的时候要看看你用的是什么 JDK 版本了,功能上倒是没有什么区别。

c3p0:

是一个开放源代码的JDBC连接池,它在lib目录中与Hibernate一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSources 对象。

Druid:多

Apache Druid 是一个分布式内存实时分析系统,用于解决如何在大规模数据集下进行快速的、交互式的查询和分析的问题。Apache Druid 由 阿里公司开发,在2019年春季被捐献给 Apache 软件基金会。

数据库连接池参考

使用方法

c3p0

c3p0

步骤
  1. 引入jar ——右键—Add as Library
    在这里插入图片描述

  2. 引入mchange-commons-java…jar——右键—Add as Library

  3. 引入 配置文件c3p0-conflg .xml 到src根目录
    在这里插入图片描述
    在这里插入图片描述
    修改配置
    在这里插入图片描述
    这里jdbcUrl存在问题,需要查询

  4. 修改代码
    在这里插入图片描述
    【上】使用static且放在getConnection()方法外,只执行一次,才能发挥出数据连接池的作用。

代码
  • 在pom中引用c3p0支持
<dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.2</version>
</dependency>
  • 在resource中创建c3p0配置文件c3p0-config.xml
<c3p0-config>
    <!-- 默认数据源 -->
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://host:port/db</property>
        <property name="user">username</property>
        <property name="password">password</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property>
        <property name="acquireIncrement">5</property>
    </default-config>

    <!-- 定义带名称的数据源 -->
    <named-config name="myDataSource">
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/demo</property>
        <property name="user">root</property>
        <property name="password">123</property>
        <property name="minPoolSize">2</property>
        <property name="maxPoolSize">10</property>
        <property name="acquireIncrement">2</property>
    </named-config>
</c3p0-config>
  • 创建DBPool工具类,使用单例模式。(可以和BaseDao放在一个源文件中)
public class DBPool {
    //1、声明本身类型的对象。static。
    private static DBPool db = null;
    private DataSource ds = new ComboPooledDataSource("myDataSource");//不带参数使用默认数据源

    //2、私有化构造方法
    private DBPool() {
    }

    //3、定义方法用于获取本身对象
    public static DBPool getInstance() {
        if (null == db) {
            db = new DBPool();
        }
        return db;
    }

    public Connection getConn() {
        try {
            return ds.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
}
  • 修改BaseDao文件,使用连接池获得连接。
import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;


public class BaseDao<T> {
    Class<T> clazz;

    //反射获得clazz
    public BaseDao() {
        clazz = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    //关闭所有链接
    public void closeAll(Connection conn, PreparedStatement pstmt, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (pstmt != null) {
            try {
                pstmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    //执行DML语句
    public int executeUpdate(String sql, Object[] param) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        int num = 0;

        try {
            conn = DBPool.getInstance().getConn();//从DBPool获得连接。
            pstmt = conn.prepareStatement(sql);
            if (param != null) {
                for (int i = 0; i < param.length; i++) {
                    pstmt.setObject(i + 1, param[i]);
                }
            }
            num = pstmt.executeUpdate();
            printSql(sql, param);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            closeAll(conn, pstmt, null);
        }
        return num;
    }

    //执行预编译DQL语句
    public List<T> executeQuery(String sql, Object[] param) {
        Connection conn = null;
        PreparedStatement stat = null;
        ResultSet rs = null;
        List<T> list = new ArrayList<T>();
        try {
            conn = DBPool.getInstance().getConn();
            stat = conn.prepareStatement(sql);
            if (param != null) {
                for (int i = 0; i < param.length; i++) {
                    stat.setObject(i + 1, param[i]);
                }
            }
            rs = stat.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            int columuCount = rsmd.getColumnCount();
            while (rs.next()) {
                T t = (T) clazz.newInstance();
                for (int i = 0; i < columuCount; i++) {
                    Field f = clazz.getDeclaredField(rsmd.getColumnName(i + 1));
                    f.setAccessible(true);
                    f.set(t, rs.getObject(i + 1));
                }
                list.add(t);
            }
            printSql(sql, param);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeAll(conn, stat, null);
        }
        return list;
    }

    //执行无条件sql语句(分页使用)
    public List<T> executeQuery(String sql) {
        Connection conn = null;
        PreparedStatement stat = null;
        ResultSet rs = null;
        List<T> list = new ArrayList<T>();
        try {
            conn = DBPool.getInstance().getConn();
            stat = conn.prepareStatement(sql);
            rs = stat.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            int columuCount = rsmd.getColumnCount();
            while (rs.next()) {
                T t = (T) clazz.newInstance();
                for (int i = 0; i < columuCount; i++) {
                    Field f = clazz.getDeclaredField(rsmd.getColumnName(i + 1));
                    f.setAccessible(true);
                    f.set(t, rs.getObject(i + 1));
                }
                list.add(t);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeAll(conn, stat, null);
        }
        return list;
    }

    //获得所有记录条数(分页使用)
    public int executeQueryCount(String sql) {
        Connection conn = null;
        PreparedStatement stat = null;
        ResultSet rs = null;
        try {
            conn = DBPool.getInstance().getConn();
            stat = conn.prepareStatement(sql);
            rs = stat.executeQuery();
            if (rs.next())
                return rs.getInt(1);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeAll(conn, stat, null);
        }
        return 0;
    }

    // 输出预编译的sql语句的具体内容(便于调试)
    private void printSql(String sql, Object[] params) {
        StringBuffer sb = new StringBuffer(sql);
        int fromIndex = 0;
        if (params != null) {
            for (int i = 0; i < params.length; i++) {
                int index = sb.indexOf("?", fromIndex);
                if (index == -1) {
                    sb.append(" ---> error: value too many   ");
                    break;
                }
                if (params[i] instanceof String) {
                    sb.replace(index, index + 1, "'" + this.valueOf(params[i]) + "'");
                } else if (params[i] instanceof Number) {
                    sb.replace(index, index + 1, this.valueOf(params[i]));
                } else if (params[i] instanceof Character) {
                    sb.replace(index, index + 1, "'" + this.valueOf(params[i]) + "'");
                } else if (params[i] instanceof Boolean) {
                    sb.replace(index, index + 1, "'" + this.valueOf(params[i]) + "'");
                } else if (params[i] instanceof Object[]) {
                    sb.replace(index, index + 1, "'" + this.valueOf(params[i]) + "'");
                } else if (params[i] instanceof java.sql.Date) {
                    sb.replace(index, index + 1, " date '" + this.valueOf(params[i]) + "'");
                } else if (params[i] instanceof java.util.Date) {
                    sb.replace(index, index + 1, "'java.util.Date'");
                }
                fromIndex = index + 1;
            }
        }
        System.out.println(sb.toString());
    }

    public String valueOf(Object obj) {
        return (obj == null) ? "" : obj.toString();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值