JDBC
JDBC 简介
JDBC 就是使用Java语言操作关系型数据库的一套API, 全称:( Java DataBase Connectivity ) Java 数据库连接
- 官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口
- 各个数据库厂商去实现这套接口,提供数据库驱动jar包
- 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类
驱动安装
-
下载 MySQL 驱动包,解压后得到 jar 库文件:https://downloads.mysql.com/archives/c-j/
-
打开 IDE,在对应项目中 configure build path 导入 jar 库文件。
JDBC快速入门
编写代码步骤
public class JDBCDemo {
public static void main(String[] args) throws Exception {
// 1.注册驱动(MySQL 5之后的驱动包,可以省略注册驱动的步骤)
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/db?useSSL=false";
String username = "root";
String password = "tt951008";
Connection conn = DriverManager.getConnection(url, username, password);
// 3.定义sql
String sql = "update account set money = 2000 where id=1";
// 4.获取执行sql的对象 Statement
Statement statement = conn.createStatement();
// 5.执行sql
int count = statement.executeUpdate(sql); // 返回受影响的行数
// 6.处理结果
System.out.println(count);
// 7.释放资源
statement.close();
conn.close();
}
}
JDBC API详解
DriverManager
DriverManager(驱动管理类)作用:
- 注册驱动
// registerDriver方法是用于注册驱动的,但是我们之前做的入门案例并不是这样写的。而是如下实现
Class.forName("com.mysql.jdbc.Driver");

我们查询MySQL提供的Driver类,看它是如何实现的,源码如下:
在该类中的静态代码块中已经执行了 DriverManager 对象的 registerDriver() 方法进行驱动的注册了,那么我们只需要加载 Driver 类,该静态代码块就会执行。而 Class.forName("com.mysql.jdbc.Driver"); 就可以加载 Driver 类。
- 获取数据库连接
url : 连接路径
语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2…
示例:jdbc:mysql://127.0.0.1:3306/db1
如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称?参数键值对
配置 useSSL=false 参数,禁用安全连接方式,解决警告提示
user :用户名
poassword :密码
Connection
Connection(数据库连接对象)作用:
-
获取执行 SQL 的对象
-
管理事务
获取执行对象
- 普通执行SQL对象
Statement createStatement()
- 预编译SQL的执行SQL对象:防止SQL注入
PreparedStatement prepareStatement(sql)
- 执行存储过程的对象
CallableStatement prepareCall(sql)
事务管理
public class JDBCDemo3_Connection {
public static void main(String[] args) throws Exception {
//1. 注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql
String sql1 = "update account set money = 3000 where id = 1";
String sql2 = "update account set money = 3000 where id = 2";
//4. 获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
try {
// ============开启事务==========
conn.setAutoCommit(false); //true表示自动提交事务,false表示手动提交事务。而开启事务需要将该参数设为为false。
//5. 执行sql
int count1 = stmt.executeUpdate(sql1);//受影响的行数
//6. 处理结果
System.out.println(count1);
int i = 3/0;
//5. 执行sql
int count2 = stmt.executeUpdate(sql2);//受影响的行数
//6. 处理结果
System.out.println(count2);
// ============提交事务==========
//程序运行到此处,说明没有出现任何问题,则需求提交事务
conn.commit();
} catch (Exception e) {
// ============回滚事务==========
//程序在出现异常时会执行到这个地方,此时就需要回滚事务
conn.rollback();
e.printStackTrace();
}
//7. 释放资源
stmt.close();
conn.close();
}
}
Statement
Statement对象的作用就是用来执行SQL语句。而针对不同类型的SQL语句使用的方法也不一样。
- 执行DDL、DML语句
executeUpdate(sql)
- 执行DQL语句
executeQuery(sql)
ResultSet
ResultSet(结果集对象)封装了SQL查询语句的结果。
ResultSet对象提供了操作查询结果数据的方法,如下:
boolean next()
将光标从当前位置向前移动一行
判断当前行是否为有效行
方法返回值说明:
true : 有效行,当前行有数据
false : 无效行,当前行没有数据
xxx getXxx(参数):获取数据
xxx : 数据类型;如: int getInt(参数) ;String getString(参数)
参数
int类型的参数:列的编号,从1开始
String类型的参数: 列的名称
PreparedStatement
PreparedStatement 好处:
预编译SQL,性能更高
防止SQL注入:将敏感字符进行转义
- 获取 PreparedStatement 对象
// SQL语句中的参数值,使用?占位符替代
String sql = "select * from user where username = ? and password = ?";
// 通过Connection对象获取,并传入对应的sql语句
PreparedStatement pstmt = conn.prepareStatement(sql);
// 设置?的值
pstmt.setString(1,name);
pstmt.setString(2,pwd);
- 设置参数值
上面的sql语句中参数使用 ? 进行占位,在之前之前肯定要设置这些 ? 的值。
PreparedStatement对象:setXxx(参数1,参数2):给 ? 赋值
Xxx:数据类型 ; 如 setInt (参数1,参数2)
参数:
参数1: ?的位置编号,从1 开始
参数2: ?的值
执行SQL语句
executeUpdate(); 执行DDL语句和DML语句
executeQuery(); 执行DQL语句
注意:调用这两个方法时不需要传递SQL语句,因为获取SQL语句执行对象时已经对SQL语句进行预编译了
PreparedStatement原理
接下来我们通过查询日志来看一下原理:
- 开启预编译功能
在代码中编写url时需要加上以下参数。而我们之前根本就没有开启预编译功能,只是解决了SQL注入漏洞。
useServerPrepStmts = true
- 配置MySQL执行日志(重启mysql服务后生效)
在mysql配置文件(my.ini)中添加如下配置
log-output=FILE
general-log=1
general_log_file="D:\mysql.log"
slow-query-log=1
slow_query_log_file="D:\mysql_slow.log"
long_query_time=2
- java测试代码如下:
@Test
public void testPreparedStatement2() throws Exception {
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
// useServerPrepStmts=true 参数开启预编译功能
String url = "jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用户输入 用户名和密码
String name = "zhangsan";
String pwd = "' or '1' = '1";
// 定义sql
String sql = "select * from tb_user where username = ? and password = ?";
// 获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
Thread.sleep(10000);
// 设置?的值
pstmt.setString(1,name);
pstmt.setString(2,pwd);
ResultSet rs = null;
// 执行sql
rs = pstmt.executeQuery();
// 设置?的值
pstmt.setString(1,"aaa");
pstmt.setString(2,"bbb");
// 执行sql
rs = pstmt.executeQuery();
// 判断登录是否成功
if(rs.next()){
System.out.println("登录成功~");
}else{
System.out.println("登录失败~");
}
//7. 释放资源
rs.close();
pstmt.close();
conn.close();
}
- 执行SQL语句,查看
D:\mysql.log日志如下:

