文章目录
- DriverManager
- Connection
- Statement
- PreparedStatement
- ResultSet
- 案例
- 案例一:JDBC控制事务
- 案例二:SQL 注入错误演示
DriverManager
-
概述:DriverManager 是驱动管理类
-
作用
- 获取数据库连接
// 返回数据库连接的对象,url 是指定连接路径,user 是数据库用户名 password 是数据库密码 static Connection getConnection(String url , String user , String password);
- url 语法
jdbc:mysql://IP地址(域名):端口号/数据库名称
如果连接的是本机 MySQL 服务器,并且端口号默认则 url简写为:jdbc:mysql:///数据库名称>
-
示例代码
// 1、获取数据库连接对象-自行更换数据库用户名和密码 Connection con = DriverManager.getConnection("jdbc:mysql:///test","root","root");
Connection
-
概述:Connection 是数据库连接类
-
作用
- 获取执行 SQL 的对象
方法 作用 Statement createStatement(); 返回执行 SQL 对象 PreparedStatement prepareStatement(String sql); 返回执行 SQL 对象,和上述对象有区别 - 管理事务
方法 作用 注意事项 setAutoCommit(boolean autoCommit); 开启事务 方法参数设置为 false ,即开启事务,反之 commit(); 提交事务 事务执行中未出现错误,执行提交 rollback(); 回滚事务 事务执行中出现错误,执行回滚 -
示例代码(这里只为演示,并无实际效果,具体看后续案例)
// 1、获取数据库连接对象 Connection con = DriverManager.getConnection("jdbc:mysql:///test","root","root"); // 2、获取执行 SQL 对象 Statement st = con.createStatement(); // ? 后续会讲,看下去 PreparedStatement pst = con.prepareStatement("SELECT * FROM account WHERE id = ?");// 1、开启事务 con.setAutoCommit(false); // 2、提交事务 con.commit(); // 3、回滚事务 con.rollback();
Statement
-
概述:执行 SQL 的对象
-
常用方法
方法 作用 boolean execute(String sql); 可以执行任意的 SQL 语句 int executeUpdate(String sql); 执行 DML、DDL语句,返回值:影响的行数,>0 则代表执行成功 ResultSet executeQuery(String sql); 执行 DQL 查询语句 -
示例代码
- 数据库代码
-- 创建一个数据库 CREATE DATABASE IF NOT EXISTS test CHARACTER SET utf8; -- 使用数据库 USE test; -- 创建一个账户表 CREATE TABLE account(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(20),balance DOUBLE ); -- 向账户表中添加数据 INSERT INTO account(NAME , balance) VALUES('张三',1000),('李四',1000);-- 查询账户表 SELECT * FROM account;
- Java 代码
public class Test1 {public static void main(String[] args) throws ClassNotFoundException, SQLException {// 1、注册驱动Class.forName("com.mysql.cj.jdbc.Driver");// 2、获取数据库连接对象Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");// 3、获取执行 SQL 对象Statement st = con.createStatement();// 4、定义 SQL 语句String sql1 = "SELECT * FROM account WHERE id = 2";String sql2 = "UPDATE account SET balance = balance - 500 WHERE id = 1";// 5、执行 SQL 语句boolean flag = st.execute(sql1);int lineNum = st.executeUpdate(sql2);ResultSet rs = st.executeQuery(sql1);// 6、输出结果System.out.println(flag + " " + lineNum);// 输出 ResultSet 结果集结果while(rs.next()){int id = rs.getInt(1);String name = rs.getString("name");double balance = rs.getDouble(3);System.out.println(id + "---" + name + "---" + balance);}// 7、释放资源st.close();con.close();} }
运行结果:
true 1
2—李四—1000.0
PreparedStatement
-
概述:执行 SQL 的对象(可以防止 SQL 注入)
- 作用:PreparedStatement 可以防止 SQL 注入,并且效率更高
-
SQL 注入!!!
- 问题:在拼接 SQL 时候,有一些 SQL 特殊的关键字参与字符串的拼接,会造成安全性问题?(在案例中演示什么问题)
- 解决此问题:使用 PreparedStatement 对象来解决,预编译的 SQL 参数使用 ?>作为占位符
-
常用方法
方法 作用 参数 setXxx(参数1,参数2) 给 ?赋值,Xxx代表数据类型 参数1:?的位置编号(从1开始)
参数2:赋给?的值 -
示例代码(此对象如何使用)
- 数据库代码
-- 创建一个数据库 CREATE DATABASE IF NOT EXISTS test CHARACTER SET utf8; -- 使用数据库 USE test; -- 创建一个账户表 CREATE TABLE account(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(20),balance DOUBLE ); -- 向账户表中添加数据 INSERT INTO account(NAME , balance) VALUES('张三',1000),('李四',1000);-- 查询账户表 SELECT * FROM account;
- Java 代码
public class Test2 {public static void main(String[] args) throws ClassNotFoundException, SQLException {// 1、注册驱动Class.forName("com.mysql.cj.jdbc.Driver");// 2、获取数据库连接对象Connection con = DriverManager.getConnection("jdbc:mysql:///test", "root", "root");// 3、定义 SQL 语句,这里使用占位符 ?String sql = "UPDATE account SET balance = balance - ? WHERE id = ?";// 4、创建 执行 SQL 对象PreparedStatement pst = con.prepareStatement(sql);// 5、设置参数,给第一个?设置值为 500 给第二个?设置值为 1pst.setInt(1,500);pst.setInt(2,1);// 6、执行 SQL 语句int lineNum = pst.executeUpdate();// 7、输出结果System.out.println(lineNum);// 8、释放资源pst.close();con.close();;} }
运行后,可看到控制台输出结果 1 ,数据库中编号 1 的balance 变成了 500
ResultSet
-
概述:结果集对象,用来封装查询结果的
-
常用方法
方法 作用 注意事项 boolean next(); 游标向下移动一行,判断当前行是否有数据 有数据返回 true 无数据返回 false getXxx(参数); 获取数据 Xxx:代表数据类型
参数是 int 类型,代表列的编号(从1开始),
参数是 String 类型,代表列名称 -
代码示例
ResultSet rs = st.executeQuery(sql1); //循环判断游标是否是最后一行末尾。 while(rs.next()){//获取数据int id = rs.getInt(1);String name = rs.getString("name");double balance = rs.getDouble(3);System.out.println(id + "---" + name + "---" + balance); }
案例
案例一:JDBC控制事务
-
概述:事务,一个包含多个步骤的业务操作。如果这个业务操作被事务管理,多个步骤要么同时成功,要么同时失败。
-
操作事务的三个步骤
- 开始事务
- 提交事务
- 回滚事务
-
代码示例(这里有很多的写法并不严谨,只是为了更好的演示效果,数据库还是上述步骤中用到过的)
public class Test3 {public static void main(String[] args) {// 这里为了省事,简单这样写String url = "jdbc:mysql://localhost:3306/test";String user = "root";String password = "root";Connection con = null;PreparedStatement pst1 = null;PreparedStatement pst2 = null;try {// 1、注册驱动Class.forName("com.mysql.cj.jdbc.Driver");// 2、获取数据库连接con = DriverManager.getConnection(url,user,password);// 3、开启事务con.setAutoCommit(false);// 4、定义 SQL 语句,sql1 张三-500 sql2 李四+500String sql1 = "UPDATE account SET balance = balance - ? WHERE id = ?";String sql2 = "UPDATE account SET balance = balance + ? WHERE id = ?";// 5、获取执行 SQL 对象pst1 = con.prepareStatement(sql1);pst2 = con.prepareStatement(sql2);// 6、设置 占位符值pst1.setInt(1,500);pst1.setInt(2,1);pst2.setInt(1,500);pst2.setInt(2,2);// 7、执行 SQLpst1.executeUpdate();// 手动制造异常,可以运行次后,看下数据库的数字,再注释掉这行再运行,再看数据库数字int i = 3/0;pst2.executeUpdate();// 提交事务,因为遇见异常,所以这步代码并不执行con.commit();} catch (Exception e) {try{if(con != null){// 事务回滚,当 con 不为空的时候,才回滚con.rollback();}}catch (SQLException e1){e1.printStackTrace();}e.printStackTrace();} finally {try {// 释放资源pst1.close();pst2.close();con.close();} catch (SQLException e) {e.printStackTrace();}}} }
案例二:SQL 注入错误演示
-
概述:SQL 语句拼接时,用一些特殊的关键字参与字符串拼接,会造成安全性问题
-
代码示例
- 数据库代码
-- 创建数据库 CREATE DATABASE IF NOT EXISTS test CHARACTER SET utf8;-- 创建 user 表 CREATE TABLE USER(username VARCHAR(20), -- 用户名PASSWORD VARCHAR(20) -- 密码 );-- 插入数据 INSERT INTO USER VALUES('lisi',"a'or'a'='a");-- 查询数据,可发现下边 3行都会显示此条信息,这样错误太明显了,这是为什么? SELECT * FROM USER WHERE username = 'lisi' AND PASSWORD = 'a'OR'a'='a';SELECT * FROM USER WHERE username = 'fhdsjkf' AND PASSWORD = 'a' OR 'a' = 'a';SELECT * FROM USER WHERE username = 'a' AND PASSWORD = 'a' OR 'a' = 'a';
注意:为什么上述3行都能显示呢?看下边两个框,可以知道,查询语句的条件有两个,中间又用 OR ,根据或的特性,只要满足其一即可,第二个红框,很明显一直是对的,所以就能查询出来。