JDBC
JDBC基本操作
JDBC概念:
JDBC: 就是使用Java语言操作关系型数据库的一套API
全称:( Java DataBase Connectivity ) Java 数据库连接
JDBC本质:
官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口
各个数据库厂商去实现这套接口,提供数据库驱动jar包, 而各个数据库厂商的实现类又有一个比较"洋气"的名字, 叫做驱动
我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类
JDBC好处:
各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发
可随时替换底层数据库,访问数据库的Java代码基本不变
Java操作数据库的步骤如下:
- 创建工程,导入驱动jar包(数据库厂商针对JDBC编写的实现类)
- 注册驱动(名称是固定的)
Class.forName("com.mysql.jdbc.Driver");
- 获取连接
Connection conn = DriverManager.getConnection(url, username, password);
- 定义SQL语句
String sql = “update…” ;
- 执行SQL语句
Statement stmt = conn.createStatement();
- 执行SQL
stmt.executeUpdate(sql);
- 处理返回结果
- 释放资源
基本演示代码(了解, 下面会详细讲解API):
public static void main(String[] args) throws Exception {
// 1. 注册驱动(com.mysql.jdbc.Driver是固定的)
Class.forName("com.mysql.jdbc.Driver");
// 2. 获取连接
String url = "jdbc:mysql://127.0.0.1:3306/db1";
String username = "root";
String password = "123456789";
Connection conn = DriverManager.getConnection(url, username, password);
// 3. 定义sql语句
String sql = "UPDATE account SET money = 2000 WHERE id = 1";
// 4. 获取sql执行的对象
Statement stmt = conn.createStatement();
// 5. 执行sql
int count = stmt.executeUpdate(sql); // 返回受影响的行数
// 6. 处理返回结果
System.out.println(count); // 1
// 7. 释放资源
stmt.close();
conn.close();
}
JDBC API详解
DriverManager
DriverManager(驱动管理类)作用:
1.注册驱动
2.获取数据库连接
作用一: 注册驱动
Class.forName("com.mysql.jdbc.Driver");
注册驱动是通过Driver类, 查看Driver类源码可以发现, 源码中有一个静态代码块, 里面通过DriverManager类的方法注册驱动
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
提示:
MySQL 5之后的驱动包,可以省略注册驱动的步骤
自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类
作用二: 获取连接
通过getConnection方法
Connection conn = DriverManager.getConnection(url, username, password);
getConnection方法有三个参数:
- url: 要连接数据库的路径
- user: 数据库的用户名
- password: 数据库的密码
参数url的注意事项:
url连接路径的语法:
jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2…
例如链接本地数据库db1:
jdbc:mysql://127.0.0.1:3306/db1
细节:
- 如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:
jdbc:mysql:///数据库名称?参数键值对
- 配置 useSSL=false 参数,禁用安全连接方式,解决警告提示
Connection
Connection(数据库连接对象)作用:
1.获取执行 SQL 的对象
2.管理事务
作用一: 获取执行 SQL 的对象
普通执行SQL对象:
Statement createStatement()
预编译SQL的执行SQL对象, 防止SQL注入:
PreparedStatement prepareStatement (sql)
执行存储过程的对象:
执行存储过程的对象
作用二: 管理事务
我们知道MySQL事务管理分为三个操作:
开启事务:BEGIN; 或者 START TRANSACTION;
提交事务:COMMIT;
回滚事务:ROLLBACK;
MySQL默认自动提交事务
在JDBC事务管理中:Connection接口中定义了3个对应的方法
开启事务:setAutoCommit(boolean autoCommit)
- true为自动提交事务;
- false为手动提交事务,即为开启事务
提交事务:commit()
回滚事务:rollback()
示例代码:
public static void main(String[] args) throws Exception {
// 获取链接
Connection conn = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "123456789");
// 定义sql
String sql1 = "UPDATE account SET money = 3000 WHERE id = 1";
String sql2 = "UPDATE account SET money = 4000 WHERE id = 2";
// 获取sql执行对象
Statement stmt = conn.createStatement();
// 开启事务
conn.setAutoCommit(false);
try {
// 执行sql1
int count1 = stmt.executeUpdate(sql1);
System.out.println(count1);
// 执行sql2
int count2 = stmt.executeUpdate(sql2);
System.out.println(count2);
// 提交事务
conn.commit();
} catch (Exception e) {
// 异常回滚事务
conn.rollback();
}
// 释放资源
stmt.close();
conn.close();
}
作用二: 获取执行 SQL 的对象
普通执行SQL对象:
Statement createStatement()
预编译SQL的执行SQL对象, 防止SQL注入:
PreparedStatement prepareStatement (sql)
执行存储过程的对象:
执行存储过程的对象
Statement
Statement的唯一作用作用:执行SQL语句
执行DML、DDL的SQL语句:
int executeUpdate(sql)
:
- 返回值:DML语句返回影响的行数; DDL语句执行后,执行成功也可能返回 0
执行DML语句演示代码
@Test
public void testDML() throws Exception {
// 获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "123456789");
// 获取sql执行对象
Statement stmt = conn.createStatement();
// 定义一个DML sql语句
String sql = "UPDATE account SET money = 3000 WHERE id = 1";
// 返回执行完DML sql语句后影响的行数
int count = stmt.executeUpdate(sql);
System.out.println(count); // 1
// 处理结果
if (count > 0) {
System.out.println("修改成功~");
} else {
System.out.println("修改失败~");
}
// 释放资源
stmt.close();
conn.close();
}
执行DDL语句演示代码, 执行DDL语句成功也有可能返回0
@Test
public void testDDL() throws Exception {
// 获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "123456789");
// 获取sql执行对象
Statement stmt = conn.createStatement();
// 定义一个DDL sql语句
String sql = "DROP DATABASE db2";
// 执行成功也有可能返回0
int count = stmt.executeUpdate(sql);
System.out.println(count); // 0
// 释放资源
stmt.close();
conn.close();
}
执行DQL的SQL语句
ResultSet executeQuery(sql)
:执行DQL 语句
- 返回值:ResultSet 结果集对象
ResultSet
ResultSet(结果集对象)作用:封装了DQL查询语句的结果
ResultSet stmt.executeQuery(sql)
: 执行DQL语句,返回 ResultSet 对象
获取查询结果:
方法
boolean next()
:
- 将光标从当前位置向前移动一行
- 判断当前行是否为有效行
返回值boolean类型:
- true:表示有效行,当前行有数据
- false:表示无效行,当前行没有数据
获取数据:
方法
xxx getXxx(参数)
:
- xxx:数据类型;如:int getInt(参数) ; String getString(参数)
参数: 传入参数可以获取表中的数据
- int类型参数:列的编号,从1开始
- String类型参数:列的名称
使用步骤:
游标向下移动一行,并判断该行否有数据:next()
获取数据:getXxx(参数)
//循环判断游标是否是最后一行末尾
while(rs.next()){
//获取数据
rs.getXxx(参数);
}
示例代码:
@Test
public void testResultSet() throws Exception {
// 获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "123456789");
// 获取sql执行对象
Statement stmt = conn.createStatement();
// 定义一个DQL sql语句
String sql = "SELECT * FROM account";
// 执行结果返回一个ResultSet结果集对象
ResultSet rs = stmt.executeQuery(sql);
// 处理结果
while (rs.next()) {
// 向下移动一行,判断是否有数据
// 获取数据 传入int类型
System.out.print(rs.getInt(1));
System.out.print(rs.getString(2));
// 获取数据 传入String类型
System.out.println(rs.getDouble("money"));
}
// 释放资源
stmt.close();
conn.close();
}
PreparedStatement
PreparedStatement作用:
预编译SQL语句并执行:预防SQL注入问题
SQL注入:
SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。
SQL注入演示
创建tb_user表, 用于做登录演示
-- 创建tb_user表
CREATE TABLE tb_user(
id int,
username VARCHAR(20),
password VARCHAR(32)
);
-- 添加数据
INSERT INTO tb_user VALUES(1,'zhangsan','123'),(2,'lisi','234');
首先写出登录的逻辑, 输入的账号密码只有与数据库一致的时候, 才会登录成功
@Test
public void testLogin() throws Exception {
// 获取连接
Connection coon = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "123456789");
// 获取sql执行对象
Statement stmt = coon.createStatement();
// 接收用户输入的账号密码
String userName = "zhangsan";
String password = "123";
// 定义sql语句
String sql = "SELECT * from tb_user WHERE username = '" + userName + "'AND password = '" + password + "'";
// 执行sql
ResultSet rs = stmt.executeQuery(sql);
// 判断登录是否成功
if (rs.next()) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
}
sql注入演示, 我们随便输入一个账号, 然后密码输入
' or '1' = '1
, 发现是可以登录成功的
@Test
public void testLogin() throws Exception {
Connection coon = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "123456789");
Statement stmt = coon.createStatement();
// 接收用户输入的账号密码
String userName = "ddamhkhyug";
// 演示sql注入
String password = "'or '1' = '1";
String sql = "SELECT * from tb_user WHERE username = '" + userName + "'AND password = '" + password + "'";
ResultSet rs = stmt.executeQuery(sql);
if (rs.next()) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
}
SQL注入是非常危险的, 我们可以通过PreparedStatement防止SQL注入, PreparedStatement使用步骤如下:
- 获取 PreparedStatement 对象
// SQL语句中的参数值,使用?占位符替代
String sql = "select * from user where username = ? and password = ?";
// 通过Connection对象获取,并传入对应的sql语句
PreparedStatement pstmt = conn.prepareStatement(sql);
- 设置参数值
pstmt.setString(1, userName);
pstmt.setString(2, password);
PreparedStatement对象:setXxx(参数1,参数2):给 ? 赋值
- Xxx:数据类型 ; 如 setInt (参数1,参数2)
参数:
- 参数1: ?的位置编号,从1 开始
- 参数2: ?的值
- 执行SQL
executeUpdate();
executeQuery(); // 不需要在传入sql语句
演示代码:
@Test
public void testPreparedStatement() throws Exception {
Connection coon = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "123456789");
String userName = "ddamhkhyug";
// sql注入
String password = "'or '1' = '1";
// 定义sql语句
String sql = "SELECT * from tb_user WHERE username = ? AND password = ?";
// 获取PrepareStatement对象
PreparedStatement pstmt = coon.prepareStatement(sql);
// 设置sql语句中?的值
pstmt.setString(1, userName);
pstmt.setString(2, password);
// 执行sql
ResultSet rs = pstmt.executeQuery();
// 判断登录是否成功
if (rs.next()) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
pstmt.close();
rs.close();
coon.close();
}
PreparedStatement 好处, 除了防止SQL注入, 将敏感字符进行转义之外; 还可以预编译SQL,性能更高
PreparedStatement 预编译功能开启:url添加参数
useServerPrepStmts=true
Connection coon = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true",
"root", "123456789");