1.什么是JDBC?
1.1 JDBC概念
全称:(Java Database Connectivity,简称JDBC)Java数据库连接
JDBC是Java语言中用来规范客户端和数据库之间连接的应用程序接口,提供了对数据库进行增删改查等方法。
1.2 JDBC的优缺点
优点:
- 提供了一系列API使得我们能通过写同一套Java程序来对不同的关系型数据库进行操作。(只需导入不同数据库的jar包即可)
缺点:
- 主要缺点是硬编码严重,当实际开发中SQL要求发生变化时需要修改Java代码,扩展性差。
- 频繁创建数据库连接对象,资源损耗大。(可以通过创建Druid(德鲁伊)数据库连接池解决)
2.JDBC主要API
2.1 DriverManager
String url = "jdbc:mysql:///db1?useSSL=false";//数据库连接路径
String username = "root";//用户名
String password = "1234";//密码
Connection conn = DriverManager.getConnection(url, username, password);
在MySQL 5之前还需要单独进行注册驱动,在MySQL 5 之后Driver类会自动注册驱动,所以可以省去如下代码。
Class.forName("com.mysql.jdbc.Driver");//注册驱动
2.2 Connection
作用:获得数据库连接;进行增删改查的事务管理
//建立数据库连接
Connection conn = DriverManager.getConnection(url, username, password);
- 开启事务
因为MySQL默认是自动提交事务,所以需要将自动提交设置为false才能手动管理事务
// 开启事务
conn.setAutoCommit(false);//不自动提交
- 提交事务
// 提交事务
conn.commit();
- 事务回滚
回滚事务一般在catch{}语句中运行,即在try{}中开启和提交事务,出现异常时再回滚事务
// 回滚事务
conn.rollback();
2.3 Statement
作用:执行SQL语句
执行DDL和DML语句时使用的方法为executeUpdate()(实际中很少在java中写DDL语句)
//定义sql
String sql = "update account set money = 3000 where id = 1";//SQL语句
//获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//执行sql
int count = stmt.executeUpdate(sql);//执行完DML语句,返回值为被修的行数
执行DQL语句时使用的方法为executeQuery(),其返回结果不再是被修改的行数,而是ResultSet对象。
2.4 ResultSet
作用:封装DQL查询语句的返回结果
ResultSet rs = stmt.executeQuery(sql);//封装查询结果
由于DQL查询返回的为结果集,所以ResultSet提供了指针next()方法,返回值为boolean类型。
然后通过getInt()、getString()等方法来获取数据。
如下图所示,当执行完DQL语句时,返回的ResultSet的结果集的指针为数据表的表头
此时调用next()方法,在通过getInt("id")方法即可获得数据行第一行的id,即 id=1;也可调用getString("name")方法获得名字,即 name="王大锤";
2.5 PreparedStatement
作用:执行SQL语句,与Statement不同的是PreparedStatement在执行前会将SQL语句的参数值用 ?占位符替换并且会进行SQL的预编译,可以防止SQL注入
因为使用了?占位符,所以要对?的值进行设置,其他的操作与Statement一致
// 定义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);
其中setString()方法也可由setInt()等方法替换,由参数类型而定。
setString(1,name)表示第 1 个 ?的值为name;
setString(2,pwd)表示第 2 个 ?的值为pwd;
PreparedStatement原理
- 将sql语句发送到MySQL服务器端
- MySQL服务端会对sql语句进行如下操作
- 检查SQL语句。检查SQL语句的语法是否正确。
-
编译SQL语句。将SQL语句编译成可执行的函数。检查SQL和编译SQL花费的时间比执行SQL的时间还要长。如果我们只是重新设置参数,那么检查SQL语句和编译SQL语句将不需要重复执行。这样就提高了性能。
-
执行SQL语句。
防SQL注入原理:在检查输入时会对特殊字符进行转义处理。如 输入的pwd ="' or '1' = '1" 时,程序会自动将字符 “ ' ”转义成“ \' ”,所以避免了对SQL语句的影响。
完整流程代码实例
public void testPreparedStatement() throws Exception {
//加载驱动,建立链接
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用户输入 用户名和密码
String name = "zhangsan";
String pwd = "' or '1' = '1";
// 定义sql
String sql = "select * from tb_user where username = ? and password = ?";
try {
// 开启事务
conn.setAutoCommit(false);
// 获取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();
} catch (Exception throwables) {
// 回滚事务
conn.rollback();
throwables.printStackTrace();
}
}