添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

JDBC学习笔记

本文是在学习JDBC时所记,便于后面复习使用。

概念

JDBC(Java Data Base Connectivity)是 Java访问数据库的标准规范 。是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC 提供了一个种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序,同时JDBC也是个商标名。

开发准备

注:此处所有用到的资源都为MySQL数据库相关

类型选择如下类型:

  • 配置jar包,强烈推荐通过Librarues方式添加
  1. 创建一个文件夹为存放jar包的临时仓库
  2. 在项目中新建一个module:“File”→ “New”→“Module”
  3. 查看项目设置。步骤如图3-1,3-2。
  4. 通过选中“Libraries”→“+”→“Java”→“选择步骤1的临时仓库”的方式添加。如图4-1。
  5. 最终通过“Module”查看jar包是否添加成功。如图5-1。
图3-1
图3-2
图4-1
图5-1

开发步骤

  1. 注册驱动:告诉JVM使用哪一种数据库
  2. 获取连接:使用JDBC中的类,获取数据库的连接对象Connection
  3. 获得语句执行平台:通过Connection可以获取执行对象,Statement,PreparedStatement
  4. 执行SQL语句:使用执行者对象,向数据库中执行SQL语句,然后可以获得对应的接口,拿到结果
  5. 对结果进行处理
  6. 释放对象:按顺序关闭

API使用

注册驱动

  • JDBC规范定义驱动接口: java.sql.Driver
  • MySQL驱动包提供了实现类: com.mysql.jdbc.Driver
注意:MySQL6之后的版本都是要指定时区serverTimezone。因此6以后驱动接口需要改为:com.mysql.cj.jdbc.Driver
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
注册驱动原理

获取连接

//2.获取连接 connection连接对象
String url = "jdbc:mysql://localhost:3306/db3?characterEncoding=URF-8";
Connection con = DriverManager.getConnection(url, "root", "19931123");

获取执行对象

//3.获取语句执行对象
Statement statement = con.createStatement();
//3.1通过statement对象的executeUpdate方法
String sql = "select * from employee;";
//3.2通过ResultSet处理结果集对象
ResultSet rs = statement.executeQuery(sql);

处理结果对象

 //4.处理对象
while (rs.next()) {
    int id = rs.getInt("eid");
    String nameStr = rs.getString("ename");
    int age = rs.getInt("age");
    System.out.println(id + ":" + nameStr + ":" + age);       
 }

关闭流

//关闭流 原则:先开后关,后开先关
rs.close();
con.close();
statement.close();

JDBC工具类

此处用到了 封装 思想,将一些重复代码封装成一个工具类,方便使用。

