之前在操作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();}}}
}