JDBC学习笔记

JDBC学习笔记…

JDBC概述

基本介绍:

JDBC为访问不同的数据库提供了统一的接口,为使用者屏蔽细节问题;通过使用JDBC,可以连接任意提供了JDBC驱动程序的数据库系统,从而完成对数据库的操作。

获取数据库连接(mysql8.0)

//通过配置文件灵活获取信息(用户名、密码、驱动、连接)
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
Class.forName(driver);//通过反射完成自动注册
Connection connection = DriverManager.getConnection(url, user, password);
Statement statement = connection.createStatement();
String sql1 = "insert into news values(1,'tom','男')";
int row1 = statement.executeUpdate(sql1);//执行sql语句(DML语句)
statement.close();//关闭连接资源
connection.close();

ResultSet结果集

基本介绍:

  1. 表示数据库结果集的数据表,通常通过执行DDL语句生成
  2. ResultSet对象保持一个光标指向当前数据行。起始位置位于第一行数据之前
  3. next方法将光标移动到下一行,若返回 false 代表对象中没有更多行。previous方法将光标移动到上一行。
  4. getXxx方法可以根据列的索引或列名返回对应列的值;getObject方法同理,但返回Object类型

Statement

基本介绍:

  1. Statement对象指执行静态SQL语句并返回其生成的结果的对象
  2. 连接建立后,访问数据库有以下三种方式:
    1. Statement:存在SQL注入问题
    2. PreparedStatement:预处理
    3. CallableStatement:存储过程
  3. SQL注入是Statement对象执行SQL语句存在的问题,即利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令,进而使数据库受到攻击和破坏。
  4. 使用PreparedStatement可以防范SQL注入

PreparedStatement

基本介绍:

  1. 执行的SQL语句中的参数用问号表示,通过调用setXxx方法来设置这些参数,问号有对应的索引(从1开始)
  2. 调用executeQuery() 返回ResultSet对象
  3. 调用executeUpdate() 执行增删改
  4. 优点:不再使用 +号拼接sql语句,减少语法错误;有效解决sql注入问题;减少编译次数,提高效率(预处理)

封装JDBCUtils

基本介绍:

通常我们需要频繁的获取连接和关闭连接,我们可以将这类操作封装起来,用到该类操作使用工具类即可