上图中第三行中的Prepare是对SQL语句进行预编译。第四行和第五行是执行了两次SQL语句,而第二次执行前并没有对SQL进行预编译。

Java代码操作数据库流程如图所示:
将sql语句发送到MySQL服务器端
MySQL服务端会对sql语句进行如下操作
检查SQL语句
检查SQL语句的语法是否正确。
编译SQL语句。将SQL语句编译成可执行的函数。
检查SQL和编译SQL花费的时间比执行SQL的时间还要长。如果我们只是重新设置参数,那么检查SQL语句和编译SQL语句将不需要重复执行。这样就提高了性能。
执行SQL语句
数据库连接池
数据库连接池简介
数据库连接池是个容器,负责分配、管理数据库连接(Connection)
它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;
释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
好处:
资源重用
提升系统响应速度
避免数据库连接遗漏
数据库连接池实现
标准接口: =DataSource
官方(SUN) 提供的数据库连接池标准接口,由第三方组织实现此接口。该接口提供了获取连接的功能:
那么以后就不需要通过 DriverManager 对象获取 Connection对象,而是通过连接池(DataSource)获取 Connection 对象。
Connection getConnection()
常见的数据库连接池,DBCP、C3P0、Druid,我们现在使用更多的是Druid,它的性能比其他两个会好一些。
Druid(德鲁伊)
Druid连接池是阿里巴巴开源的数据库连接池项目
功能强大,性能优秀,是Java语言最好的数据库连接池之一
Driud使用
1.导入jar包 druid-1.1.12.jar
2.定义配置文件
3.加载配置文件
4.获取数据库连接池对象
5.获取连接
使用druid的代码如下:
public class DruidDemo {
@Test
public void test() throws Exception {
// 1.导入jar包
// 2.定义配置文件
// 3. 加载配置文件
Properties prop = new Properties();
prop.load(new FileReader("src/druid.properties"));
// 4. 获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
// 5.获取数据库连接 Connection
Connection connection = dataSource.getConnection();
System.out.println(connection);
// System.out.println(System.getProperty("user.dir")); // 获取当前文件所在路径位置
}
}
druid配置详解
| 属性 | 说明 | 建议值 |
|---|---|---|
| url | 数据库的jdbc连接地址。一般为连接oracle/mysql。示例如下: | |
| mysql : jdbc:mysql://ip:port/dbname?option1&option2&… | ||
| oracle : jdbc:oracle:thin:@ip:port:oracle_sid | ||
| username | 登录数据库的用户名 | |
| password | 登录数据库的用户密码 | |
| initialSize | 启动程序时,在连接池中初始化多少个连接 | 10-50已足够 |
| maxActive | 连接池中最多支持多少个活动会话 | |
| maxWait | 程序向连接池中请求连接时,超过maxWait的值后,认为本次请求失败,即连接池 | 100 |
| 没有可用连接,单位毫秒,设置-1时表示无限等待 | ||
| minEvictableIdleTimeMillis | 池中某个连接的空闲时长达到 N 毫秒后, 连接池在下次检查空闲连接时,将 | 见说明部分 |
| 回收该连接,要小于防火墙超时设置 | ||
| net.netfilter.nf_conntrack_tcp_timeout_established的设置 | ||
| timeBetweenEvictionRunsMillis | 检查空闲连接的频率,单位毫秒, 非正整数时表示不进行检查 | |
| keepAlive | 程序没有close连接且空闲时长超过 minEvictableIdleTimeMillis,则会执 | true |
| 行validationQuery指定的SQL,以保证该程序连接不会池kill掉,其范围不超 | ||
| 过minIdle指定的连接个数。 | ||
| minIdle | 回收空闲连接时,将保证至少有minIdle个连接. | 与initialSize相同 |
| removeAbandoned | 要求程序从池中get到连接后, N 秒后必须close,否则druid 会强制回收该 | false,当发现程序有未 |
| 连接,不管该连接中是活动还是空闲, 以防止进程不会进行close而霸占连接。 | 正常close连接时设置为true | |
| removeAbandonedTimeout | 设置druid 强制回收连接的时限,当程序从池中get到连接开始算起,超过此 | 应大于业务运行最长时间 |
| 值后,druid将强制回收该连接,单位秒。 | ||
| logAbandoned | 当druid强制回收连接后,是否将stack trace 记录到日志中 | true |
| testWhileIdle | 当程序请求连接,池在分配连接时,是否先检查该连接是否有效。(高效) | true |
| validationQuery | 检查池中的连接是否仍可用的 SQL 语句,drui会连接到数据库执行该SQL, 如果 | |
| 正常返回,则表示连接可用,否则表示连接不可用 | ||
| testOnBorrow | 程序 申请 连接时,进行连接有效性检查(低效,影响性能) | false |
| testOnReturn | 程序 返还 连接时,进行连接有效性检查(低效,影响性能) | false |
| poolPreparedStatements | 缓存通过以下两个方法发起的SQL: | true |
| public PreparedStatement prepareStatement(String sql) | ||
| public PreparedStatement prepareStatement(String sql, | ||
| int resultSetType, int resultSetConcurrency) | ||
| maxPoolPrepareStatementPerConnectionSize | 每个连接最多缓存多少个SQL | 20 |
| filters | 这里配置的是插件,常用的插件有: | stat,wall,slf4j |
| 监控统计: filter:stat | ||
| 日志监控: filter:log4j 或者 slf4j | ||
| 防御SQL注入: filter:wall | ||
| connectProperties | 连接属性。比如设置一些连接池统计方面的配置。 | |
| druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 | ||
| 比如设置一些数据库连接属性: | ||

JDBC
浙公网安备 33010602011771号