java程序员入行科目一之CRUD轻松入门教程(一)

news/2024/9/19 10:55:48/ 标签: java, 架构, mysql

之前在操作MySQL的时候,都是采用Navicat,或者cmd黑窗口。

无论使用什么方式和MySQL交互,大致步骤是这样的

  • 建立连接,需要输入用户名和密码
  • 编写SQL语句,和数据库进行交互

这个连接方式不会变,但是现在需要 基于Java语言去和MySQL进行一波

image.png

在实际开发中,当用户要对数据进行一些改变的时候,不能通过工具去执行SQL或者直接点来点去修改的,需要用Java语言去进行交互,使用Java会让操作更有效率和准确性。

Java语言为了提供和多种数据库都可以用一样的方式进行交互,Java提供了一个规范,这个规范 JDBC(Java Database Connectivity)

JDBC介绍

什么是JDBC

JDBC就是Java对外提供的一种规范,JDBC的目的就是让Java语言可以和数据库进行交互,完成CRUD。

JDBC的核心思想

JDBC是个规范,Java就对外发布了这个规范,如果各个数据库厂商,想让你的数据库可以和Java进行交互,数据库厂商就需要根据我JDBC的规范去做具体的实现,提供一个驱动(Driver)。

image.png

MySQL数据库驱动

这里在课程资料中会提供,如果想自行下载,可以去一个地址搜索。

http://mvnrepository.com

可以直接搜索需要的jar包,只要大版本没问题,正常下载即可

image.png

JDBC API

JDBC的API主要掌握4个,了解1个。

类型类的全路径描述
classjava.sql.DriverManager管理数据库的驱动类,需要基于他来获取到Connection连接对象
interfacejava.sql.Connection代表一个和数据库的连接,通过他获取到Statement发送SQL
interfacejava.sql.Statement将SQL语句发送给数据库服务端
interfacejava.sql.ResultSet数据库服务端执行完毕SQL后的返回结果
classjava.sql.SQLException和数据库交互时,会抛出的异常。

JDBC开发步骤

构建项目

image.png

导入依赖

第一步,先将jar文件copy到项目的所在目录下。

image.png

第二步,需要将这个jar包添加到工程中。

image.png

第三步,随便搞一个测试类,看一下Driver类有没有MySQL提供的驱动

image.png

编写开发过程

注册驱动

java">//        ###  注册驱动
// 本质就是将Driver类构建好对象并且封装好,将封装好的Driver对象扔到DriverManager类中的一个List集合中
Class.forName("com.mysql.cj.jdbc.Driver");

建立连接

java">//        ###  建立连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?characterEncoding=utf-8",
"root","root");

获取发送SQL的对象

java">//        ###  获取发送SQL的对象
Statement statement = conn.createStatement();

执行SQL

java">//        ###  执行SQL
String sql = "insert into account (id,name,money) values (5,'赵六',9999)";
int count = statement.executeUpdate(sql);

处理结果

java">//        ###  处理结果
if(count == 1){System.out.println("当前操作成功!");
}

释放资源

java">//      释放资源
statement.close();
conn.close();

完整操作