public class JDBCUtils {
    //1.将连接信息定义为字符串常量
    public static final String DRIVERNAME = "com.mysql.cj.jdbc.Driver";
    public static final String URL = "jdbc:mysql://localhost:3306/db3?characterEncoding=UTF-8";
    public static final String USER = "root";
    public static final String PASSWORD = "19931123";
    //2.静态代码块
    static {
        try {
            Class.forName(DRIVERNAME);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
    //3.获取连接的静态方法
    public static Connection getConnection() {
        //获取连接对象并返回
        try {
            Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
            return connection;
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
    //4.关闭资源fangfa
    public static void close(Connection con, Statement statement) {
        if (con != null && statement != null) {
            try {
                statement.close();
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
    //重载方法,当执行查询时需要关闭resultSet对象
    public static void close(Connection con, Statement statement, ResultSet resultSet) {
        if (con != null && statement != null) {
            try {
                statement.close();
                con.close();
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
}
Statement的SQL注入问题

SQL注入是一个安全问题,使用拼接SQL的技术成为hacker攻击后台的方式。

如何避免SQL注入?

PreparedStatement

概念:PreparedStatement是Statement接口的子接口,继承于父接口中所有的方法,它是一个预编译的SQL语句。

预编译:是指SQL语句被预编译,并存储在PreparedStatement对象中,然后可以使用此对象多次高效执行。

使用PreparedStatement对象的步骤

  1. 获取连接Connection
  2. 获取Statement
  3. 编写SQL语句,未知内容使用"?"占位
  4. 获取PreparedStatement对象
  5. 设置实际参数:setXxxx()
  6. 执行参数化SQL语句
  7. 关闭相关资源

Statement和PreparedStatement的执行原理

  1. 传输SQL给数据库
  2. 数据库验证并解析SQL
  3. 计算Access Plan,数据库会通过检测index,statistics来给出最优的访问计划
  4. 根据访问计划进行检索,返回数据

上述步骤中,数据库为了提高性能,会缓存执行语句以及其Access Plan,被称为StatementCache。在StatementCache中,SQL语句本身为key,Access Plan为value,当相同的SQL语句被发送过来时,数据库会使用缓存的Access Plan来节省时间。

而PreparedStatement在创建的时候,会将参数化的语句发送给数据库,进行语法检测和执行计划计算,Cache中的key将是参数化的语句,当后面PreparedStatement在执行的时候,每次均会命中Cache,使用已存在的Access Plan进行检索。

数据库事务

概念:数据库事务(Transaction)是由若干个SQL语句构成的一个操作序列,类似于Java中的锁同步。数据库系统保证在一个事务中的所有SQL要么全部执行成功,要么全部不执行。

ACID特性:

  • Atomicity:原子性,一组事务要么成功执行,要么撤回
  • Consistency:一致性,事务执行后,数据库状态与其他业务规则保持一致
  • Isolation:隔离性,一个事务处理后的结果,影响到其他事务,那么其他事务会撤回
  • Durability:持久性

要在JDBC中执行事务,本质上就是如何把多条SQL包裹在一个数据库事务中执行。

Connection con = null;
PreparedStatement ps = null;
try {
    con = JDBCUtils.getConnection();
    //开启事务 关闭自动提交
    con.setAutoCommit(false);
    //执行sql语句
    //to do....
    //提交事务
    con.commit();
}catch (SQLException e) {
    e.printStackTrace();
    //出现异常则回滚事务
    con.rollback();
}finally




    
 {
    JDBCUtils.close(con, ps);
}

数据库连接池

概念:为了解决实际开发中“获得连接”和“释放资源”的性能问题,通常情况下采用连接池技术,来共享连接Connection。我们就不用自己来创建Connection,而是通过连接池获取,当使用完毕,调用close()方法也不会真的关闭Connection,而是把Connection归还给池。

Java为数据库连接池提供了公共接口: javax.sql.DataSource ,各厂商可以让自己的连接池实现这个接口。这样应用程序可以方便切换不同厂商的连接池。常见的连接池有 DBCP、C3P0、Druid。

通过引入jar包的方式使用常见连接池。

DBCP连接池

DBCP连接池是一个开源的连接池,是Apache成员之一,tomcat内置的连接池。

  • 将DBCP的如下jar包放入项目中存放jar包的临时仓库,并添加依赖。

编写工具类

public class DBCPUtils {
    //1.将连接信息定义为字符串常量
    public static final String DRIVERNAME = "com.mysql.cj.jdbc.Driver";
    public static final String URL = "jdbc:mysql://localhost:3306/db3?characterEncoding=UTF-8";
    public static final String USER = "root";
    public static final String PASSWORD = "19931123";
    //2.创建连接池对象
    public static BasicDataSource dataSource = new BasicDataSource();
    //3.通过静态代码块进行配置
    static {
        dataSource.setDriverClassName(DRIVERNAME); 
        dataSource.setUrl(URL); 
        dataSource.setUsername(USER); 
        dataSource.setPassword(PASSWORD);
    //4.获取连接的方法 
    public static Connection getConnection() throws SQLException { 
        //从连接池中获取连接 
        Connection connection = dataSource.getConnection(); 
        return connection; 
    //5.释放资源方法 
    public static void close(Connection con, Statement statement){ 
        if(con != null && statement != null){ 
             try {
                 statement.close(); 
                 //归还连接 
                 con.close();
             } catch (SQLException e) { 
                 e.printStackTrace(); 
    public static void close(Connection con, Statement statement, ResultSet resultSet){ 
        if(con != null && statement != null && resultSet != null){ 
             try {
                 resultSet.close(); 
                 statement.close(); 
                 //归还连接 
                 con.close(); 
             } catch (SQLException e) { 
                 e.printStackTrace(); 
}

C3P0连接池

C3P0是一个开源的JDBC连接,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等。

  • 将C3P0的如下jar包放入项目中存放jar包的临时仓库,并添加依赖。
  • 导入配置文件 c3p0-confifig.xml

配置文件名称不可修改,直接放到src下,也可以放到资源文件夹中。

C3P0核心工具类为 ComboPooledDataSource ,如果要使用连接池就必须创建该类对象。无参构造方法为使用默认配置,带参则为使用命名配置

Druid连接池

阿里巴巴开发的号称为监控而生的数据库连接池,Druid是目前最好的数据库连接池,在功能、性能、扩展性方面都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB和SQL执行情况。

  • 导入Druid连接池jar包
  • 导入配置文件。配置文件为properties形式,可以改为任意名称,可以放在任意目录。但建议 放在src或资源文件夹中
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/db3?characterEncoding=UTF-8
username=root 
password=19931123 
initialSize=5 
maxActive=10 
maxWait=3000
Druid通过工厂DruidDataSourceFactory类的createDataSource方法来获取连接池对象。createDataSource(Properties p)方法参数可以是一个属性集对象。

Druid连接池初始化和DBCP类似,都是在静态代码块中进行初始化。

static { 
    try {
        //创建属性集对象 
        Properties p = new Properties(); 
        //加载配置文件Druid连接池不能够主动加载配置文件,需要指定文件 
        InputStream inputStream = DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties"); 
        //使用Properties对象的load方法从字节流中读取配置信息 
        p.load(inputStream); 
        //通过工厂类获取连接池对象 
        dataSource = DruidDataSourceFactory.createDataSource(p); 
    } catch (Exception e) {
        e.printStackTrace();
}

DBUtils工具类

概念:Commons DBUtils是Apache提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。DbUtils类主要负责装载驱动、关闭连接的常规工作。

  • 导入jar包: commons-dbutils-1.6.jar

核心功能介绍

QreryRunner类是Dbutils的核心类之一,它显著的简化了SQL查询,并与ResultSetHandler协同工作将使编码量大为减少。

  • QueryRunner中提供对sql语句操作的API。
  • ResultSetHandler接口,用于定义select操作后,怎样封装结果集。

QueryRunne r 的创建

//手动方式创建
QueryRunner queryRunner = new QueryRunner();
//自动方式创建(需要传入连接池对象)
QueryRunner queryRunner = new QueryRunner(DBUtils.getDataSource());

DBUtils完成增删改操作

//用来执行插入、更新或删除操作。 
update(Connection conn, String sql, Object... params)

DBUtils完成查询操作

//执行选择查询,在查询中,对象阵列的值被用来作为查询的置换参数。
query(Connection conn, String sql, Object param, ResultSetHandler<T> rsh)
//不提供数据库连接执行选择查询,在查询中,对象阵列的值被用来作为查询的置换参数。
query(String sql, Object[] params, ResultSetHandler rsh)
//执行无需参数的查询
query(Connection conn, String sql, ResultSetHandler rsh)

ResultSetHandler接口执行处理一个结果集对象,将数据转变并处理为任何一种形式,供其他应用使用。常用实现类如下:

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

JavaBean组件

JavaBean就是一个类,开发中通常用于封装数据。特点如下:

  • 需要实现 序列化接口, Serializable (暂时可以省略)
  • 提供私有字段: private 类型 变量名;
  • 提供getter和setter方法
  • 提供无参构造方法

数据库批处理

概念:批处理指的是一次操作中执行多条SQL语句,相比于按次执行批处理的效率会高很多。

MySQL的批处理默认是关闭的,需要加一个参数才打开批处理

url=jdbc:mysql://127.0.0.1:3306/db3?characterEncoding=UTF-8&rewriteBatchedStatements=true 

批处理方法

//将给定的SQL指令添加到此Statement对象的当前命令列表中
void addBatch()
//每次提交一批命令到数据库中执行,如果所有的命令都成功执行了,那么返回一个数组,
//这个数组是说明每条命令所影响的行数
int[] executeBatch()

MySql元数据

除了表之外的数据都是 元数据 ,可以分为三类:

  • 查询结果信息
  • 数据库和数据表的信息
  • MySqL服务器信息

元数据相关命令

//查看服务器的状态信息
show status;
//获取mysql服务器的版本信息 
select version();
//显示表的字段信息等 
show columns from table_name; 
//显示数据表的详细索引信息,包括PRIMARY KEY(主键)
show index from table_name;