1. JDBC介绍
JDBC(Java Database Connectivity)是 Java 连接数据库的标准接口,它提供了一种与数据库交互的统一方式,使得 Java 程序能够通过标准 API 访问和操作各种关系型数据库。
2. JDBC使用步骤
第0步:导bao
第1步:注册驱动(仅需一次)
第2步:建立链接(Connection)
第3步:创建语句传输对象(Statement)
第4步:运行sql语句
第5步:处理运行结果(ResultSet)
第6步:释放资源
其中,如果是添加,删除,更新操作,可以没有第五步,查询肯定有第五步。
2.0 导包
下载相应版本的jar包(下载地址:Maven Repository: MySQL (mvnrepository.com))
创建Java项目 ——> 在项目下创建lib文件夹——> 将jar包复制到lib文件夹下——> 右键——> Build Path ——> Add to Build Path
2.1 注册驱动
创建java类 JDBC_00 (类名随意)
// 1. 注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
2.2 建立链接
// 2. 创建链接对象
// 如果出现乱码等问题 可以在url后添加设置编码方式
// url : jdbc:mysql://IP:端口/数据库?useUnicode=true&characterEncoding=utf-8
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/_day_02","root", "root");
2.3 创建语句传输对象
// 3. 创建语句传输对象
Statement statement = conn.createStatement();
String sql = "select * from student";
2.4 运行语句
// 4. 执行sql语句获取结果集
ResultSet rs = statement.executeQuery(sql);
2.5 处理运行结果
// 5. 处理结果集数据
while (rs.next()) {
// 根据列名获取数据
int id = rs.getInt("id");
// 根据列的索引获取数据,不建议使用,
// int id = rs.getInt(1);
String name = rs.getString("name");
int tid = rs.getInt("teacher_id");
double score = rs.getDouble("score");
System.out.println(id + "--" + name + "--" + tid + "--" + score);
}
2.6 释放资源
// 6. 关闭资源
rs.close();
statement.close();
conn.close();
3.代码优化
添加try...catch...finally异常处理
public class JDBC_00 {
public static void main(String[] args) {
Connection conn = null;
Statement statement = null;
ResultSet rs = null;
try {
// 1. 注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 创建链接对象
// 如果出现乱码等问题 可以在url后添加东西
// url : jdbc:mysql://IP:端口/数据库?useUnicode=true&characterEncoding=utf-8
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/_day_02","root", "abc280619SS");
// 3. 创建语句传输对象
statement = conn.createStatement();
String sql = "select * from student";
// 4. 执行sql语句获取结果集
rs = statement.executeQuery(sql);
// 5. 处理结果集数据
while (rs.next()) {
// 根据列名获取数据
int id = rs.getInt("id");
// 根据列的索引获取数据,不建议使用,
// int id = rs.getInt(1);
String name = rs.getString("name");
int tid = rs.getInt("teacher_id");
double score = rs.getDouble("score");
System.out.println(id + "--" + name + "--" + tid + "--" + score);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
// 6. 关闭资源,先打开的后关闭
rs.close();
statement.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
4. DML
Data Manipulation Language : 数据操作语言
涉及的关键字有 : delete,update,insert
和查询的操作几乎一样,就是把第4步和第5步更改一下
public class JDBC_02 {
public static void main(String[] args) {
Connection conn = null;
Statement statement = null;
try {
// 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 创建链接对象
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/_day_02", "root", "abc280619SS");
// 创建语句传输对象
statement = conn.createStatement();
// 编写sql语句
// 添加
String sql = "insert into teacher(id,`name`) values(3,'宋老师')";
// 修改
sql = "update teacher set `name` = '赵老师' where id = 3";
// 删除
sql = "delete from teacher where id = 3";
// 执行sql语句,增删改使用executeUpdate()方法,查询使用executeQuery()方法
int count = statement.executeUpdate(sql);
System.out.println("成功,影响了"+ count + "行。" );
} catch (Exception e) {
e.printStackTrace();
}finally {
// 关闭资源
try {
statement.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
5. PrepareStatement
添加或删除的时候,尽量使用PrepareStatement,而不是Statement
Statement和PrepareStatement的区别:
Statement 用于执行静态SQL语句,在执行的时候,必须指定一个事先准备好的SQL语句,并且相对不安全,会有SQL注入风险。
PrepareStatement 是预编译的SQL语句对象,SQL语句被预编译i并保存在对象中,被封装的SQL语句中,可以使用动态包含的参数?,在执行的时候可以为?传递参数。
使用PrepareStatement对象执行SQL语句的时候,sql被数据库进行预编译和预解析,然后被放到缓冲区中,每当执行一个PrepareStatement对象时,他就会被解析一次,但不会被再次编译,可以重复使用,减少编译次数,提高数据库性能。并且能够避免SQL注入,相对安全(把’ 单引号 使用 \ 转义,避免SQL注入 )。
SQL注入:
SQL注入(SQL Injection)是一种常见的网络安全攻击技术,通过在应用程序中插入恶意的SQL查询语句,来利用程序缺陷或漏洞,从而对数据库进行非法操作或获取敏感信息。
SQL注入攻击通常发生在需要用户输入数据并将其嵌入到 SQL 查询语句中的地方,比如登录表单、搜索框、参数化查询等。攻击者利用这些地方未对用户输入进行有效验证和过滤,直接将恶意的SQL代码注入到查询中,从而执行恶意操作。
/*
* PrepareStament
*/
public class JDBC_05 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = scanner.nextLine();
System.out.println("请输入密码:");
String password = scanner.nextLine();
// login(username, password);
// updatePwd(username, password);
loginUser(username, password);
}
// 用户登录方法
public static boolean login(String username,String password) {
Connection conn = null;
PreparedStatement statement = null;
ResultSet rs = null;
try {
// 加载驱动
conn = DBUtil.getConnection();
// 编写sql语句
String sql = "select count(*) from user where name = ? and password = ?";
// 创建输出对象
statement = conn.prepareStatement(sql);
// 给问号赋值
statement.setString(1, username);
statement.setString(2, password);
// 创建结果集,执行sql语句
rs = statement.executeQuery();
rs.next();
// 返回结果
int count = rs.getInt(1);
if (count == 0) {
System.out.println("登录失败");
return false;
}else {
System.out.println("登录成功");
return true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭资源
DBUtil.close(rs);
DBUtil.close(statement);
DBUtil.close(conn);
}
return false;
}
// 修改密码的方法
public static void updatePwd(String username,String password) {
Connection conn = null;
PreparedStatement statement = null;
try {
// 加载驱动
conn = DBUtil.getConnection();
// 编写sql语句
String sql = "update user set password = ? where name = ?";
// 创建输出对象
statement = conn.prepareStatement(sql);
// 给问号赋值
statement.setString(1, password);
statement.setString(2, username);
// 执行sql语句
int count = statement.executeUpdate();
System.out.println("修改了"+count+"条数据");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭资源
DBUtil.close(statement);
DBUtil.close(conn);
}
}
// 使用statement的登录方法,容易发生sql注入问题
// 由于Statement在执行sql语句之前进行了字符串的拼接,所以如果username输入类似'or 1=1 or'格式
// 即使用户不存在也能实现登录
public static boolean loginUser(String username,String password) {
Connection conn = null;
Statement statement = null;
ResultSet rs = null;
try {
// 加载驱动
conn = DBUtil.getConnection();
// 创建输出对象
statement = conn.createStatement();
// 编写sql语句
String sql = "select count(*) from user where name = '"+username+"' and password = '"+password+"'";
// 创建结果集,执行sql语句
rs = statement.executeQuery(sql);
rs.next();
// 返回结果
int count = rs.getInt(1);
if (count == 0) {
System.out.println("登录失败");
return false;
}else {
System.out.println("登录成功");
return true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭资源
DBUtil.close(rs);
DBUtil.close(statement);
DBUtil.close(conn);
}
return false;
}
}
6. 封装工具类
以上代码中创建链接和关闭资源操作都是相同的,因此可以把这一部分逻辑抽离出来,形成独立的类和方法,在实际应用中直接调用相应的类和方法即可。
创建JDBCUtil类,提供获取链接的方法和释放资源的方法
public class DBUtil {
// 封装方法加载驱动创建链接
public static Connection getConnection() throws ClassNotFoundException, SQLException{
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/_day_02","root", "abc280619SS");
return conn;
}
// 封装方法关闭资源
public static void close(AutoCloseable obj) {
if (obj != null) {
try {
obj.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
7. Batch 多语句操作
在一次任务中执行多条语句
public class JDBC_Batch {
public static void main(String[] args) {
// testStatement();
testPrepareStatement();
}
// 使用Statement添加多条数据
public static void testStatement() {
Connection conn = null;
Statement statement = null;
try {
conn = DBUtil.getConnection();
statement = conn.createStatement();
statement.addBatch("insert into user(name,password,nickname) values('test1',111,'用户1')");
statement.addBatch("insert into user(name,password,nickname) values('test2',222,'用户2')");
statement.addBatch("insert into user(name,password,nickname) values('test3',333,'用户3')");
statement.executeBatch();
System.out.println("添加成功");
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(statement);
DBUtil.close(conn);
}
}
// 使用PrepareStatement添加多条数据
public static void testPrepareStatement() {
Connection conn = null;
PreparedStatement preparedStatement = null;
try {
conn = DBUtil.getConnection();
preparedStatement = conn.prepareStatement("insert into user(name,password,nickname) values(?,?,?)");
preparedStatement.setString(1, "test1");
preparedStatement.setInt(2, 111);
preparedStatement.setString(3, "用户1");
preparedStatement.addBatch();
preparedStatement.setString(1, "test2");
preparedStatement.setInt(2, 222);
preparedStatement.setString(3, "用户2");
preparedStatement.addBatch();
preparedStatement.setString(1, "test3");
preparedStatement.setInt(2, 333);
preparedStatement.setString(3, "用户3");
preparedStatement.addBatch();
preparedStatement.executeBatch();
System.out.println("添加成功");
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(preparedStatement);
DBUtil.close(conn);
}
}
}