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

开发准备
注:此处所有用到的资源都为MySQL数据库相关
- 驱动jar包,官网下载地址: https:// dev.mysql.com/downloads /connector/j/
类型选择如下类型:

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




开发步骤
- 注册驱动:告诉JVM使用哪一种数据库
- 获取连接:使用JDBC中的类,获取数据库的连接对象Connection
- 获得语句执行平台:通过Connection可以获取执行对象,Statement,PreparedStatement
- 执行SQL语句:使用执行者对象,向数据库中执行SQL语句,然后可以获得对应的接口,拿到结果
- 对结果进行处理
- 释放对象:按顺序关闭
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对象的步骤
- 获取连接Connection
- 获取Statement
- 编写SQL语句,未知内容使用"?"占位
- 获取PreparedStatement对象
- 设置实际参数:setXxxx()
- 执行参数化SQL语句
- 关闭相关资源
Statement和PreparedStatement的执行原理
- 传输SQL给数据库
- 数据库验证并解析SQL
- 计算Access Plan,数据库会通过检测index,statistics来给出最优的访问计划
- 根据访问计划进行检索,返回数据
上述步骤中,数据库为了提高性能,会缓存执行语句以及其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;