一、前言
我们之前学习了MySQL,可以使用客户端软件手写SQL操作数据库。但在Java后端项目中,我们不可能人工打开数据库客户端执行语句。想要让Java程序直接读写MySQL数据库,就必须学习JDBC。很多初学者学习JDBC只会复制粘贴代码,分不清各个API的作用,不理解SQL注入的危害,也不知道企业开发为什么要用数据库连接池。
本文按照学习路线循序渐进讲解:JDBC基础入门、五大核心API、SQL注入与预编译对象PreparedStatement、Druid连接池。学习完成之后,你就可以独立编写Java代码实现数据库增删改查,同时为后续MyBatis持久层框架打好底层基础。
二、JDBC简介与快速入门
1、简介
JDBC 全称JavaDataBaseConnectivity ,Java数据库连接。它是Sun公司制定的一套操作数据库的标准接口。
• 数据库厂商(MySQL、Oracle)实现这套接口,提供数据库驱动jar包
• 我们Java开发人员,只需要调用统一的JDBC接口,不需要适配不同数据库
• 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类
• 好处:切换数据库时,业务代码几乎不用改动
2、入门程序步骤
0 创建工程,导入驱动jar包
导入jar包后,需要右键点击 add as library ,选择 Module library。
① 加载驱动
class.forName("com.mysql.cj.jdbc.Driver");② 获取连接
/** url: MySQL对应的地址 * username: MySQL对应的用户名 * password: 对应的密码 */ Connection conn = DriverManager.getConnection(url, username, password);url固定写法:"jdbc:mysql://+MySQL对应的IP端口以及数据库的名称"
③ 定义SQL语句
String sql = "update...";④ 获取执行SQL对象
Statement stmt = conn.createStatement();⑤ 执行SQL语句
stmt.executeUpdate(sql);⑥ 处理返回结果
⑦ 释放资源
3、入门示例代码
现数据库数据如下:
通过Java代码把张三的money改为2000
如上运行成功且数据库中数据已更新!
三、JDBC五大核心API详解
1、DriverManager
1.1 DriverManager(驱动管理类)作用
① 注册/加载驱动
② 获取数据库连接,尝试建立与给定数据库URL的连接
1.2 注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");• 查看 Driver 类源码
static{ try{ DriverManager.registerDriver(new Driver()); }catch(SQLException var1){ throw new RuntimeException("Can't register driver!"); } }提示:
• MySQL5.1.6之后的驱动包,可以省略注册驱动的步骤
• 自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类
1.3 获取连接
| static Connection | getConnection(String url, String user, String password) |
• 参数
① url:连接路径
语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2...
示例:jdbc:mysql://127.0.0.1:3306/db1
细节:
• 如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称?参数键值对
• 配置 useSSL=false 参数,禁用安全连接方式,解决警告提示
② user:MySQL对应的用户名
③ password:MySQL对应的密码
2、Connection 连接对象
2.1 Connection(数据库连接对象)作用
① 获取执行SQL语句的对象
② 管理事务
2.2 获取执行SQL的对象
• 普通执行SQL对象
Statement createStatement()• 预编译SQL的执行SQL对象:防止SQL注入
PreparedStatement prepareStatement(sql)• 执行存储过程的对象
CallableStatement prepareCall(sql)2.3 事务管理
• MySQL事务管理
开启事务:begin; / start transaction;
提交事务:commit;
回滚事务:rollback;
MySQL默认自动提交事务
• JDBC事务管理:Connection接口中定义了3个对应的方法
开启事务:setAutoCommit(boolean autoCommit):true为自动提交事务;false为手动提交事务,即为开启事务
提交事务:commit()
回滚事务:rollback()
3、Statement SQL执行对象
3.1 Statement作用
① 执行SQL语句
3.2 执行SQL语句
int executeUpdate(sql):执行DML、DDL语句
• 返回值:(1)DML语句影响的行数 (2)DDL语句执行后,执行成功也可能返回0
• DML语句影响的行数
• 执行DDL语句
ResultSet executeQuery(sql):执行DQL语句
• 返回值:ResultSet 结果集对象
4、ResultSet 结果集对象
4.1 ResultSet(结果集对象)作用
封装了DQL查询语句的结果,本质上是一张二维数据表
ResultSet stmt.executeQuery(sql):执行DQL语句,返回ResultSet对象
4.2 获取查询结果
• boolean next():将游标从当前位置移动一行,判断当前行是否为有效行
返回值:① true:有效行,当前行有数据
② false:无效行,当前行没有数据
• getInt() / getString():根据列名/下标获取字段值
参数:int:列的编号,从1开始;String:列的名称
4.3 使用步骤
① 游标向下移动一行,并判断该行是否有数据:next()
② 获取数据:getXxx(参数)
//循环判断游标是否是最后一行末尾 while(rs.next()){ //获取数据 rs.getXxx(参数); }代码演示:
4.4 ResultSet案例
查询account账户表数据,封装为Account对象(Java对象)中,并且存储到ArrayList集合中
先准备一个实体类Account
再在JDBCDemo_ResultSet中实现
5、PreparedStatement ⭐
5.1 PreparedStatement作用
预编译SQL语句并执行:预防SQL注入问题
5.2 SQL注入
SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。简单理解就是当我们需要输入用户名和密码登录时,如果在密码处写一段特殊脚本就能登录成功,登录成功之后就能进行攻击,这样会非常不安全。
案例:登录场景
拼接写法:
select * from user where username="+name+" and password="+pwd+"如果用户密码输入:' or '1' ='1 最终SQL逻辑被篡改,不需要正确密码也能登录成功,这就是SQL注入!
• 登录案例
演示SQL注入:
分析sql语句:String sql = "select * from tb_user where username = 'whflbr' and password = ' ' or '1' = '1' "
username = 'whflbr' and password = ' '结果为false,'1' = '1'结果为true,所以where语句为true
那么我们就需要通过PreparedStatement对象来解决SQL注入问题。
5.3 PreparedStatement的使用
① 获取 PreparedStatement 对象
//SQL语句中的参数值,使用?占位符替代 String sql = "select * from user where username = ? and password = ?"; //通过Connection对象获取,并传入对应的sql语句 PreparedStatement pstmt = conn.prepareStatement(sql);② 设置参数值
PreparedStatement对象:setXxx(参数1,参数2):给 ? 赋值
• Xxx:数据类型;如setInt(参数1,参数2)
• 参数:
参数1:?的位置编号,从1开始
参数2:?的值
③ 执行SQL
executeUpdate(); / executeQuery(); //不需要再传递sql登录案例演示:
PreparedStatement会对传入的值进行转义!!!
5.4 PreparedStatement 原理
• PreparedStatement 好处:
① 预编译SQL,性能更高(模板一样,执行时跳过“检查语法”和“编译SQL”,直接执行SQL)
② 防止SQL注入:将敏感字符进行转义
① PreparedStatement 预编译供能开启:useServerPrepStmts=true(默认关闭,要开启)
② 配置MySQL执行日志(重启mysql服务后生效)
log-output=FILE general-log=1 general_log_file="D:\MySQL\mysql.log" slow-query-log=1 slow_query_log_file="D:\MySQL\mysql_slow.log" long_query_time=2在my.ini中编辑,重启MySQL就能看到mysql.log文件和mysql_slow.log文件
• PreparedStatement 原理:
① 在获取PreparedStatement对象时,将sql语句发送给mysql服务器进行检查,编译(这些步骤很耗时)
② 执行时就不用再进行这些步骤了,速度更快
③ 如果sql模板一样,则只需要进行一次检查、编译
四、数据库连接池原理与Druid使用
1、数据库连接池简介
• 数据库连接池是个容器,负责分配、管理数据库连接(Connection)
• 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
• 释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
• 好处:
• 资源重用
• 提升系统响应速度
• 避免数据库连接遗漏
2、数据库连接池实现
• 标准接口:DataSource
• 官方(SUN)提供的数据库连接池标准接口,由第三方组织实现此接口。
• 功能:获取连接
Connection getConnection()• 常见的数据库连接池:
• DBCP
• C3P0
• Druid
• Druid(德鲁伊)
• Druid连接池是阿里巴巴开源的数据库连接池项目
• 功能强大,性能优秀,是Java语言最好的数据库连接池之一
3、Druid使用步骤
① 导入jar包 druid-1.2.9.jar,添加为库,选择模块库
② 定义配置文件 druid.properties
③ 加载配置文件
④ 获取数据库连接池对象
⑤ 获取连接
五、结语
本篇完整学习了Java操作数据库底层技术JDBC:从基础入门代码,逐一吃透DriverManager、Connection、Statement、ResultSet五大API;理解危险的SQL注入漏洞,掌握安全的PreparedStatement预编译方案;最后学习数据库连接池Druid,解决原生JDBC性能短板,贴近企业真实开发规范。
JDBC是所有持久层框架的基石,MyBatis、MyBatis-Plus底层依然封装JDBC。把本章内容吃透,后续学习持久层框架将会事半功倍。