JDBC p2 JDBC API
JDBC API
获取数据库连接5种方式
- 通过new创建Driver对象;
- 使用反射加载Driver类,动态加载,减少依赖性,更加灵活;
- 使用DriverManager 替代 Driver 进行统一管理,有了更好的扩展性;
- 使用 Class.forName 自动完成注册驱动,简化代码;
- 在方式4的基础上改进,增加配置文件,让mysql连接更灵活,最推荐使用;
代码演示:
package com.hspedu.jdbc;
import com.mysql.jdbc.Driver;
import org.junit.jupiter.api.Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
/**
* 分析java连接mysql的5种方式
*/
public class JdbcConn {
//方式1
@Test
public void connect01() throws SQLException {
Driver driver = new Driver();
String url = "jdbc:mysql://localhost:3306/jdbc_learning";
Properties properties = new Properties();
properties.setProperty("user", "root");//用户名
properties.setProperty("password", "root");//密码
Connection connection = driver.connect(url, properties);
System.out.println("第一种方式" + connection);
connection.close();
}
//方式2
@Test
public void connect02() throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
//使用反射加载Driver类,动态加载,减少依赖性,更加灵活
Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) aClass.newInstance();
String url = "jdbc:mysql://localhost:3306/jdbc_learning";
Properties properties = new Properties();
properties.setProperty("user", "root");//用户名
properties.setProperty("password", "root");//密码
Connection connection = driver.connect(url, properties);
System.out.println("第二种方式" + connection);
connection.close();
}
//方式3 使用DriverManager 替代 Driver 进行统一管理,有了更好的扩展性
@Test
public void connect03() throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
//使用反射加载Driver类
Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) aClass.newInstance();
String url = "jdbc:mysql://localhost:3306/jdbc_learning";
String user = "root";
String password = "root";
DriverManager.registerDriver(driver);//注册Driver驱动,DriverManager是Java自带的类
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println("第三种方式" + connection);
}
//方式4 使用 Class.forName 自动完成注册驱动,简化代码
//这种方式推荐使用,使用最多
@Test
public void connect04() throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
//使用反射加载Driver类
//在加载 Driver类时,完成注册
/*
源码:1. 静态代码块,在类加载时,会执行一次
2. 因此注册driver的工作在底层已经完成了
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
*/
//1.mysqL驱动5.1.6可以无需CLass.forName("com.mysql.jdbc.Driver");
//2.从jdk1.5以后使用了jdbc4,不再需要显示调用class.forName()注册驱动而是自动调用驱动
//jar包下META-INF\services\java.sql.Driver文本中的类名称去注册
//3.建议还是写上CLass.forName("com.mysql.jdbc.Driver"),更加明确
Class.forName("com.mysql.jdbc.Driver");//内部有一段静态代码会默认自动注册
String url = "jdbc:mysql://localhost:3306/jdbc_learning";
String user = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println("第四种方式" + connection);
}
//方式5 在方式4的基础上改进,增加配置文件,让mysql连接更灵活,最推荐使用
@Test
public void connect05() throws IOException, ClassNotFoundException, SQLException {
//通过Properties对象获取配置文件的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
//获取相关的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
Class.forName(driver);//建议写上
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println("第五种方式" + connection);
}
}
配置文件mysql.properties:
user=root
password=zyl
url=jdbc:mysql://localhost:3306/jdbc_learning
driver=com.mysql.jdbc.Driver
ResultSet[结果集]
-
基本介绍
- 表示数据库结果集的数据表,通常通过执行查询数据库的语句生成;
- ResultSet对象保持一个光标指向其当前的数据行。最初,光标位于第一行前;
- next方法将光标移动到下一行,并且由于在ResultSet对象中没有更多行时返回false,因此可以在while循环中使用循环来遍历结果集。
-
代码演示:
package com.hspedu.jdbc.resultset_; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.sql.*; import java.util.Properties; /** * @author: 86199 * @date: 2023/6/14 21:52 * Description: 演示select 语句 返回 ResultSet,并取出结果 */ @SuppressWarnings({"all"}) public class ResultSet_ { public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException { //通过Properties对象获取配置文件的信息 Properties properties = new Properties(); properties.load(new FileInputStream("src\\mysql.properties")); //获取相关的值 String user = properties.getProperty("user"); String password = properties.getProperty("password"); String driver = properties.getProperty("driver"); String url = properties.getProperty("url"); //1. 注册驱动 Class.forName(driver);//建议写上 //2. 得到连接 Connection connection = DriverManager.getConnection(url, user, password); //3. 得到Statement Statement statement = connection.createStatement(); //组织sql语句 String sql = "select id, name, sex, borndate from actor;"; /* 1 周星驰 男 1970-11-11 00:00:00 110 2 刘德华 男 1970-11-11 00:00:00 110 3 刘德华 男 1970-11-11 00:00:00 110 */ //执行给定的SQL语句,该语句返回单个ResultSet对象 /* 源码: */ ResultSet resultSet = statement.executeQuery(sql); while (resultSet.next()) {//让光标后移,如果没有更多行,则返回false int id = resultSet.getInt(1);//获取该行的第1列 String name = resultSet.getString(2);//获取该行的第2列 String sex = resultSet.getString(3); String date = resultSet.getString(4); System.out.println(id + "\t" + name + "\t" + sex + "\t" + date); } //关闭资源 resultSet.close(); statement.close(); connection.close(); } }
## Statement对象
- **基本介绍**
1. Statement对象,用于执行静态SQL语句并返回其生成的结果的对象。
2. 在连接建立之后,需要对数据库进行访问,执行命名或是SQL语句,可以通过
- Statement [存在SQL注入]
- ==PreparedStatement==(预处理)
- CallableStatement(存储过程)
3. Statement对象执行SQL语句存在==SQL注入==的风险
- **SQL注入**是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令,恶意攻击数据库。
- 要防范 SQL注入,只要用 **PreparedStatement**(从Statement扩展而来)取代 Statement 就可以了。
**MySQL代码:**
```mysql
-- 演示sql注入
-- 创建一张表
CREATE TABLE admin ( -- 管理员表
`name` VARCHAR(32) NOT NULL UNIQUE,
pwd VARCHAR(32) NOT NULL DEFAULT '') CHARACTER SET utf8;
-- 添加数据
INSERT INTO admin VALUES('jac', '123');
-- 查找某个管理员是否存在
SELECT *
FROM admin
WHERE `name` = 'tom' AND pwd = '123';
-- SQL注入
-- 输入用户名 1' or
-- 输入密码 为 or '1' = '1
-- SELECT *
-- FROM admin
-- WHERE `name` = '' AND pwd = '';
SELECT *
FROM admin
WHERE `name` = '1' or' AND pwd = 'or '1' = '1';
Java代码:
package com.hspedu.jdbc.statement_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;
/**
* @author: 86199
* @date: 2023/6/15 22:24
* Description: 演示 SQL注入的问题
*/
public class Statement_ {
public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
Scanner scanner = new Scanner(System.in);
//让用户输入管理员用户名和密码
System.out.print("请输入管理员名字:");
String admin_name = scanner.nextLine();
System.out.print("请输入管理员密码:");
String admin_pwd = scanner.nextLine();
//通过Properties对象获取配置文件的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
//获取相关的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
//1. 注册驱动
Class.forName(driver);//建议写上
//2. 得到连接
Connection connection = DriverManager.getConnection(url, user, password);
//3. 得到Statement
Statement statement = connection.createStatement();
//组织sql语句
String sql = "SELECT name, pwd FROM admin where name = '"
+ admin_name + "' and pwd = '" + admin_pwd + "';";
ResultSet resultSet = statement.executeQuery(sql);
if (resultSet.next()) {//如果查询到一条记录,说明该管理员存在
System.out.println("恭喜,登录成功");
}else{
System.out.println("对不起,登录失败");
}
resultSet.close();
statement.close();
connection.close();
}
}
//运行
/*
请输入管理员名字:1' or
请输入管理员密码:or '1' = '1
恭喜,登录成功
*/
预处理(查询和修改)
- PreparedStatement 执行的SQL语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数。setXxx() 方法有两个参数,第一个参数都是int,要设置SQL语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值。
- 调用 executeQuery(),返回 ResultSet 对象。
- 调用 executeUpdate():执行更新,包括增,删,修改
package com.hspedu.jdbc.preparedstatement_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;
/**
* @author: 86199
* @date: 2023/7/17 20:43
* Description: 演示PreparedStatement使用
*/
public class PreparedStatement_ {
public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
Scanner scanner = new Scanner(System.in);
//让用户输入管理员用户名和密码
System.out.print("请输入管理员名字:");
String admin_name = scanner.nextLine();
System.out.print("请输入管理员密码:");
String admin_pwd = scanner.nextLine();
//通过Properties对象获取配置文件的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
//获取相关的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
//1. 注册驱动
Class.forName(driver);//建议写上
//2. 得到连接
Connection connection = DriverManager.getConnection(url, user, password);
//sql中的?就相当于占位符
String sql = "SELECT name, pwd FROM admin where name = ? and pwd = ? ;";
//3. 得到PreparedStatement,这里的statement是实现了PreparedStatement接口的实现类的对象
PreparedStatement statement = connection.prepareStatement(sql);
//给 ? 赋值
statement.setString(1, admin_name);
statement.setString(2, admin_pwd);
//执行sql语句,如果执行的是dml语句要用executeUpdate()
ResultSet resultSet = statement.executeQuery();//()中不能再写sql语句,不然执行的就是带?的,填了sql语句就是调用了父类Statement的方法了
if (resultSet.next()) {//如果查询到一条记录,说明该管理员存在
System.out.println("恭喜,登录成功");
}else{
System.out.println("对不起,登录失败");
}
//关闭链接
resultSet.close();
statement.close();
connection.close();
}
}
//运行
/*
请输入管理员名字:1' or
请输入管理员密码:or '1' = '1
对不起,登录失败
*/