简介
JDBC概念:
- JDBC就是使用java语言操作关系型数据库的一套API
-
全称:(Java Database Connectivity)java数据库连接
JDBC本质:
- 官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口
- 各个数据库厂商去实现这套接口,提供数据库驱动jar包
- 我们可以使用这套接口(JABC)编程,真正执行代码的是驱动jar包中的实现类
JDBC好处:
- 各数据库厂商使用相同的接口,Java代码不需要针对不同的数据库分别开发
- 可以随时替换底层数据库,访问数据库的Java代码基本不变
JDBC快速入门
创建工程,导入驱动jar包
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2、获取连接
String url = "jdbc:mysql://localhost:3306/db_school";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
//定义sql语句
String sql = "UPDATE account SET money = 2000 WHERE id = 1";
//获取sql对象
Statement stmt = conn.createStatement();
//执行sql 返回修改的行数
int count = stmt.executeUpdate(sql);
//处理返回的数据
System.out.println(count);
//释放资源
stmt.close();
conn.close();
JDBC的API
DriverManager(驱动管理类)
作用:
-
注册驱动
-
Class.forName("com.mysql.jdbc.Driver");
-
获取数据库连接
-
url:连接路径
- 语法:jdbc:mysql://ip地址(域名):端口号/数据库名?参数值对1&参数值对2…
-
细节:
- 如果连接的是本地mysql服务器,并且mysql服务器默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称?参数值对
- 配置useSSL=false参数,禁用安全连接方式,解决警告提示
- user:用户名
- password:密码
-
url:连接路径
提示:
- mysql 5之后的驱动包,可以省略注册驱动的步骤
- 自动加载jar包中META-INF/services/java.sql.Driver中的驱动类
Connection
作用:
-
获取执行sql的对象
-
普通执行SQL对象
-
Statement createStatement()
-
预编译SQL的执行SQL对象:防止sql注入
-
PreparedStatement preparedStatement(sql)
-
执行存储过程的对象
-
CallableStatement prepareCall(sql)
-
-
管理事务
-
mysql事务管理
开启事务:BEGIN; /START TRANSACTION; 提交事务:COMMIT; 回滚事务:ROLLBACK; mysql默认自动提交事务
-
JDBC事务管理:Connection接口中定义了3个对应的方法
开启事务:setAutoCommit(boolean autoCommit):true为自动提交事务;false为手动提交事务,即为开启事务 提交事务:commit() 回滚事务:rollback()
-
Statement
-
Startment的作用:
- 执行SQL语句
-
执行SQL语句
int executeUpdate(sql):执行DML、DDL语句 返回值:(1)DML语句影响的行数(2)DDL语句执行后,执行成功也可以返回0
ResultSet executeQuery(sql):执行DQL语句 返回值:ResultSet结果对象
ResultSet
-
ResultSet(结果集对象)作用
-
封装了DQL查询语句的结果
ResultSet stmt.executeQuery(sql):执行DQL语句,返回ResultSet对象
-
-
获取查询结果
boolean next():(1)将光标从当前位置向前移动一行(2)判断当前行是否为有效行 返回值: true:有效行,当前行有数据 false:无效行,当前行没数据
xxx getXxx(参数):获取数据 xxx:数据类型;如:int getInt(参数);String getString(参数) 参数: int:列的编号,从1开始 String:列的名称
-
使用步骤
-
游标向下移动一行,并判断该行是否有数据:next()
-
获取数据:getXxx(参数)
//循环判断游标是否是最后一行末尾 while(rs.next()){ //获取数据 rs.getXxx(参数); }
-
PreparedStatement
-
PreparedStatement的作用:
- 预编译SQL语句并执行:预防sql注入问题
-
SQL注入
- SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方式。
-
PreparedStatement
-
获取PreparedStatement对象
//sql语句中的参数值用?占位代替 String = "select * from user where username = ? and password = ?"; //通过Connection对象获取,并传入对应的SQL语句 PreparedStatement pstmt = conn.prepareStatement(sql);
-
设置参数
PreparedSement对象:setXxx(参数1,参数2):给?赋值 Xxx:数据类型 参数: 参数1:?的位置编号,从1开始 参数2:?的值
-
执行SQL
executeUpdate();/executeQuery(); //不再需要传递sql
-
PreparedStatement原理
PreparedStatement 好处:
- 预编译SQL,性能更高
- 防止SQL注入:
将敏感字符进行转义
Java代码操作数据库流程如图所示:
-
将sql语句发送到MySQL服务器端
-
MySQL服务端会对sql语句进行如下操作
-
检查SQL语句
检查SQL语句的语法是否正确。
-
编译SQL语句。将SQL语句编译成可执行的函数。
检查SQL和编译SQL花费的时间比执行SQL的时间还要长。如果我们只是重新设置参数,那么检查SQL语句和编译SQL语句将不需要重复执行。这样就提高了性能。
-
执行SQL语句
-
接下来我们通过查询日志来看一下原理。
-
开启预编译功能
在代码中编写url时需要加上以下参数。而我们之前根本就没有开启预编译功能,只是解决了SQL注入漏洞。
useServerPrepStmts=true
-
配置MySQL执行日志(重启mysql服务后生效)
在mysql配置文件(my.ini)中添加如下配置
log-output=FILE general-log=1 general_log_file="D:\mysql.log" slow-query-log=1 slow_query_log_file="D:\mysql_slow.log" long_query_time=2
-
java测试代码如下:
/** * PreparedStatement原理 * @throws Exception */ @Test public void testPreparedStatement2() throws Exception { //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写 // useServerPrepStmts=true 参数开启预编译功能 String url = "jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true"; 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 = ?"; // 获取pstmt对象 PreparedStatement pstmt = conn.prepareStatement(sql); Thread.sleep(10000); // 设置?的值 pstmt.setString(1,name); pstmt.setString(2,pwd); ResultSet rs = null; // 执行sql rs = pstmt.executeQuery(); // 设置?的值 pstmt.setString(1,"aaa"); pstmt.setString(2,"bbb"); // 执行sql rs = pstmt.executeQuery(); // 判断登录是否成功 if(rs.next()){ System.out.println("登录成功~"); }else{ System.out.println("登录失败~"); } //7. 释放资源 rs.close(); pstmt.close(); conn.close(); }
-
执行SQL语句,查看
D:\mysql.log
日志如下:
上图中第三行中的
Prepare
是对SQL语句进行预编译。第四行和第五行是执行了两次SQL语句,而第二次执行前并没有对SQL进行预编译。