java程序员入行科目一之CRUD轻松入门教程(一)
之前在操作MySQL的时候,都是采用Navicat,或者cmd黑窗口。
无论使用什么方式和MySQL交互,大致步骤是这样的
- 建立连接,需要输入用户名和密码
- 编写SQL语句,和数据库进行交互
这个连接方式不会变,但是现在需要 基于Java语言去和MySQL进行一波

在实际开发中,当用户要对数据进行一些改变的时候,不能通过工具去执行SQL或者直接点来点去修改的,需要用Java语言去进行交互,使用Java会让操作更有效率和准确性。
Java语言为了提供和多种数据库都可以用一样的方式进行交互,Java提供了一个规范,这个规范 JDBC(Java Database Connectivity)
JDBC介绍
什么是JDBC
JDBC就是Java对外提供的一种规范,JDBC的目的就是让Java语言可以和数据库进行交互,完成CRUD。
JDBC的核心思想
JDBC是个规范,Java就对外发布了这个规范,如果各个数据库厂商,想让你的数据库可以和Java进行交互,数据库厂商就需要根据我JDBC的规范去做具体的实现,提供一个驱动(Driver)。

MySQL数据库驱动
这里在课程资料中会提供,如果想自行下载,可以去一个地址搜索。
http://mvnrepository.com
可以直接搜索需要的jar包,只要大版本没问题,正常下载即可

JDBC API
JDBC的API主要掌握4个,了解1个。
| 类型 | 类的全路径 | 描述 |
|---|---|---|
| class | java.sql.DriverManager | 管理数据库的驱动类,需要基于他来获取到Connection连接对象 |
| interface | java.sql.Connection | 代表一个和数据库的连接,通过他获取到Statement发送SQL |
| interface | java.sql.Statement | 将SQL语句发送给数据库服务端 |
| interface | java.sql.ResultSet | 数据库服务端执行完毕SQL后的返回结果 |
| class | java.sql.SQLException | 和数据库交互时,会抛出的异常。 |
JDBC开发步骤
构建项目

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

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

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

编写开发过程
注册驱动
// ### 注册驱动
// 本质就是将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的对象
// ### 获取发送SQL的对象
Statement statement = conn.createStatement();
执行SQL
// ### 执行SQL
String sql = "insert into account (id,name,money) values (5,'赵六',9999)";
int count = statement.executeUpdate(sql);
处理结果
// ### 处理结果
if(count == 1){System.out.println("当前操作成功!");
}
释放资源
// 释放资源
statement.close();
conn.close();
完整操作
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();}}
常见错误


ResultSet结果集
ResultSet操作
前面操作是针对增删改,返回结果是几行受影响,就是一个int类型的数值。
现在需要玩一波查询操作,而查询操作,返回的就是一个虚拟表。
直接查询之前test库中的account表
首先在执行查询的select的SQL语句时,需要使用的是statement提供的executeQuery方法。
其次,在执行executeQuery方法后,返回的是一个ResultSet结果集,他相当你查询的数据内容。
再有就是针对ResultSet的操作。首先要记住ResultSet的next方法。
next方法类似一个指针,你每次next,指针都会移动到下一行。如果下一行有数据,next方法会返回true,如果下一行没数据,next方法会返回false。
Ps:ResultSet第一次执行next,指针才会指向第一行。
在指针指向某一个行之后,可以再基于ResultSet提供的getXxx方法获取对应列的数据,获取对应列的方式,可以通过序号来找,从1开始,但是 推荐使用列名去找具体数据 。
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();}
}
常见错误

综合案例
完成一个注册登录的小案例。
准备表
创建一张用户表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集合中。
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注入 。

