目录
一、JDBC简介
- JDBC就是用Java语言操作关系型数据库的一套API。
- 全称:(Java DataBase Connectivity)Java数据库连接。
JDBC本质:同一套Java代码,操作不同类型的关系型数据库。
- 官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。
- 各个数据库厂商去实现这套接口,提供数据库驱动jar包。
- 我们可以使用这套接口(JDBC) 编程,真正执行的代码是驱动jar包中的实现类。
二、JDBC的快速入门
步骤:
①创建工程,导入驱动jar包
1. 配置:
2. 导入jar包:
3. 右键点击jar包,将jar包添加到本项目中
②注册驱动
Class.forName("com.mysql.jdbc.Driver");
③获取连接
Connection conn = DriverManager.getConnection(url,username,password);
④定义sql语句
String sql = "update...";
⑤获取执行sql对象
Statement stmt = conn.creatStatement();
⑥执行sql
stmt.executeUpdate(sql);
⑦处理返回结果
⑧释放资源
package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/*
* JDBC快速入门
*/
public class JDBCDemo {
public static void main(String[] args) throws Exception {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/db1";//固定写法,只需修改db1数据库名来连接不通的数据库
String username = "root";
String password = "";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql语句
String sql = "update account set money = 2000 where id = 1";
//4.获取执行sql的对象Statement
Statement stmt = conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);//受影响的行数
//6.处理结果
System.out.println(count);
//7.释放资源
stmt.close();
conn.close();
}
}
三、DriverManager详解
- DriverManager(驱动管理类)作用:
- 1.注册驱动
- 2.获取数据库连接
1. 注册驱动
Class.forNae("com.mysql.jdbc.Driver");//可以省略不写
查看Driver源代码:
tips:
- MySQL5之后的驱动包,可以省略注册驱动的步骤
- 自动加载jar包中 META-INF\services\java.sql.Driver文件中的驱动类
2.获取数据库连接
static Connection getConnection(String url,String user,String password);
参数:
①url:连接路径
语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2...
示例:jdbc:mysql://127.0.0.1:3306/db1
细节:
- 如果连接的是本机的mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql://数据库名称?参数键值对
- 配置useSSL=false参数,禁止安全连接方式,解决警告提示
② user:用户名
③password:密码
四、Connection详解
- Connection(数据库连接对象)作用:
- 1.获取执行SQL的对象
- 2.管理事务
1.获取执行SQL的对象
- 执行普通SQL对象:
Statement createStatement()
- 预编译SQL的执行SQL对象:防止SQL注入
PrepareStatement prepareStatement(sql)
- 执行存储过程的对象
CallableStatement prepareCall(sql)
2.事务管理
MySQL事务管理
开启事务:begin;/start transaction
提交事务:commit;
回滚事务:rollback;
MySQL默认自动提交事务
JDBC事务管理:Connection接口中定义了三个对应的方法
开启事务:setAutoCommit(boolean autoCommit):true为自动提交事务,false为手动提交事务
提交事务:commit{};
回滚事务:rollback();
public static void main(String[] args) throws Exception {
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");//5版本之后的mysql不需要写,jar包中META-INF中有
//2.获取连接:如果连接的是本机的mysql并且端口是默认的3306则可以简写
String url = "jdbc:mysql:///db1?useSSL=false";//固定写法,只需修改db1数据库名来连接不通的数据库,?后是参数
String username = "root";
String password = "";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql语句
String sql1 = "update account set money = 3000 where id = 1";
String sql2 = "update account set money = 3000 where id = 2";
//4.获取执行sql的对象Statement
Statement stmt = conn.createStatement();
//快捷键ctrl+alt+t
try {
//开启事务
conn.setAutoCommit(false);
//5.执行sql
int count1 = stmt.executeUpdate(sql1);//受影响的行数
//6.处理结果
System.out.println(count1);
int i = 3/0;
//5.执行sql
int count2 = stmt.executeUpdate(sql2);//受影响的行数
//6.处理结果
System.out.println(count2);
//提交事务
conn.commit();
} catch (Exception e) {
//回滚事务
conn.rollback();
e.printStackTrace();
}
//7.释放资源
stmt.close();
conn.close();
}
五、Statement详解
- Statement作用:执行SQL语句
执行SQL语句
int executeUpdate(sql):执行DML、DDL语句
返回值:(1)DML语句影响的行数
(2)DDL语句执行后,执行成功也可能返回0
ResultSet executeQuery(sql):执行DQL语句
返回值:ResultQuery结果集对象
/**
* JDBC API详解:Statement
*/
public class JDBCDemo4_Statement {
/**
* 执行DML语句
* @throws Exception
*/
@Test
public void testDML() throws Exception {
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");//5版本之后的mysql不需要写,jar包中META-INF中有
//2.获取连接:如果连接的是本机的mysql并且端口是默认的3306则可以简写
String url = "jdbc:mysql:///db1?useSSL=false";//固定写法,只需修改db1数据库名来连接不通的数据库,?后是参数
String username = "root";
String password = "";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql语句
String sql = "update account set money = 3000 where id = 5";
//4.获取执行sql的对象Statement
Statement stmt = conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);//执行完DML语句后受影响的行数
//6.处理结果
//System.out.println(count);
if(count>0){
System.out.println("修改成功!");
}else{
System.out.println("修改失败!");
}
//7.释放资源
stmt.close();
conn.close();
}
/**
* 执行DDL语句
* @throws Exception
*/
@Test
public void testDDL() throws Exception {
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");//5版本之后的mysql不需要写,jar包中META-INF中有
//2.获取连接:如果连接的是本机的mysql并且端口是默认的3306则可以简写
String url = "jdbc:mysql:///db1?useSSL=false";//固定写法,只需修改db1数据库名来连接不通的数据库,?后是参数
String username = "root";
String password = "";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql语句
String sql = "drop database db2";
//4.获取执行sql的对象Statement
Statement stmt = conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);//执行完DDL语句,返回值可能是0(如删除一个数据库)
//6.处理结果
//System.out.println(count);
// if(count>0){
// System.out.println("修改成功!");
// }else{
// System.out.println("修改失败!");
// }
System.out.println(count);
//7.释放资源
stmt.close();
conn.close();
}
}
六、ResultSet详解
-
ResultSet(结果集对象)作用:
封装了DQL查询语句的结果
ResultSet stmt.executeQuery(sql):执行DQL语句,返回ResultSet对象
-
获取查询结果
boolean next():(1)将光标从当前位置向前移动一行
(2)判断当前行是否为有效行
返回值:
ture:有效行,当前行有数据
false:无效行,当前行没有数据
xxx getXxx(参数) :获取数据
xxx:数据类型;如:int getInt(参数);String getString(参数);
参数:
int:列的编号,从1开始
String:列的名称
-
使用步骤:
1.游标向下移动一行,并判断该行是否有数据:next()
2.获取数据:getXxx(参数)
//循环判断游标是否是最后一行末尾
while(rs.next(()){
//获取数据
rs.getXxx(参数);
}
/**
* 执行DQL语句
* @throws Exception
*/
@Test
public void testResultSet() throws Exception {
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");//5版本之后的mysql不需要写,jar包中META-INF中有
//2.获取连接:如果连接的是本机的mysql并且端口是默认的3306则可以简写
String url = "jdbc:mysql:///db1?useSSL=false";//固定写法,只需修改db1数据库名来连接不通的数据库,?后是参数
String username = "root";
String password = "";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义SQL
String sql = "select * from account";
//4.获取statement对象
Statement stmt = conn.createStatement();
//5.执行sql
ResultSet rs = stmt.executeQuery(sql);
//6. 处理结果,遍历rs中的所有数据
// //6.1光标向下移动一行并且判断当前行是否有数据
// while(rs.next()){
// //6.2获取数据 getXxx()
// int id = rs.getInt(1);
// String name = rs.getString(2);
// double money = rs.getDouble(3);
//
// System.out.println(id);
// System.out.println(name);
// System.out.println(money);
// System.out.println("-------");
// }
//6.1光标向下移动一行并且判断当前行是否有数据
while(rs.next()){
//6.2获取数据 getXxx()
int id = rs.getInt("id");
String name = rs.getString("name");
double money = rs.getDouble("money");
System.out.println(id);
System.out.println(name);
System.out.println(money);
System.out.println("-------");
}
//7.释放资源
rs.close();
stmt.close();
conn.rollback();
}
ResultSet案例
需求:查询account账户表数据,封装在Account对象中,并且存储到ArrayList集合中
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");//5版本之后的mysql不需要写,jar包中META-INF中有
//2.获取连接:如果连接的是本机的mysql并且端口是默认的3306则可以简写
String url = "jdbc:mysql:///db1?useSSL=false";//固定写法,只需修改db1数据库名来连接不通的数据库,?后是参数
String username = "root";
String password = "";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义SQL
String sql = "select * from account";
//4.获取statement对象
Statement stmt = conn.createStatement();
//5.执行sql
ResultSet rs = stmt.executeQuery(sql);
//创建集合
List<Account> list = new ArrayList<>();
//6.1 rs.next()光标向下移动一行并且判断当前行是否有数据
while(rs.next()){
Account account = new Account();
//6.2获取数据 getXxx()
int id = rs.getInt("id");
String name = rs.getString("name");
double money = rs.getDouble("money");
//赋值
account.setId(id);
account.setName(name);
account.setMoney(money);
//存入集合
list.add(account);
}
System.out.println(list);
//7.释放资源
rs.close();
stmt.close();
conn.rollback();
}
七、PreparedStatement详解
-
PrepareStatement作用:
预编译SQL语句并执行:防止SQL注入问题
- SQL注入
SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。
- 原sql语句:
select * from tb_user where username = 'zhangsan' and password = '123'
- 通过操作输入来修改事先定义好的SQL语句,使之语意发生改变:
select * from tb_user where username = '呵呵呵' and password = '' or '1' = '1'
- 采用API:PreparedStatement后:在pstmt.setXxx时将传入的值进行转义,将转义后的内容当成文本的形式传入。
-- ' or '1' = '1 select * from tb_user where username = 'hfkjsfhskj' and password = '\' or \'1\' = \'1'
-
PrepareStatement用法步骤:
①获取PreparedStatement对象
//SQl语句中的参数值,使用?占位符替代
String sql = "select * from user where username = ? and password = ? ";
//通过Connection对象获取,并传入对应的sql语句
PreparedStatement pstmt = conn.prepareStatement(sql);
②设置参数值
PreparedStatement对象:setXxx(参数1,参数2):给?赋值
Xxx:数据类型;如setInt(参数1,参数2)参数:
参数1:?的位置编号,从1开始
参数2:?的值
③ 执行sql
//不再需要传递sql
executeUpdate();
executeQuery();
防止SQL注入用法示例:
@Test
public void testPreparedStatement() throws Exception {
//2.获取连接:如果连接的是本机的mysql并且端口是默认的3306则可以简写
String url = "jdbc:mysql:///db1?useSSL=false";//固定写法,只需修改db1数据库名来连接不通的数据库,?后是参数
String username = "root";
String password = "";
Connection conn = DriverManager.getConnection(url, username, password);
//接受用户名和密码
String name = ",,,,";
String pwd = "' or '1' = '1";
//定义sql
String sql = "select * from tb_user where username = ? and password = ?";
//获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置?的值
pstmt.setString(1,name);
pstmt.setString(2,pwd);
//执行sql
ResultSet rs = pstmt.executeQuery();
//判断登录是否成功
if(rs.next()){
System.out.println("登陆成功!!!");
}else{
System.out.println("登陆失败!");
}
//7.释放资源
rs.close();
pstmt.close();
conn.close();
}
需求:完成用户登陆
select * from tb_user where username = "张三" and password = '123';
/**
* 演示sql注入
* @throws Exception
*/
@Test
public void testLogin_Inject() throws Exception {
//2.获取连接:如果连接的是本机的mysql并且端口是默认的3306则可以简写
String url = "jdbc:mysql:///db1?useSSL=false";//固定写法,只需修改db1数据库名来连接不通的数据库,?后是参数
String username = "root";
String password = "";
Connection conn = DriverManager.getConnection(url, username, password);
//接受用户名和密码
String name = "shhiiii";
String pwd = "' or '1' = '1";
String sql = "select * from tb_user where username = '" + name + "' and password = '" + pwd + "'";
System.out.println(sql);
//获取stmt对象
Statement stmt = conn.createStatement();
//执行sql
ResultSet rs = stmt.executeQuery(sql);
//判断登录是否成功
if (rs.next()) {
System.out.println("登陆成功!!!");
} else {
System.out.println("登陆失败!");
}
}
-
PreparedStatement的好处:
1.预编译SQL,性能高
2.防止SQL注入:将敏感字符义
①PreparedStatement预编译功能开启:useServerPrepStmts=true
②配置MySQL执行日志(重启mysql服务后生效)
log-output=FILE
general-log=1
general_log_file="G:\MySQL\mysql.log"
slow-query-log=1
slow_query_log_file="G:\MySQL\mysql_show.log"
long_query_time=2
-
PreparedStatement的原理:
- 1.在获取PreparedStatement对象时,将sql语句发送给mysql服务器进行检查,编译(这些步骤比较耗时)
- 2.执行时就不用再进行这些步骤了,速度更快
- 3.如果sql模板一样,则只需要进行一次检查、编译