java">package com.jimihua;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;/*** 在当前类中完成最基本的和MySQL交互。* 完成一个添加操作。*/
public class Demo1 {public static void main(String[] args) throws ClassNotFoundException, SQLException {
//        ###  注册驱动
// 本质就是将Driver类构建好对象并且封装好,将封装好的Driver对象扔到DriverManager类中的一个List集合中Class.forName("com.mysql.cj.jdbc.Driver");//        ###  建立连接Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?characterEncoding=utf-8","root", "root");//        ###  获取发送SQL的对象Statement statement = conn.createStatement();//        ###  执行SQLString sql = "insert into account (id,name,money) values (5,'赵六',9999)";int count = statement.executeUpdate(sql);//        ###  处理结果if (count == 1) {System.out.println("当前操作成功!");}
//        ### 3.3.6 释放资源statement.close();conn.close();}}

常见错误

image.png


image.png


image.pngResultSet结果集

ResultSet操作

前面操作是针对增删改,返回结果是几行受影响,就是一个int类型的数值。

现在需要玩一波查询操作,而查询操作,返回的就是一个虚拟表。

直接查询之前test库中的account表

首先在执行查询的select的SQL语句时,需要使用的是statement提供的executeQuery方法。

其次,在执行executeQuery方法后,返回的是一个ResultSet结果集,他相当你查询的数据内容。

image.png

再有就是针对ResultSet的操作。首先要记住ResultSet的next方法。

next方法类似一个指针,你每次next,指针都会移动到下一行。如果下一行有数据,next方法会返回true,如果下一行没数据,next方法会返回false。

Ps:ResultSet第一次执行next,指针才会指向第一行。

在指针指向某一个行之后,可以再基于ResultSet提供的getXxx方法获取对应列的数据,获取对应列的方式,可以通过序号来找,从1开始,但是 推荐使用列名去找具体数据

java">package com.jimihua;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;/*** 查询account表,获取返回的结果集ResultSet*/
public class Demo2 {public static void main(String[] args) throws Exception {//1、注册驱动Class.forName("com.mysql.cj.jdbc.Driver");//2、获取连接Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8","root","root");//3、获取StatementStatement statement = conn.createStatement();//4、执行查询的SQLString sql = "select * from account";ResultSet rs = statement.executeQuery(sql);//5、操作ResultSet结果集//5.1 先用ResultSet的一个next方法确认是否有返回的数据while(rs.next()){// 如果进到while循环,说明有数据// 5.2 基于ResultSet提供的get类型方法去获取结果long id = rs.getLong("id");String name = rs.getString("name");long money = rs.getLong("money");System.out.println("获取数据:" + id + "," + name + "," + money + "。");}// 到这,说明指针已经到最后了,没有数据了。//6、释放资源rs.close();statement.close();conn.close();}
}

常见错误

image.png

综合案例

完成一个注册登录的小案例。

准备表

创建一张用户表user

