一、JDBC概念
JDBC就是使用Java语言操作关系型数据库的一套API
全称:(Java DataBase Connectivity) Java数据库连接
JDBC本质:
官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口
各个数据库厂商去实现这套接口,提供数据库驱动jar包
我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类
JDBC好处:
各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发
可随时替代底层数据库,访问数据库的Java代码基本不变
二、JDBC快速入门步骤
0、创建工程,导入驱动jar包
1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
2、获取连接
Connection conn = DriverManager.getConnection(url, username, password);
3、定义SQL语句
String sql = "SQL语句";
4、获取执行SQL对象
Statement stat = conn.createStatement();
5、执行SQL
stat.executeUpdate(sql);
6、处理返回结果
7、释放资源
代码示例:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; /** * JDBC快速入门 */ public class JDBCDemo1he2 { public static void main(String[] args) throws ClassNotFoundException, SQLException { //1、注册驱动 Class.forName("com.mysql.jdbc.Driver"); //2、获取连接:如果连接的是本机mysql并且端口是默认的3306,可以简化书写 String url = "jdbc:mysql:///db1?useUnicode=true&characterEncoding=utf8"; String username = "root"; String password = "199884lj"; Connection conn = DriverManager.getConnection(url, username, password); //3、定义sql String sql = "update stu set math = 90 where age = 55"; //4、获取执行sql的对象 Statement stat = conn.createStatement(); //5、执行sql int count = stat.executeUpdate(sql);//受影响的行数 //6、处理结束 System.out.println(count); //7、释放资源 stat.close(); conn.close(); } }
三、JDBC API详解
DriverManger(驱动管理类)
管理JDBC驱动程序的基本服务。
作用:1、注册驱动 2、获取数据库连接
一、注册驱动
有此Driver文件可自动读取文件在,自动注册驱动
二、获取数据库连接
static Connaction getConnaction (String usl,String user,String password)
参数
1、url:连接路径
语法:
jdbc:mysql://地址(域名):端口号/数据库名称?参数键值对1&参数键值对2...
示例:
jdbc:mysql://127.0.0.1:3306/db1
细节:
如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则usl可以简写为:jdbc:mysql:///数据库名称?参数键值对
2、user:用户名
3、password:密码
Connection(数据库连接对象)
与特定数据库连接(会话)。执行SQL语句并在连接的上下文中返回结果。
作用:1、获取执行SQL的对象 2、管理事务
1、获取执行SQL对象
普通执行SQL对象
Statement createStatement()
预编译SQL的执行SQL对象:防止SQL注入
PreparedStatement prepareStatement(sql)
执行存储过程的对象
CallableStatement prepareCall(sql)
2、事务管理
MySQL事务管理
开启事务:
BEGIN;/START TRANSACTION;
提交事务:
COMMIT;
回滚事务:
ROLLBACK;
MySQL默认自动提交事务
JDBC事务管理:Connection接口中定义了3个对应的方法
开启事务:
setAutoCommit(boolean autoCommit):true为自动提交事务;false为手动提交事务,即为开启事务
提交事务:
commit()
回滚事务:
rollback()
代码示例
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; /** * JDBC API 详解:Connection */ public class JDBCDemo3_Connection { public static void main(String[] args) throws Exception { //1、注册驱动,在mysql的jar包下添加java.sql.Driver这个文件即可以省去手动注册驱动 // Class.forName("com.mysql.jdbc.Driver"); //2、获取连接:如果连接的是本机mysql并且端口是默认的3306,可以简化书写 String url = "jdbc:mysql:///db1?useUnicode=true&characterEncoding=utf8"; String username = "root"; String password = "xxxxxxxx"; Connection conn = DriverManager.getConnection(url, username, password); //3、定义sql String sql1 = "update stu set math = 300 where id = 1"; String sql2 = "update stu set math = 300 where id = 2"; //4、获取执行sql的对象 Statement stat = conn.createStatement(); try { //开启事务 conn.setAutoCommit(false); //5、执行sql int count1 = stat.executeUpdate(sql1);//受影响的行数 //6、处理结束 System.out.println(count1); //5、执行sql int count2 = stat.executeUpdate(sql2);//受影响的行数 //6、处理结束 System.out.println(count2); //提交事务 conn.commit(); } catch (Exception e) { //回滚事务 conn.rollback(); e.printStackTrace(); } //7、释放资源 stat.close(); conn.close(); } }
执行结果:
Statement(执行SQL语句)
用于执行静态SQL语句并返回其生成的结果的对象。
作用:执行SQL语句
int executeUpdate(sql):执行DML、DDL语句
返回值:1、DML语句影响的行数 2、DDL语句执行后,执行成功也可能返回0
ResultSet executeQuery(sql):执行DQL语句
返回值:ResultSet结果集对象
代码示例:
import org.junit.Test; import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; /** * JDBC API 详解:Statement */ public class JDBCDemo4_Statement { /** * 执行DML语句 * * @throws Exception */ @Test public void testDML() throws Exception { //1、注册驱动,在mysql的jar包下添加java.sql.Driver这个文件即可以省去手动注册驱动 // Class.forName("com.mysql.jdbc.Driver"); //2、获取连接:如果连接的是本机mysql并且端口是默认的3306,可以简化书写 String url = "jdbc:mysql:///db1?useUnicode=true&characterEncoding=utf8"; String username = "root"; String password = "xxxxxxx"; Connection conn = DriverManager.getConnection(url, username, password); //3、定义sql String sql = "update stu set math = 90 where id=1"; //4、获取执行sql的对象 Statement stat = conn.createStatement(); //5、执行sql int count = stat.executeUpdate(sql);//执行完DML语句,受影响的行数 //6、处理结束 //System.out.println(count); if (count > 0) { System.out.println("修改成功"); } else { System.out.println("修改失败"); } //7、释放资源 stat.close(); conn.close(); } /** * 执行DDL语句 * @throws Exception */ @Test public void testDDDL() throws Exception { //1、注册驱动,在mysql的jar包下添加java.sql.Driver这个文件即可以省去手动注册驱动 // Class.forName("com.mysql.jdbc.Driver"); //2、获取连接:如果连接的是本机mysql并且端口是默认的3306,可以简化书写 String url = "jdbc:mysql:///db1?useUnicode=true&characterEncoding=utf8"; String username = "root"; String password = "xxxxxxxx"; Connection conn = DriverManager.getConnection(url, username, password); //3、定义sql String sql = "drop database db2"; //4、获取执行sql的对象 Statement stat = conn.createStatement(); //5、执行sql int count = stat.executeUpdate(sql);//执行完DDL语句,可能是0 //6、释放资源 stat.close(); conn.close(); } }
运行结果:
ResultSet(结果集对象)
ResultSet作用:
1、封装了DQL查询语句的结果
ResultSet stmt.executeQuery(sql):执行DQL语句,返回ResultSet对象
获取查询结果
boolean next():1、将光标从当前位置向前移动一行 2、判断当前行是否为有效行
返回值:
1、true:有效行,当前行有数据
2、false:无效行,当前行没有数据
xxx getXxx(参数):获取数据
xxx:数据类型;如:int getInt(参数);String getString(参数
参数
int:列的编号,从1开始
String:列的名称
代码示例:
import com.itheima.pojo.Account; import org.junit.Test; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.ArrayList; import java.util.List; /** * JDBC API 详解:Result */ public class JDBCDemo5_ResultSet { /** * 执行DQl语句 * @throws Exception */ @Test public void testResultSet() throws Exception { //1、注册驱动,在mysql的jar包下添加java.sql.Driver这个文件即可以省去手动注册驱动 // Class.forName("com.mysql.jdbc.Driver"); //2、获取连接:如果连接的是本机mysql并且端口是默认的3306,可以简化书写 String url = "jdbc:mysql:///db1?useUnicode=true&characterEncoding=utf8"; String username = "root"; String password = "xxxxxxx"; Connection conn = DriverManager.getConnection(url, username, password); //3、定义sql String sql = "select * from stu"; //4、获取statement对象 Statement stmt = conn.createStatement(); //5、执行sql ResultSet rs = stmt.executeQuery(sql); //处理结果,遍历rs中的所有数值 //6.1 光标向下移动一行,并且判断当前行是否有数据 // while(rs.next()){ // //6.2 获取数据 getXxx() // int id = rs.getInt(1); // String name = rs.getString(2); // // System.out.println(id); // System.out.println(name); // // System.out.println("---------------"); // } while(rs.next()){ //6.2 获取数据 getXxx() int id = rs.getInt("id"); String name = rs.getString("name"); System.out.println(id); System.out.println(name); System.out.println("---------------"); } //7、释放资源 rs.close(); stmt.close(); conn.close(); } /** * 查看account账户表数据,封装为Account对象中,并且存储到ArrayList集合中 * 1、定义实体类Account * 2、查询数据,封装到Account对象中 * 3、将Account对象存入ArrayList集合中 * * * @throws Exception */ @Test public void testResultSet2() throws Exception { //1、注册驱动,在mysql的jar包下添加java.sql.Driver这个文件即可以省去手动注册驱动 // Class.forName("com.mysql.jdbc.Driver"); //2、获取连接:如果连接的是本机mysql并且端口是默认的3306,可以简化书写 String url = "jdbc:mysql:///db1?useUnicode=true&characterEncoding=utf8"; String username = "root"; String password = "xxxxxx"; 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<>(); while(rs.next()){ Account account = new Account(); //6.2 获取数据 getXxx() int id = rs.getInt("id"); String name = rs.getString("name"); int money = rs.getInt("money"); //赋值 account.setId(id); account.setName(name); account.setMoney(money); //存入集合 list.add(account); } System.out.println(list); //7、释放资源 rs.close(); stmt.close(); conn.close(); } }
运行结果:
PreparedStatement(预编译SQL语句的对象)
作用:预编译SQL语句并执行,预防SQL注入问题
SQL注入
SQL注入是通过操作输入来修改事先定义号的SQL语句,用以达到执行代码对服务器进行攻击的方法。
SQL注入演示:
import com.itheima.pojo.Account; import org.junit.Test; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.ArrayList; import java.util.List; /** * 用户登录 */ public class JDBCDemo6_UserLogin { @Test public void testResultSet() throws Exception { //2、获取连接:如果连接的是本机mysql并且端口是默认的3306,可以简化书写 String url = "jdbc:mysql:///db1?useUnicode=true&characterEncoding=utf8"; String username = "root"; String password = "199884lj"; Connection conn = DriverManager.getConnection(url, username, password); //接收用户输入 用户名和密码 String name = "zhangsan"; String pwd = "2"; String sql = "select * from tb_user where username = '" + name + "' and password = '" + pwd + "'"; //获取stmt对象 Statement stmt = conn.createStatement(); //执行sql ResultSet rs = stmt.executeQuery(sql); //判断登录是否成功 if (rs.next()) { System.out.println("登录成功"); } else { System.out.println("登录失败"); } //7、释放资源 rs.close(); stmt.close(); conn.close(); } /** * 演示SQL注入 * @throws Exception */ @Test public void testLogin_Inject() throws Exception { //2、获取连接:如果连接的是本机mysql并且端口是默认的3306,可以简化书写 String url = "jdbc:mysql:///db1?useUnicode=true&characterEncoding=utf8"; String username = "root"; String password = "199884lj"; Connection conn = DriverManager.getConnection(url, username, password); //接收用户输入 用户名和密码 String name = "sdbabasdga"; 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("登录失败"); } //7、释放资源 rs.close(); stmt.close(); conn.close(); } }
运行结果:
sql注入语句
select * from tb_user where username 'sdbabasdga' and password = ' ' or '1' = '1'
1、获取PreparedStatement对象
//SQL语句中的参数值,使用?占位符替代 String sql = "select * from tb_user where username = ? and password = ?"; //通过Connection对象获取,并传入对应的sql语句 PreparedStatement pstmt = conn.prepareStatement(sql);
2、设置参数值
PreparedStatement对象:setXxx(参数1,参数2):给?赋值
Xxx:数据类型:如setInt(参数1,参数2)
参数:
参数1:?的位置编号,从1开始
参数2:?的值
3、执行SQL
executeUpdate();/executeQuery();:不需要再传递sql
PreparedStatement好处:
1、预编译SQL,性能更高
2、防止SQL注入:将敏感字符进行转义
①PreparedStatement 预编译功能开启:useServerPrepStmts=true
②配置MySQL执行日志(重启mysql服务后生效)
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
PrepareStatement原理:
1、在获取PreparedStatement对象时,将sql语句发送给mysql服务检查,编译(这些步骤很耗时)
2、执行时就不用再进行这些步骤,速度更快
3、如果sql模板一样,则只需要进行一次检查、编译
代码示例:
import org.junit.Test; import java.sql.*; /** * API详解 PreparedStatement */ public class JDBCDemo7_PreparedStatement { @Test public void testPreparedStatement() throws Exception { //2、获取连接:如果连接的是本机mysql并且端口是默认的3306,可以简化书写 String url = "jdbc:mysql:///db1?useUnicode=true&characterEncoding=utf8"; String username = "root"; String password = "xxxxxxxx"; Connection conn = DriverManager.getConnection(url, username, password); //接收用户输入 用户名和密码 String name = "zhangsan"; String pwd = "123"; //定义sql String sql = "select * from tb_user where username = ? and password = ?"; //获取stmt对象 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(); } /** * PreparedStatement原理 * @throws Exception */ @Test public void testPreparedStatement2() throws Exception { //2、获取连接:如果连接的是本机mysql并且端口是默认的3306,可以简化书写 String url = "jdbc:mysql:///db1?useUnicode=true&characterEncoding=utf8"; String username = "root"; String password = "xxxxxxx"; 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 = ?"; //获取stmt对象 PreparedStatement pstmt = conn.prepareStatement(sql); //设置?的值 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(); } }
运行结果: