文章目录
-
- DriverManager
- Connection
- Statement
- PreparedStatement
- ResultSet
- 案例
-
- 案例一:JDBC控制事务
- [案例二:SQL 注入错误演示](#案例二:SQL 注入错误演示)
DriverManager
-
概述:DriverManager 是驱动管理类
-
作用
- 获取数据库连接
java// 返回数据库连接的对象,url 是指定连接路径,user 是数据库用户名 password 是数据库密码 static Connection getConnection(String url , String user , String password);
-
url 语法
jdbc:mysql://IP地址(域名):端口号/数据库名称
如果连接的是本机 MySQL 服务器,并且端口号默认则 url简写为:jdbc:mysql:///数据库名称>
-
示例代码
java// 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(); 回滚事务 事务执行中出现错误,执行回滚 -
示例代码(这里只为演示,并无实际效果,具体看后续案例)
java// 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 查询语句 -
示例代码
- 数据库代码
sql-- 创建一个数据库 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 代码
javapublic 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:赋给?的值 -
示例代码(此对象如何使用)
- 数据库代码
sql-- 创建一个数据库 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 代码
javapublic 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 给第二个?设置值为 1 pst.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 类型,代表列名称 -
代码示例
javaResultSet 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控制事务
-
概述:事务,一个包含多个步骤的业务操作。如果这个业务操作被事务管理,多个步骤要么同时成功,要么同时失败。
-
操作事务的三个步骤
- 开始事务
- 提交事务
- 回滚事务
-
代码示例(这里有很多的写法并不严谨,只是为了更好的演示效果,数据库还是上述步骤中用到过的)
javapublic 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 李四+500 String 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、执行 SQL pst1.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 语句拼接时,用一些特殊的关键字参与字符串拼接,会造成安全性问题
-
代码示例
- 数据库代码
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 ,根据或的特性,只要满足其一即可,第二个红框,很明显一直是对的,所以就能查询出来。