  • id,数值类型,主键,自增
  • username,用户名,字符串类型,唯一,非空
  • password,密码,字符串类型,非空
create table user(id bigint primary key auto_increment comment '主键id',username varchar(32) unique not null comment '用户名',password varchar(32) not null comment '密码'
)comment '用户表';

查询2条测试数据

insert into user values (1,'admin','admin'),(2,'zhangsan','123456');

实现注册和登录操作

注册驱动这个事情,只需要做一次就足够了。

注册驱动的本质就是将MySQL的Driver对象存放到DriverManager中的一个List集合中。

java">package com.jimihua;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;/***  实现注册和登录操作*/
public class Demo3 {public static void main(String[] args) throws Exception {// 因为注册驱动的操作,做一次就够了,他就是将Driver的对象扔到DriverManager的一个List集合中Class.forName("com.mysql.cj.jdbc.Driver");Scanner input = new Scanner(System.in);while(true){// 基于提示,做具体什么操作System.out.println("当前可以选择注册或者登录");System.out.println("注册操作输入 1");System.out.println("登录操作输入 2");int i = input.nextInt();// 因为无论是注册还是登录,都需要用户输入用户名和密码System.out.println("请输入用户名:");String username = input.next();System.out.println("请输入密码:");String password = input.next();// 根据i执行不同的逻辑if(i == 1){// 注册操作//1、获取链接Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_test?characterEncoding=UTF-8", "root", "root");//2、拿到statementStatement statement = conn.createStatement();//3、准备注册的insert的SQLString sql = "insert into user (username,password) values ('"+username+"','"+password+"');";System.out.println("注册要执行的SQL:" + sql);//4、执行SQLint count = statement.executeUpdate(sql);//5、根据返回结果基于提示if(count == 1){System.out.println("注册成功!!");}//6、释放资源statement.close();conn.close();}else {// 登录操作//1、获取链接Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_test?characterEncoding=UTF-8", "root", "root");//2、拿到statementStatement statement = conn.createStatement();//3、准备登录的查询SQLString sql = "select * from user where username='"+username+"' and password='"+password+"';";System.out.println("登录要执行的SQL:" + sql);//4、执行SQLResultSet resultSet = statement.executeQuery(sql);if (resultSet.next()){// 到这,说明用户名和密码正确,登录成功!System.out.println("用户名和密码正确,登录成功!");}else{// 到这,说明用户名和密码错误,登录失败!System.out.println("用户名和密码错误,登录失败!");}//5、释放资源resultSet.close();statement.close();conn.close();}}}
}

SQL注入问题

问题介绍

用户输入的数据中有SQL关键字或者语法,并且这些内容参与了SQL语句的编译,导致SQL语句编译后的条件含义为true,一致得到正确的结果,你输入的内容其实不是正确的。这种现象就成为 SQL注入

image.png

SQL注入是一个很经典的问题。 由于编写的SQL语句是在用户输入数据,整合后再进行编译的。所以为了避免SQL注入的问题,咱们要使SQL语句在用户输入数据前,就已经编译完成了完整的SQL语句,再进行填充数据。

PreparedStatement

PreparedStatement实现了Statement接口,执行SQL语句的方法,和最开始使用的Statement对象是一样的。

之前通过createStatement方法获取到的是

java">public class StatementImpl

现在需要使用到的是,PreparedStatement的实现类

java">public interface PreparedStatement

咱们也在PreparedStatement接口上的注释信息看到了基本的使用方式

将SQL语句中需要咱们填充的值,采用?代替,然后再通过PreparedStatement对象的setXxx方法,通过从1开始的索引位置,给每个?赋值。

java">PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES SET SALARY = ? WHERE ID = ?");
pstmt.setBigDecimal(1, 153833.00)
pstmt.setInt(2, 110592)

将前面的综合案例修改为使用PreparedStatement对象来解决之前的问题

java">package com.jimihua;
import java.sql.*;
import java.util.Scanner;/***  实现注册和登录操作*  基于SQL注入的问题,在这里采用PreparedStatement来解决SQL注入问题。*/
public class Demo4 {public static void main(String[] args) throws Exception {// 因为注册驱动的操作,做一次就够了,他就是将Driver的对象扔到DriverManager的一个List集合中Class.forName("com.mysql.cj.jdbc.Driver");Scanner input = new Scanner(System.in);while(true){// 基于提示,做具体什么操作System.out.println("当前可以选择注册或者登录");System.out.println("注册操作输入 1");System.out.println("登录操作输入 2");int i = input.nextInt();// 因为无论是注册还是登录,都需要用户输入用户名和密码System.out.println("请输入用户名:");String username = input.next();System.out.println("请输入密码:");String password = input.next();// 根据i执行不同的逻辑if(i == 1){// 注册操作//1、获取链接Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_test?characterEncoding=UTF-8", "root", "root");//2、准备注册的insert的SQLString sql = "insert into user (username,password) values (?,?)";//3.1、拿到statementPreparedStatement ps = conn.prepareStatement(sql);//3.2 给占位符?赋值ps.setString(1,username);ps.setString(2,password);//4、执行SQLint count = ps.executeUpdate();//5、根据返回结果基于提示if(count == 1){System.out.println("注册成功!!");}//6、释放资源ps.close();conn.close();}else {// 登录操作//1、获取链接Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_test?characterEncoding=UTF-8", "root", "root");//2、准备登录的查询SQLString sql = "select * from user where username = ? and password = ?";//3.1、拿到statementPreparedStatement ps = conn.prepareStatement(sql);//3.2、给?赋值ps.setString(1,username);ps.setString(2,password);//4、执行SQLResultSet resultSet = ps.executeQuery();if (resultSet.next()){// 到这,说明用户名和密码正确,登录成功!System.out.println("用户名和密码正确,登录成功!");}else{// 到这,说明用户名和密码错误,登录失败!System.out.println("用户名和密码错误,登录失败!");}//5、释放资源resultSet.close();ps.close();conn.close();}}}
}

http://www.ppmy.cn/news/1527103.html

相关文章

JVM程序计数器

JVM的程序计数器是线程私有的内存区域,它记录着当前线程执行的字节码指令地址,是Java虚拟机中至关重要的组件,确保多线程环境下程序的正确执行与流畅切换。其重要性不容忽视,是Java程序高效、稳定运行的基石。 一、程序计数器介绍…

敲击键盘到屏幕上打印字符计算机都做了什么

当你在 Linux 系统上按下键盘的 x 键并看到屏幕上打印出字母 x 时,Linux 系统内部发生了很多过事情,涉及硬件、操作系统内核和用户空间的多个层次。下面是一个大致的流程: 1. 硬件层 键盘硬件捕获按键:当你按下 x 键&#xff0c…

学成在线练习(HTML+CSS)

准备工作 项目目录 内部包含当前网站的所有素材,包含 HTML、CSS、图片、JavaScript等等 1.由于元素具有一些默认样式,可能是我们写网页过程中根本不需要的,所有我们可以在写代码之前就将其清除 base.css /* 基础公共样式:清除…

【PostgreSQL里vacuum但是无法回收死元组的原因】

PostgreSQL数据库里的vacuum/autvacuum在我们日长的使用中可能会遇到很多问题,例如vacuum被阻塞,vacuum时间长,vacuum成功执行后,仍旧无法回收死元组等等。,本文主要介绍PostgreSQL的vacuum成功执行后,仍旧…

力扣100题——动态规划(二)

单词划分 题目 139. 单词拆分 - 力扣&#xff08;LeetCode&#xff09; 思路 使用dp数组记录当前下标对应的字符串长度能否被正确划分 确定状态转移方程&#xff0c;当j<i时&#xff0c;d[i] d[j]&&wordDict.contains(s.substring(j, i)) 代码 public boole…

C++——多线程编程(从入门到放弃)

进程&#xff1a;运行中的程序 线程&#xff1a;进程中的进程 线程的最大数量取决于CPU的核心数 一、将两个函数添加到不同线程中 demo&#xff1a;两个函数test01()和test02()&#xff0c;实现将用户输入的参数进行打印输出1000次 将这两个函数均放到独立的线程t1和t2中&…

代码随想录训练营 Day60打卡 图论part10 SPFA算法 Bellman-Ford 之判断负权回路 Bellman-Ford 之单源有限最短路

代码随想录训练营 Day60打卡 图论part10 一、Bellman_ford 队列优化算法&#xff08;又名SPFA&#xff09; 例题&#xff1a;卡码94. 城市间货物运输 I 题目描述 某国为促进城市间经济交流&#xff0c;决定对货物运输提供补贴。共有 n 个编号为 1 到 n 的城市&#xff0c;通过…

第159天:安全开发-Python-协议库爆破FTPSSHRedisSMTPMYSQL等

案例一: Python-文件传输爆破-ftplib 库操作 ftp 协议 开一个ftp 利用ftp正确登录与失败登录都会有不同的回显 使用ftplib库进行测试 from ftplib import FTP # FTP服务器地址 ftp_server 192.168.172.132 # FTP服务器端口&#xff08;默认为21&#xff09; ftp_po…

深度学习实战电路板缺陷检测【数据集+YOLOv5模型+源码+PyQt5界面】

基于深度学习的电路板缺陷检测- 文章目录 研究背景1. 电路板制造的重要性2. 传统检测方法的局限性3. 深度学习技术的兴起4. 深度学习在缺陷检测中的应用5. 研究进展6. 面临的挑战7. 结论 代码下载链接一、效果演示1.1 图像演示1.2 视频演示1.3 摄像头演示 二、技术原理2.1 整体…

2024年9月HarmonyOS鸿蒙应用开发者高级认证全新题库(覆盖99%考题)

一个小时通过鸿蒙高级认证 1、在开发 Harmony0S 应用工程时&#xff0c; 随着业务的发展&#xff0c;现在需要创建一个模块&#xff0c; 关于在 DevEco Studio 中创建 Module &#xff0c; 下列选项哪种方式是错误的? 必对 在 hvigor 目录下&#xff0c;单击鼠标右键&#xf…

Rust程序结构与代码注释

【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟&#xff0c;李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust编程与项目实战_夏天又到了的博客-CSDN博客 3.1 Rust程序结构 我们从一个最简单的程序入手&#xff0c;来观察一个Rust的程序结…

AD的入门操作

锦囊 1、打开AD后&#xff0c;一般默认打开上一个工程&#xff0c;这个时候如果想要打开新的工程&#xff0c;那就必须要创建一个项目&#xff0c;然后再在项目中添加原理图库和PCB库。 2、大多数情况下&#xff0c;直接使用库&#xff0c;不用自己再画原理图和封装库。 3、…

python压缩图片的代码

从网上复制的&#xff0c;不知道对不对 def compress_image(infile, outfile, mb1500, step10, quality80):"""不改变图片尺寸压缩到指定大小:param infile: 压缩源文件:param outfile: 压缩文件保存地址:param mb: 压缩目标&#xff0c;KB:param step: 每次调…

多层建筑能源参数化模型和城市冠层模型的区别

多层建筑能源参数化&#xff08;Multi-layer Building Energy Parameterization, BEP&#xff09;模型和城市冠层模型&#xff08;Urban Canopy Model, UCM&#xff09;都是用于模拟城市环境中能量交换和微气候的数值模型&#xff0c;但它们的侧重点和应用场景有所不同。以下是…

Ubuntu 下载软件包时,提示 但是它将不会被安装E: 无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系。

解决办法&#xff1a; 打开 软件和更新 先更新一下&#xff1a; sudo apt-get update 接下来再次安装你需要的软件包&#xff0c;例如&#xff1a; sudo apt install libsdl2-dev

【网络安全的神秘世界】渗透测试基础

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 渗透测试基础 基于功能去进行漏洞挖掘 1、编辑器漏洞 1.1 编辑器漏洞介绍 一般企业搭建网站可能采用了通用模板&#xff…

JavaScript 事件处理

一、简介 ​ 事件&#xff1a;发生在HTML元素上的事情&#xff0c;可以是用户的行为&#xff0c;也可以是浏览器的行为&#xff0c;如 用户点击了某个HTML元素用户将鼠标移动到某个HTML元素上用户输入数据时光标离开页面加载完成 ​ 事件源&#xff1a;事件触发的源头&#xf…

C语言 | Leetcode C语言题解之题409题最长回文串

题目&#xff1a; 题解&#xff1a; int longestPalindrome(char * s) {int c[128]{0},ret0;for(int i0;i<strlen(s);i){c[s[i]];}for(int i0;i<128;i){retc[i]-c[i]%2;}return ret(ret!strlen(s)); }

VUE下拉选择分页,远程搜索

实现效果 实现思路 初始化加载第一页&#xff1b;监听下拉框的滚动事件&#xff0c;当滚动到底部的时候加载下一页&#xff1b;输入搜索时&#xff0c;重置为第一页加载&#xff1b;关闭下拉选择框时&#xff0c;判断如果存在搜索值&#xff0c;要清空搜索值、并加载第一页。 …

7天速成前端 ------学习日志 (继苍穹外卖之后)

前端速成计划总结&#xff1a; 全26h课程&#xff0c;包含html&#xff0c;css&#xff0c;js&#xff0c;vue3&#xff0c;预计7天内学完。 起始日期&#xff1a;9.16 预计截止&#xff1a;9.22 每日更新&#xff0c;学完为止。 学前计划 课…