持续学习&持续更新中…

学习态度:守破离


JDBC FOR MySQL

  • 什么是JDBC
    • 如何通过Java操作数据库
    • JDBC是属于JavaSE的一部分
  • 下载MySQL的JDBC实现
  • JDBC细节
    • JDBC——MySQL的url格式
    • JDBC版本与JavaSE版本
  • JDBC使用步骤
    • 最基本的JDBC程序——MySQL驱动包6.x之前
    • 最基本的JDBC程序——MySQL驱动包6.x开始及之后
  • Statement常用API
  • ResultSet常用API
    • 使用上述API查询表中的数据
    • 使用上述API查询表中的数据(优化版)
  • 举一个SQL注入问题的例子(使用Statement)
  • PreparedStatement
  • 参考

什么是JDBC

如何通过Java操作数据库

JDBC是属于JavaSE的一部分

下载MySQL的JDBC实现

地址链接:

解释:https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-versions.html
下载:https://dev.mysql.com/downloads/connector/j/

JDBC细节

JDBC——MySQL的url格式

JDBC版本与JavaSE版本

注意:从Java SE 6(JDBC4.0)开始我们就不用显示的注册驱动程序了。

JDBC使用步骤

最基本的JDBC程序——MySQL驱动包6.x之前

public class Main {private static final String DRIVER_MYSQL = "com.mysql.jdbc.Driver";private static final String mysqlURL = "jdbc:mysql://localhost:3306/xmg";private static final String user = "root";private static final String password = "root";/* JDBC属于JavaSE的一部分 具体看图示Java.png *//* 最基本的JDBC访问MySQL程序 */public static void main(String[] args) throws Exception {/* 步骤一: 将Driver注册到DriverManager 加载驱动 */// 方式一 推荐使用 装载MySQL驱动类Class.forName(DRIVER_MYSQL);//  方式二 不推荐使用//  DriverManager.registerDriver(new Driver());/* 步骤二:利用DriverManager创建数据库连接 获取数据库连接对象 */Connection connection = DriverManager.getConnection(mysqlURL, user, password);/* 步骤三:利用Connection创建SQL语句对象 */Statement statement = connection.createStatement();/* 步骤四:执行SQL语句 SQL语句不用加;*/final String sql = "INSERT INTO customer (id, name, phone, company_id) VALUES (101, 'lphahaha', '11122223333', 1)";statement.execute(sql);/* 步骤五:关闭释放资源 */statement.close();connection.close();}}

也可以使用try-with-resources来简写代码,确保关闭释放资源