//工具类,完成对mysql的连接和关闭
public class JdbcUtils {
    private static String url;
    private static String user;
    private static String password;
    private static String driver;
    //使用静态代码块进行初始化
    static {
        try {
            Properties properties = new Properties();
            properties.load(new FileInputStream("src\\mysql.properties"));

            user = properties.getProperty("user");
            password = properties.getProperty("password");
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    public static void close(ResultSet resultSet, Statement statement, Connection connection) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

事务

基本介绍:

  1. JDBC程序中,Connection对象创建时,默认情况下会自动提交事务,每成功执行一个sql语句,就会向数据库自动提交,而不能使用回滚
  2. 使用Connection中的setAutoCommit方法可以取消自动提交提交事务(设为false),即开启事务
  3. 在所有sql语句成功执行后,使用commit方法提交,使用rollback方法回滚

批处理

基本介绍:

  1. 有时需要我们进行大量插入或更新记录的操作,我们可以使用java的批量更新机制,将多条语句一次性提交给数据库进行批量处理,这样做效率更高
  2. 常用方法:
    1. addBatch():添加需要批量处理的sql语句或参数;
    2. executeBatch():执行批量处理语句;
    3. clearBatch():清空批处理包的语句
  3. 使用批处理时,url中需要添加参数:?rewriteBatchedStatements=true
  4. 批处理常与PreparedStatement搭配使用,减少编译次数的同时减少运行次数,大大提高效率

数据库连接池

传统JDBC连接数据库的弊端:

  1. 使用DriverManager获取连接,每次向数据库建立连接时,都需要将Connection加载到内存中,再验证IP地址、用户名和密码。当频繁进行数据库连接操作时,会大量占用系统资源,容易造成服务器崩溃
  2. 每次数据库连接使用结束后需要关闭连接,若程序出现异常,连接未能正常关闭时,会导致数据库内存泄漏,最终导致重启数据库
  3. 无法控制连接数量

数据连接池可以解决以上问题

  1. 提供连接池维护与mysql的连接,连接池控制初始连接数量、最小连接数量和最大连接数量,可以根据需要对连接数量及时扩容
  2. 当程序需要建立连接时,从连接池中获取链接,使用完毕释放连接即可(连接可被复用);若连接均被占用,则加入等待队列
  3. 连接池种类:C3P0(稳定性高)、DBCP、Proxool、BoneCP、Druid德鲁伊

德鲁伊工具类

集多种连接池优点于一身的连接池,速度快

public class DruidUtils {
    private static DataSource ds;
    //利用静态代码块对ds进行初始化
    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("src\\druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e){
            e.printStackTrace();
        }
    }
    //获取连接
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
    //释放连接
    public static void close(ResultSet resultSet, Statement statement,Connection connection){
        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}
//配置文件中的参数设置
#key=value
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
#url=jdbc:mysql://localhost:3306/girls
username=root
password=1234
#initial connection Size
initialSize=10
#min idle connecton size
minIdle=5
#max active connection size
maxActive=50
#max wait time (5000 mil seconds)
maxWait=5000

Apache-DBUtils

使用ResultSet结果集存在的问题:

  1. 关闭Connection后,ResultSet结果集无法再使用
  2. ResultSet结果集不利于数据的管理

解决办法:

  1. 创建JavaBean对象保存每一条查询记录中字段对应的值
  2. 将所有的记录保存在ArrayList中,限制保存类型为对应的JavaBean类
  3. 这样对结果集进行了封装,并可以复用

========》DBUtils实现了以上的功能

DButils基本介绍:

  1. 开源的JDBC工具类库,可以极大简化jdbc编码的工作量
  2. DBUtils:
    1. QueryRunner类:封装了SQL的执行,线程安全,可以实现CRUD和批处理
    2. ResultHandler接口:用于处理ResultSet结果集,将数据按要求转换成另一种形式

具体工具类:

  • ArrayHandler:把结果集中的第一行数据转成对象数组
  • ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。
  • BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
  • BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
  • ColumnListHandler:将结果集中某一列的数据存放到List中。
  • KeyedHandler(name):将结果集中的每行数据都封装到Map里,再把这些map再存到一个map里,其key为指定的key。
  • MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
  • MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List

DBUtils和德鲁伊连接池的实现:

//先创建好和表对应的Ja
public void testDB() throws SQLException {
        Connection connection = DruidUtils.getConnection();
        QueryRunner queryRunner = new QueryRunner();
        String sql = "select * from emp where deptno = ?";
		//传入参数,这里可以根据需要使用各种不同的Handler
    	//query方法执行DQL语句 update方法执行DML语句
    	//int row = queryRunner.update(connection,sql,params...);
        List<emp> empList = queryRunner.query(connection, sql, new BeanListHandler<>(emp.class), 10);
        for (emp emp:empList) {
            System.out.println(emp);
        }
        DruidUtils.close(null,null,connection);
}
//输出
/*emp{empno=7782, ename='CLARK', job='MANAGER', mgr=7839, hiredate=1981-06-09, sal=2695.0, comm=null, deptno=10}

emp{empno=7839, ename='KING', job='PRESIDENT', mgr=null, hiredate=1981-11-17, sal=5500.0, comm=null, deptno=10}

emp{empno=7934, ename='MILLER', job='CLERK', mgr=7782, hiredate=1982-01-23, sal=1430.0, comm=null, deptno=10} */

query方法源码分析:

private <T> T query(Connection conn, boolean closeConn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
        if (conn == null) {
            throw new SQLException("Null connection");
        } else if (sql == null) {
            if (closeConn) {
                this.close(conn);
            }

            throw new SQLException("Null SQL statement");
        } else if (rsh == null) {
            if (closeConn) {
                this.close(conn);
            }

            throw new SQLException("Null ResultSetHandler");
        } else {
            PreparedStatement stmt = null;//定义PreparedStatement
            ResultSet rs = null;//定义ResultSet用于接收返回的结果集
            Object result = null;//用于接收返回的Arraylist

            try {
                stmt = this.prepareStatement(conn, sql);//创建PreparedStatement对象
                this.fillStatement(stmt, params);//设置sql语句的参数即对?赋值
                rs = this.wrap(stmt.executeQuery());//执行sql语句返回ResultSet
                result = rsh.handle(rs);//将结果集封装到ArrayList中(利用反射)
            } catch (SQLException var33) {
                this.rethrow(var33, sql, params);
            } finally {
                try {
                    this.close(rs);//关闭ResultSet
                } finally {
                    this.close(stmt);//关闭PreparedStatement
                    if (closeConn) {
                        this.close(conn);
                    }

                }
            }

            return result;
        }
    }

DAO和增删改查通用方法-BasicDao

通过apache-dbutil配合druid简化了JDBC开发,但仍然存在不足

问题分析:

  1. sql语句固定,无法通过参数传入
  2. 对DQL语句,如果有返回值,返回类型不能固定,需要使用泛型
  3. 仅靠单个javabean无法完成复杂的业务

基本介绍:

  1. DAO:data access object,数据访问对象
  2. BasicDAO,即通用类,专门和数据库交互,并完成对表的CRUD
  3. 在BasicDAO的基础上,实现一张表对应一个DAO

DAO以及BasicDAO的好处:

  1. BasicDAO将所有DAO的共同操作提取出来,提高可读性和维护性
  2. 各个DAO通过继承BasicDAO完成对应的表的CRUD操作,并可以对不同表执行特有的操作

在这里插入图片描述

//BasciDAO
public class BasicDAO<T> {
    private QueryRunner qr = new QueryRunner();

    //通用的DML方法,针对任意的表
    public int update(String sql,Object... params){
        Connection connection = null;

        try {
            connection = DruidUtils.getConnection();
            int update = qr.update(connection,sql,params);
            return update;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            DruidUtils.close(null,null,connection);
        }
    }
    //查询多行,返回多个对象,针对任意表
    public List<T> queryMany(String sql,Class<T> cls,Object... params){
        Connection connection = null;
        try {
            connection = DruidUtils.getConnection();
            return qr.query(connection,sql,new BeanListHandler<T>(cls),params);
        } catch (SQLException throwables) {
            throw new RuntimeException(throwables);
        } finally {
            DruidUtils.close(null,null,connection);
        }
    }
    //查询当行,返回单个对象,针对任意表
    public Object querySingle(String sql,Object... params){
        Connection connection = null;
        try {
            connection = DruidUtils.getConnection();
            return qr.query(connection,sql,new ScalarHandler(),params);
        } catch (SQLException throwables) {
            throw new RuntimeException(throwables);
        } finally {
            DruidUtils.close(null,null,connection);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值