Appearance
二、全新JDBC核心API
1、引入mysql-jdbc驱动jar
驱动jar版本选择
mysql版本 | 推荐驱动版本 | 备注 |
---|---|---|
mysql 5.5.x | 5.0.x | com.mysql.jdbc.Driver |
mysql 5.7.x | 5.1.x | com.mysql.jdbc.Driver |
msyql 8.x | 8.0.x | 建议: 8.0.25+省略时区设置 com.mysql.cj.jdbc.Driver |
2、POM依赖
xml
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
3、jdbc基本使用步骤分析
- 注册驱动
- 获取连接
- 创建发送sql语句对象
- 发送sql语句,并获取返回结果
- 结果集解析
- 资源关闭
4、基于statement实现查询
准备数据库数据
mysql
CREATE DATABASE xx_jdbc;
USE xx_jdbc;
CREATE TABLE t_user(
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户主键',
account VARCHAR(20) NOT NULL UNIQUE COMMENT '账号',
PASSWORD VARCHAR(64) NOT NULL COMMENT '密码',
nickname VARCHAR(20) NOT NULL COMMENT '昵称');
INSERT INTO t_user(account,PASSWORD,nickname) VALUES
('root','123456','技术总监'),('admin','666666','CTO');
java
package com.xx;
import java.sql.*;
/**
* @Author: xueqimiao
* @Date: 2023/1/4 09:14
*/
public class JdbcBasePart {
public static void main(String[] args) throws SQLException {
//1.注册驱动
/**
* TODO: 注意
* Driver -> com.mysql.cj.jdbc.Driver
*/
DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
//2.获取连接
/**
* 面向接口编程
* java.sql 接口 = 实现类
* connection 使用java.sql.Connection接口接收
*/
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/xx_jdbc",
"root",
"mac_root");
//3.创建小车
Statement statement = connection.createStatement();
//4.发送SQL语句
String sql = "select id,account,password,nickname from t_user ;";
ResultSet resultSet = statement.executeQuery(sql);
//5.结果集解析
while (resultSet.next()) {
int id = resultSet.getInt("id");
String account = resultSet.getString("account");
String password = resultSet.getString("password");
String nickname = resultSet.getString("nickname");
System.out.println(id + "\t" + account + "\t" + password + "\t" + nickname);
}
//6.关闭资源 【先开后关】
resultSet.close();
statement.close();
connection.close();
}
}
5、基于statement方式问题
模拟登录,控制台输入账号和密码,判断是否登陆成功成功!
java
package com.xx;
import java.sql.*;
import java.util.Scanner;
/**
* @Author: xueqimiao
* @Date: 2023/1/4 09:23
*/
public class JdbcStatementLoginPart {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.输入账号和密码
Scanner scanner = new Scanner(System.in);
String account = scanner.nextLine();
String password = scanner.nextLine();
scanner.close();
//2.jdbc的查询使用
/**
* 类加载: java文件 -> 编译 -> 【 class字节码文件 --> 类加载 --> jvm虚拟中 --> Class对象】
* 类加载具体步骤: 加载 【class文件转成对象加载到虚拟机中】->
* 连接 【验证(检查类文件) -> 准备 (静态变量赋默认值) -> 解析 (调用静态代码块) 】 ->
* 初始化 -> (赋真实值)
* 以下7种方式会触发类加载:
* 1. new关键字
* 2. 调用静态属性
* 3. 调用静态方法
* 4. 接口 包含1.8 新特性 default关键字
* 5. 反射 【Class.forName() 类名.class】
* 6. 子类调用会触发父类的静态代码块
* 7. 触发类的入口方法main
*/
//注册一次驱动
Class.forName("com.mysql.cj.jdbc.Driver");
/**
* 重写: 为了子类扩展父类的方法!父类也间接的规范了子类方法的参数和返回!
* 重载: 重载一般应用在第三方的工具类上,为了方便用户多种方式传递参数形式!简化形式!
*/
/**
* 三个参数:
* String URL: 连接数据库地址
* String user: 连接数据库用户名
* String password: 连接数据库用户对应的密码
* 数据库URL语法:
* JDBC:
* ip port
* jdbc:mysql | jdbc:oracle :// 127.0.0.1 | localhost : 3306 / 数据库名
* jdbc:mysql://localhost:3306/xx_jdbc
* 192.168.33.45
* jdbc:mysql://192.168.33.45/3306/xx_jdbc
* 当前电脑的省略写法! 注意:本机和端口3306
* jdbc:mysql://localhost:3306/xx_jdbc = jdbc:mysql:///xx_jdbc
*
* 两个参数:
* String URL : 写法还是jdbc的路径写法!
* Properties : 就是一个参数封装容器!至少要包含 user / password key!存储连接账号信息!
*
* 一个参数:
* String URL: URl可以携带目标地址,可以通过?分割,在后面key=value&key=value形式传递参数
* jdbc:mysql:///xx_jdbc?user=root&password=123456
* 扩展路径参数(了解):
* serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true
*
*/
//获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc", "root", "mac_root");
//固定方法固定剂
//创建statement
Statement statement = connection.createStatement();
//执行SQL语句 [动态SQL语句,需要字符串拼接]
String sql = "select * from t_user where account = '" + account + "' and password = '" + password + "' ;";
/**
* ResultSet 结果集对象 = executeQuery(DQL语句)
* int 响应行数 = executeUpdate(非DQL语句)
*/
ResultSet resultSet = statement.executeQuery(sql);
//ResultSet == 你必须有面向对象的思维:Java是面向对象编程的语言 OOP!
/**
*
* TODO:1.需要理解ResultSet的数据结构和在navicat中查询出来的是一样,需要在脑子里构建结果表!
* TODO:2.有一个光标指向的操作数据行,默认指向第一行的上边!我们需要移动光标,指向行,在获取列即可!
* boolean = next()
* false: 没有数据,也不移动了!
* true: 有更多行,并且移动到下一行!
* 推荐:推荐使用if 或者 while循环,嵌套next方法,循环和判断体内获取数据!
* if(next()){获取列的数据!} || while(next()){获取列的数据!}
*
*TODO:3.获取当前行列的数据!
* get类型(int columnIndex | String columnLabel)
* 列名获取 //lable 如果没有别名,等于列名, 有别名label就是别名,他就是查询结果的标识!
* 列的角标 //从左到右 从1开始! 数据库全是从1开始!
*/
//进行结果集对象解析
if (resultSet.next()) {
//只要向下移动,就是有数据 就是登录成功!
System.out.println("登录成功!");
} else {
System.out.println("登录失败!");
}
//关闭资源
resultSet.close();
statement.close();
connection.close();
}
}
java
admin
666666
登录成功!
admin
123456 'or 1='1
登录成功!
1、存在问题
SQL语句需要字符串拼接,比较麻烦
只能拼接字符串类型,其他的数据库类型无法处理
可能发生注入攻击
动态值充当了SQL语句结构,影响了原有的查询结果!
6、基于preparedStatement方式优化
利用preparedStatement解决上述案例注入攻击和SQL语句拼接问题!
java
package com.xx;
import java.sql.*;
import java.util.Scanner;
/**
* @Author: xueqimiao
* @Date: 2023/1/4 09:30
*/
public class JdbcPreparedStatementLoginPart {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.输入账号和密码
Scanner scanner = new Scanner(System.in);
String account = scanner.nextLine();
String password = scanner.nextLine();
scanner.close();
//2.jdbc的查询使用
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc", "root", "mac_root");
//创建preparedStatement
//connection.createStatement();
//TODO 需要传入SQL语句结构
//TODO 要的是SQL语句结构,动态值的部分使用 ? , 占位符!
//TODO ? 不能加 '?' ? 只能替代值,不能替代关键字和容器名
String sql = "select * from t_user where account = ? and password = ? ;";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//占位符赋值
//给占位符赋值! 从左到右,从1开始!
/**
* int 占位符的下角标
* object 占位符的值
*/
preparedStatement.setObject(2, password);
preparedStatement.setObject(1, account);
//这哥们内部完成SQL语句拼接!
//执行SQL语句即可
ResultSet resultSet = preparedStatement.executeQuery();
//preparedStatement.executeUpdate()
//进行结果集对象解析
if (resultSet.next()) {
//只要向下移动,就是有数据 就是登录成功!
System.out.println("登录成功!");
} else {
System.out.println("登录失败!");
}
//关闭资源
resultSet.close();
preparedStatement.close();
connection.close();
}
}
7、基于preparedStatement增删改查
1、新增
java
/**
* 插入一条用户数据!
* 账号: test
* 密码: test
* 昵称: 测试
*/
@Test
public void testInsert() throws Exception {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc", "root", "mac_root");
//TODO: 切记, ? 只能代替 值!!!!! 不能代替关键字 特殊符号 容器名
String sql = "insert into t_user(account,password,nickname) values (?,?,?);";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//占位符赋值
preparedStatement.setString(1, "test");
preparedStatement.setString(2, "test");
preparedStatement.setString(3, "测试");
//发送SQL语句
int rows = preparedStatement.executeUpdate();
//输出结果
System.out.println(rows);
//关闭资源close
preparedStatement.close();
connection.close();
}
2、修改
java
/**
* 修改一条用户数据!
* 修改账号: test的用户,将nickname改为tomcat
*/
@Test
public void testUpdate() throws Exception {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc", "root", "mac_root");
//TODO: 切记, ? 只能代替 值!!!!! 不能代替关键字 特殊符号 容器名
String sql = "update t_user set nickname = ? where account = ? ;";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//占位符赋值
preparedStatement.setString(1, "tomcat");
preparedStatement.setString(2, "test");
//发送SQL语句
int rows = preparedStatement.executeUpdate();
//输出结果
System.out.println(rows);
//关闭资源close
preparedStatement.close();
connection.close();
}
3、删除
java
/**
* 删除一条用户数据!
* 根据账号: test
*/
@Test
public void testDelete() throws Exception {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc", "root", "mac_root");
//TODO: 切记, ? 只能代替 值!!!!! 不能代替关键字 特殊符号 容器名
String sql = "delete from t_user where account = ? ;";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//占位符赋值
preparedStatement.setString(1, "test");
//发送SQL语句
int rows = preparedStatement.executeUpdate();
//输出结果
System.out.println(rows);
//关闭资源close
preparedStatement.close();
connection.close();
}
4、查询
java
/**
* 查询全部数据!
* 将数据存到List<Map>中
* map -> 对应一行数据
* map key -> 数据库列名或者别名
* map value -> 数据库列的值
* 1.先创建一个List<Map>集合
* 2.遍历resultSet对象的行数据
* 3.将每一行数据存储到一个map对象中!
* 4.将对象存到List<Map>中
* 5.最终返回
* <p>
* 学习获取结果表头信息(列名和数量等信息)
*/
@Test
public void testQueryMap() throws Exception {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc", "root", "mac_root");
//TODO: 切记, ? 只能代替 值!!!!! 不能代替关键字 特殊符号 容器名
String sql = "select id,account,password,nickname from t_user ;";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//占位符赋值 本次没有占位符,省略
//发送查询语句
ResultSet resultSet = preparedStatement.executeQuery();
//创建一个集合
List<Map> mapList = new ArrayList<>();
//获取列信息对象
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
while (resultSet.next()) {
Map map = new HashMap();
for (int i = 1; i <= columnCount; i++) {
map.put(metaData.getColumnLabel(i), resultSet.getObject(i));
}
mapList.add(map);
}
System.out.println(mapList);
//关闭资源close
preparedStatement.close();
connection.close();
resultSet.close();
}