    public static void main(String[] args) {try {Class.forName(DRIVER_MYSQL);} catch (ClassNotFoundException e) {System.err.println("加载驱动失败!");e.printStackTrace();}// try-with-resourcestry (Connection connection = DriverManager.getConnection(mysqlURL, user, password);Statement statement = connection.createStatement()) {final String sql = "INSERT INTO customer (id, name, phone, company_id) VALUES (101, 'lphahaha', '11122223333', 1)";statement.execute(sql);} catch (Exception e) {e.printStackTrace();}}

又因为从Java SE 6(JDBC4.0)开始我们就不用显示的注册驱动程序。

所以代码可以简化如下:

public static void main(String[] args) throws Exception{try (Connection connection = DriverManager.getConnection(mysqlURL, user, password);Statement statement = connection.createStatement()) {final String sql = "INSERT INTO customer (name, phone, company_id) VALUES ('niuniuniu', '66666666666', 2)";statement.execute(sql);}}

最基本的JDBC程序——MySQL驱动包6.x开始及之后

public class Main {private static final String DRIVER_MYSQL = "com.mysql.cj.jdbc.Driver";private static final String mysqlURL = "jdbc:mysql://localhost:3306/xmg?serverTimezone=UTC";private static final String user = "root";private static final String password = "root";public static void main(String[] args) {try {// Java SE 6开始就不用显示加载驱动了// 这儿显示加载驱动的目的是为了学习这块的知识点Class.forName(DRIVER_MYSQL);} catch (ClassNotFoundException e) {System.out.println("加载驱动失败!");}try (Connection connection = DriverManager.getConnection(mysqlURL, user, password);Statement statement = connection.createStatement()) {final String sql = "INSERT INTO customer (id, name, phone, company_id) VALUES (104, 'hahaha', '44444444444', 3)";statement.execute(sql);} catch (Exception e) {e.printStackTrace();}}}

Statement常用API

ResultSet常用API

注意:

  • 游标刚开始没有指向任何记录,指向的是第一条记录之前的东西,当调用next方法之后,它才会指向第一条记录。

  • 使用resultSet.getXXX(int columnIndex)获取数据时,columnIndex是从1开始的(columnIndex指的是表的第几列)。

  • 使用resultSet.getXXX(String columnLabel)获取数据时,columnLabel不一定是表的列名(如果查询的时候使用了别名,那么此时的columnLabel就是别名)。

使用上述API查询表中的数据

    private static void test3() throws Exception {final String mysqlURL = "jdbc:mysql://localhost:3306/xmg?serverTimezone=UTC";final String user = "root";final String password = "root";final String sql = "SELECT * FROM customer";try (Connection connection = DriverManager.getConnection(mysqlURL, user, password);Statement statement = connection.createStatement();ResultSet resultSet = statement.executeQuery(sql)) {while (resultSet.next()) {System.out.println("name : " + resultSet.getString("name") + " ;" +"phone : " + resultSet.getString("phone") + " ;" +"company id : " + resultSet.getInt("company_id"));}}}

使用上述API查询表中的数据(优化版)

在向数据库插入某个记录的时候,有可能该记录的某一列上的数据不存在,因此就没有向该列插入数据,导致该列的数据为NULL。

如果是这种情况的话,我们查询数据的时候就不应该使用基本类型,而是应该使用对象数据类型(假设表中某个INT类型的字段的数据为NULL,那么直接使用resultSet.getInt()的话,返回值会是0),而ResultSet又没有提供resultSet.getInteger()之类的API,因此我们可以使用resultSet.getObject(),查询出数据后可以进行判空操作,判空操作之后再继续下一步操作。

    private static void test4() throws Exception {final String mysqlURL = "jdbc:mysql://localhost:3306/xmg?serverTimezone=UTC";final String user = "root";final String password = "root";final String sql = "SELECT company_id myCpid FROM customer";try (Connection connection = DriverManager.getConnection(mysqlURL, user, password);Statement statement = connection.createStatement();ResultSet resultSet = statement.executeQuery(sql)) {while (resultSet.next()) {Object myCpid = resultSet.getObject("myCpid");if (myCpid != null) {// int id = (Integer) myCpid;// 推荐使用对象类型Integer id = (Integer) myCpid; // 执行相应的操作// ......}}}}

举一个SQL注入问题的例子(使用Statement)

① 建表 & 插入数据:

DROP TABLE IF EXISTS user;
CREATE TABLE user (id INT PRIMARY KEY AUTO_INCREMENT,name varchar(20) NOT NULL UNIQUE,pswd varchar(20) DEFAULT NULL
);INSERT INTO user (name, pswd) VALUES ('123', '123');
INSERT INTO user (name, pswd) VALUES ('lpruoyu', 'lpruoyu');
INSERT INTO user (name, pswd) VALUES ('root', 'root');

② 编写Java代码(使用Statement来进行查询):

    private static void login(String name, String pswd) throws Exception {final String mysqlURL = "jdbc:mysql://localhost:3306/xmg?serverTimezone=UTC";final String user = "root";final String password = "root";final String sql = "SELECT * FROM user WHERE name = '" + name + "' AND pswd = '" + pswd + "'";try (Connection connection = DriverManager.getConnection(mysqlURL, user, password);Statement statement = connection.createStatement();ResultSet resultSet = statement.executeQuery(sql)) {// 返回结果只可能有1条或者0条if (resultSet.next()) { // 返回值有一条记录 找到该用户System.out.println("登录成功!");} else { // 没有返回值 没有找到该用户System.out.println("登录失败,用户名或密码不正确!");}}}

如果用户将pswd传入' OR '1' = '1的话,就相当于执行下列的语句(此时name的值是什么已经无所谓了,我就什么都没写):

很明显,这样做的话,使用上述Java代码进行登录,每次都会登录成功(由于AND 优先级高于 OR,因此OR前面的name = '' AND pswd = ''是一个整体AOR后面的'1' = '1'是一个整体B,这时WHERE后面就有两部分组成:A OR B,而B是恒成立的,因此每次都会查询出结果。),这就导致了SQL Injection(SQl注入)问题,程序就会产生漏洞。

那么该如何修复这种问题呢?使用PreparedStatement!

PreparedStatement

使用PreparedStatement来优化上述例子,防止SQL Injection问题:

    private static void login(String name, String pswd) throws Exception {final String mysqlURL = "jdbc:mysql://localhost:3306/xmg?serverTimezone=UTC";final String user = "root";final String password = "root";final String sql = "SELECT * FROM user WHERE name = ? AND pswd = ?";try (Connection connection = DriverManager.getConnection(mysqlURL, user, password);PreparedStatement preparedStatement = connection.prepareStatement(sql);) {preparedStatement.setString(1, name);preparedStatement.setString(2, pswd);ResultSet resultSet = preparedStatement.executeQuery();if (resultSet.next()) {System.out.println("登录成功!");} else {System.out.println("登录失败!");}// ResultSet没法使用try-with-resources// 所以ResultSet需要关闭resultSet.close();}}

参考

李明杰: Java从0到架构师②JavaEE技术基石.


本文完,感谢您的关注支持!


【Java从零到架构师第二季】【07】JDBC FOR MySQL相关推荐

  1. 【Java从零到架构师第二季】【14】AJAX

    持续学习&持续更新中- 学习态度:守破离 AJAX 同步请求和异步请求 未学AJAX之前向服务器提交请求的方式 同步和异步 AJAX 什么是AJAX AJAX的常见使用方式 原生 jQuery ...

  2. 【Java从零到架构师第③季】【26】SpringMVC-反射获取方法参数名_SpringMVC是如何获取方法的参数名的

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][26]SpringMVC-反射获取方法参数名_SpringMVC是如何获取方法的参数名的 利用反射获取方法的参数名 直接编译 修 ...

  3. 【Java从零到架构师第③季】【49】会话管理—Token_ehcache

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][49]会话管理-Token_ehcache 基于Cookie.Session 基于Token ehcache 简单使用 项目使用 ...

  4. 【Java从零到架构师第③季】【48】SpringBoot-Swagger

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][48]SpringBoot-Swagger 接口文档-Swagger 基本使用 不使用starter 使用starter(Swa ...

  5. 【Java从零到架构师第③季】【24】SpringMVC-概述_入门

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][24]SpringMVC-概述_入门 Spring.SpringMVC.MyBatis之间的关系 SpringMVC简介 Spr ...

  6. 【Java从零到架构师第③季】【28】SpringMVC-Servlet的URL匹配_path-matching suffix-pattern

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][28]SpringMVC-Servlet的URL匹配_path-matching suffix-pattern Servlet的 ...

  7. 【Java从零到架构师第1季】【并发 Concurrent 03】线程间通信_ReentrantLock_线程池

    持续学习&持续更新中- 守破离 [Java从零到架构师第1季][并发 Concurrent 03]线程间通信_ReentrantLock_线程池 线程间通信 线程间通信-示例 可重入锁Reen ...

  8. 个人总结的一个中高级Java开发工程师或架构师需要掌握的一些技能...

    近三年,其实都是在做一个项目,项目是一个大型的多节点部署的项目,做了好几个版本,中间用到了很多技术和框架, 也用了一些管理工具和敏捷实践.我这里不是来说项目的,因为最近看了一些招聘信息,结合项目中用到 ...

  9. 【Java从0到架构师】Redis 基础 - 数据类型

    Redis 原理与实战 Redis 基础 为什么 Redis 这么快? Redis 安装.启动 Redis 常用配置 Redis 数据类型 通用命令 String - value 可以是字符串.数值. ...

最新文章

  1. 学习ui设计的流程是什么
  2. VTK:图像置换用法实战
  3. 启动tomcat提示The Network Adapter could not establish the connection
  4. CF585E-Present for Vitalik the Philatelist【莫比乌斯反演,狄利克雷前缀和】
  5. 觉得WaitGroup不好用?试试ErrorGroup吧!
  6. 三方协议接收节点不存在_【花开法务】没有保密协议是否意味着员工不存在保密义务?...
  7. 开发中所使用的渠道(统计分析、分享、第三方登录、短信等)
  8. Angular之constructor和ngOnInit差异及适用场景
  9. 工具:帆软FineBI使用指南
  10. 五、hive-1.2.1安装
  11. MacOS与Windows快捷键对照
  12. 国美在线php面试题,国美电器面试经验
  13. 使用栈(非调用)判断该字符串是否中心对称,如 abccba 即为 中心对称 字符串
  14. springboot+vue+elementUI springboot地方废物回收机构管理系统-#毕业设计
  15. Autovue集成全过程
  16. python拟合函数_python拟合函数
  17. 认识Vue源码 (2)-- 手写类Vue框架:Zue
  18. 使用Mailgun WordPress插件增加订户
  19. 使用OpenGL实现场景构建
  20. Oracle Primavera P6 文档管理与文件查看(Autovue及Outsidein)

热门文章

  1. 【译】css动画里的steps()用法详解
  2. Druid后台监控与过滤器
  3. 【Multisim仿真】74LS47译码器驱动共阳数码管显示(0-8)数字显示
  4. 我TM究竟应该选哪个版本的MySQL?!
  5. php7 三元运算 精简
  6. Exception和继承自Exception的RuntimeException区别
  7. 最新!使用Python爬取蓝奏云文件下载直链并下载,支持批量爬取,已封装为函数,可直接使用(含注释、库的使用解释)
  8. 极品工控插件 iocomp 中 iXYPlotX1配置全面解析
  9. python设定字符串长度_python 修改字符串长度_Python 字符串操作
  10. 赵小楼《天道》《遥远的救世主》深度解析(56)芮小丹的“精神绝症”和“心之地狱”