SQL注入是一个很经典的问题。 由于编写的SQL语句是在用户输入数据,整合后再进行编译的。所以为了避免SQL注入的问题,咱们要使SQL语句在用户输入数据前,就已经编译完成了完整的SQL语句,再进行填充数据。
PreparedStatement
PreparedStatement实现了Statement接口,执行SQL语句的方法,和最开始使用的Statement对象是一样的。
之前通过createStatement方法获取到的是
public class StatementImpl现在需要使用到的是,PreparedStatement的实现类
public interface PreparedStatement咱们也在PreparedStatement接口上的注释信息看到了基本的使用方式
将SQL语句中需要咱们填充的值,采用?代替,然后再通过PreparedStatement对象的setXxx方法,通过从1开始的索引位置,给每个?赋值。
PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES SET SALARY = ? WHERE ID = ?"); pstmt.setBigDecimal(1, 153833.00) pstmt.setInt(2, 110592)
将前面的综合案例修改为使用PreparedStatement对象来解决之前的问题
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();}}}
}
相关文章:
java程序员入行科目一之CRUD轻松入门教程(一)
之前在操作MySQL的时候,都是采用Navicat,或者cmd黑窗口。 无论使用什么方式和MySQL交互,大致步骤是这样的 建立连接,需要输入用户名和密码编写SQL语句,和数据库进行交互 这个连接方式不会变,但是现在需要 基…...
OpenHarmony鸿蒙开发( Beta5.0)智能油烟机开发实践
样例简介 本Demo是基于Hi3516开发板,使用开源OpenHarmony开发的应用。本应用主要功能有: 可以搜索本地指定目录的图片和视频文件,并可进行点击播放。 可以通过wifi接收来自手机的美食图片以及菜谱视频,让我们对美食可以边学边做…...
【GBase 8c V5_3.0.0 分布式数据库常用维护命令】
一、查看数据库状态/检查(gbase用户) 1.gha_ctl monitor 使用gha_ctl monitor查看节点运行情况(跟dcs的地址和端口) gha_ctl monitor -c gbase -l http://172.20.10.8:2379 -Hall |coordinator | datanode | gtm | server|dcs:必选字段。指定查看哪类集…...
破解AI生成检测:如何用ChatGPT降低论文的AIGC率
学境思源,一键生成论文初稿: AcademicIdeas - 学境思源AI论文写作 降低论文的“AIGC率”是个挑战,但有一些策略可以尝试。使用ChatGPT逐步调整和改进内容,使其更加自然和原创,降低AI检测工具识别出高“AIGC率”的概率…...
Python用MarkovRNN马尔可夫递归神经网络建模序列数据t-SNE可视化研究
原文链接:https://tecdat.cn/?p37634 本文聚焦于利用马尔可夫递归神经网络(MarkovRNN)结合树库展开建模工作。MarkovRNN 通过整合马尔可夫特性与离散随机变量来深入探索递归神经网络中的随机转换机制,旨在高效处理具有复杂潜在信…...
setup函数子传父普通写法
父组件 <template><div><p>接收的数据: {{ receivedData }}</p><Demo4Chiren2 custom-event"handleGetWeb" /></div> </template><script> import { ref } from vue; import Demo4Chiren2 from ./demo4Chiren2.vue…...
seafaring靶场漏洞测试攻略
步骤一:打开网页 一:sql注入漏洞 步骤一:测试回显点 -1 union select 1,2,3# 步骤二:查看数据库 -1 union select 1,2,database()# 步骤三:查看表名 -1 union select 1,2,group_concat(table_name) from informati…...
简单示例,搞懂PowerBI的ALL(),ALLEXCEPT()和ALLSELECTED()的区别
假设我们有如下数据,我们来统计下各班级的人数 我们在报表页里加上 班级’二班‘ 的筛选条件,此时PowerBI已经自动为我们显示了各班级人数:一班有3人,二班有1人。 根据我们的筛选条件,我们的统计人数应该是按照筛选器&…...
Collection
java.util.Collections:是集合工具类 作用:Collections不是集合,而是集合的工具类 常用API addAll package Collections;import java.util.ArrayList; import java.util.Collections;public class CollectionsDemo {public static void main(String[]…...
19章 泛型
1.修改程序清单19-1中的GenericStack类,使用数组而不是ArrayList来实现它。你应该在给栈添加新元素之前检查数组的大小如果数组满了,就创建一个新数组。该数组是当前数组大小的两倍,然后将当前数组的元素复制到新数组中。 public class Gene…...
基于python+django+mysql+Nanodet检测模型的水稻虫害检测系统
博主介绍: 大家好,本人精通Java、Python、C#、C、C编程语言,同时也熟练掌握微信小程序、Php和Android等技术,能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验,能够为学生提供各类…...
计算机网络27、28——Linux命令1、2
1、虚拟机网络前方路径内容 用户名机器名:/$ $表示普通用户,#表示root用户 2、Linux不分盘,都是绝对路径 /表示根目录,表示计算机文件夹下 ~是当前用户的家,表示home文件夹下自己的文件夹 3、bin文件夹下的是可执…...
【Python深度学习】逆强化学习(IRL):通俗揭开学习背后的奥秘
逆强化学习:揭开学习背后的奥秘 1. 引言 当我们谈论人工智能(AI)时,很多人第一时间会想到强化学习。强化学习是一种让智能体通过与环境的互动,逐渐学习到如何做出最优决策的学习方法。然而,有一种更加神奇的学习方式叫做 逆强化学习(Inverse Reinforcement Learning,…...
Linux:五种IO模型
1:五种IO模型 1:阻塞IO 阻塞IO: 在内核将数据准备好之前,系统调用会一直等待.所有的套接字,默认 都是阻塞方式。 2:非阻塞 IO 非阻塞 IO: 如果内核还未将数据准备好, 系统调用仍然会直接返回, 并且返回EWOULDBLOCK 错误码。 非阻塞 IO 往往需…...
ansible企业实战
ansible最佳实践 优化ansible速度 开启SSH长连接 修改 /etc/ansible/ansible.cfg里面的参数 ssh_args -C -o ControlMasterauto -o ControlPersist5d ControlPersist5d这个参数是设置整个长连接保持时间设置为5天,如果开启,通过SSH连接过的设备都会…...
面向对象程序设计之模板进阶(C++)
在之前我出过一篇博客介绍了模版的初阶:面向对象程序设计(C)模版初阶,接下来我们将进行模版的进阶学习,介绍关于更多模版的知识 1.非类型模版参数 模板参数分类类型形参与非类型形参 类型形参即:出现在模板参数列表中,跟在class或…...
电巢科技携Ecosmos元宇宙产品亮相第25届中国光博会
第25届中国国际光电博览会(“CIOE中国光博会”)今日在深圳国际会展中心盛大开幕。本届博览会以“光电引领未来,驱动应用创新”为主题,吸引了全球超过3700家优质光电企业参展,展示了光电产业的最新成果和前沿技术。 电…...
Redis 入门 - 收官
《Redis 入门》系列文章总算完成了,希望这个系列文章可以想入门或刚入门的同学提供帮助,希望能让你形成学习Redis系统性概念。 当时为什么要写这个系列文章,是因为我自己就是迷迷糊糊一路踩坑走过来的,我踩完的坑就踩完了&#x…...
Windows技术栈企业基础底座(1)-为基于Windows的Nginx安装证书
企业的基础环境是一个组织的信息化数字化底座。传统企业基础环境多种系统,应用交杂,多种技术栈使得深入运维成本极大,且人员知识技能较难复用,造成资源浪费。本系列旨在尝试推动这一理念, 建立Windows, 或linux聚焦的技术栈的企业…...
ThreeJS入门(002):学习思维路径
查看本专栏目录 - 本文是第 002篇入门文章 文章目录 如何使用这个思维导图 Three.js 学习思维导图可以帮助你系统地了解 Three.js 的各个组成部分及其关系。下面是一个简化的 Three.js 学习路径思维导图概述,它包含了学习 Three.js 的主要概念和组件。你可以根据这个…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
怎么开发一个网络协议模块(C语言框架)之(六) ——通用对象池总结(核心)
+---------------------------+ | operEntryTbl[] | ← 操作对象池 (对象数组) +---------------------------+ | 0 | 1 | 2 | ... | N-1 | +---------------------------+↓ 初始化时全部加入 +------------------------+ +-------------------------+ | …...

