2.JDBC
JDBC是什么?
- Java Database Connectivity,简称JDBC(Java语言来连接数据库)
JDBC本质是什么?
- JDBC是SUN公司制定的一套接口(interface)
- java.sql. *;(这个软件包下有很多接口。)
- 接口都有调用者和实现者。
- 面向接口调用、面向接口写实现类,这都属于面向接口编程。
- 为什么要面向接口编程?
- 解耦合:降低程序的耦合度,提高程序的扩展力.
- 多态机制就是非常典型的:面向抽象编程。(不要面向具体编程)
建议:
不建议:Animal a = new cat() ; Animal a = new Dog () ;//喂养的方法 public void feed(Animal a) { //面向父类型编程。 )
Dog d = new Dog () ; cat c = new cat( ;
- 为什么要面向接口编程?
- 思考:为什么sun要制订一套jdbc接口呢?
因为每一个数据库的底层实现原理都不一样。
oracle数据库有自己的原理。
MysQL数据库也有自己的原理。
Ms sqlserver数据库也有自己的原理。
…
每一个数据库产品都有自己独特的实现原理。- 图解:
- 图解:
- JDBC本质到底是什么?
一套接口
JDBC开发前的准备工作是什么?
先从官网下载对应的驱动jar包,然后将其配置到环境变量classpath当中。
- classpath=.;D: \course\06-JDBC\resourcesMysq1 connector Java 5.1.23\mysq1-connector-java-5.1.23-bin.jar
以上的配置是针对于文本编辑器的方式开发,使用IDEA工具的时候,不需要配置以上的环境变量。工DA有自己的配置方式。
JDBC编程六步的概述
第一步:注册驱动 (作用:告诉Java程序,即将要连接的是哪个品牌的数据库)
第二步:获取连接(表示jvm的进程和数据库进程之间的通道打开了这属于金承志假案的通信,重量级的,是用完之后一定要关闭)
第三步:获取数据库操作对象(专门执行SQL语句的对象)
第四步:执行SQL语句(DQL,DML…)
第五步:处理查询结果集(只有当第四步执行的是select语句的时候,才有这第五步处理查询结果集)
第六步:释放资源(使用完资源一定要关闭资源,Java和数据库属于进程间的通信,开启后一定要关闭!)
- 实例1: 执行的是添加语句
package com.buba.JDBC;
import java.sql.*;
public class JDBCTest01 {
public static void main(String[] args) {
Statement statement = null;
Connection conn = null;
try {
//1.注册驱动
Driver driver = new com.mysql.jdbc.Driver();//多态 父类型指向子类型对象
DriverManager.registerDriver(driver);
//2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/text1?serverTimezone=Asia/Shanghai";
String user = "root";
String password = "root";
conn = DriverManager.getConnection(url,user,password);
System.out.println("数据库连接对象="+conn);
//3.获取数据库操作对象(statement专门执行SQL语句的)
statement = conn.createStatement();
//4.执行SQL语句
String sql = "insert into class(cid,caption) value(4,'1234567890')";
//专门执行DM江语句的(insert delete update)
// 返回值是"影响数据库中的记录条数"
int count = statement.executeUpdate(sql) ;
System.out.println (count == 1 ?"保存成功":"保存失败");
} catch (SQLException e) {
e.printStackTrace();
}finally {
//6.释放资源
//为了保证资源一定释放 在finally语句块中释放资源
//必须遵循从小到大依次关闭
//分别对其try catch
if (statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
- 实例2.:执行的是删除和修改语句
package com.buba.JDBC;
import java.sql.*;
public class JDBCTest02 {
public static void main(String[] args) {
Statement statement = null;
Connection conn = null;
try {
//1.注册驱动
Driver driver = new com.mysql.jdbc.Driver();//多态 父类型指向子类型对象
DriverManager.registerDriver(driver);
//2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/text1?serverTimezone=Asia/Shanghai";
String user = "root";
String password = "root";
conn = DriverManager.getConnection(url,user,password);
System.out.println("数据库连接对象="+conn);
//3.获取数据库操作对象(statement专门执行SQL语句的)
statement = conn.createStatement();
//4.执行SQL语句
//String sql = "delete from class where cid = 4";
//jdbc中的SQL语句不需要提供分号结尾
String sql = "update class set cid=4,caption='你好吗' where cid = 3";
//专门执行DM江语句的(insert delete update)
// 返回值是"影响数据库中的记录条数"
int count = statement.executeUpdate(sql) ;
System.out.println (count == 1 ?"删除成功":"删除失败");
} catch (SQLException e) {
e.printStackTrace();
}finally {
//6.释放资源
//为了保证资源一定释放 在finally语句块中释放资源
//必须遵循从小到大依次关闭
//分别对其try catch
if (statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
- 实例3: 查询语句.别着急啊 在下面呢 往下翻呀!
注册驱动的两种方式
在上面的实例中已经写出了一种:
- 第一种:
DriverManager.registerDriver(new com.mysql.jdbc.Driver());//多态 父类型指向子类型对象
- 第二种(常用的):
- 为什么这种方式常用?因为参数是一个字符串,字符串可以写到xxx.properties文件中。
- 以下方法不需要接收返回值,因为我们只想用它的类加载动作。
Class.forName("com.mysql.jdbc.Driver");
处理查询结果集
- 实例3:查询语句!
处理查询结果集也称为遍历结果集,话不多说上代码:
package com.buba.JDBC;
import java.sql.*;
public class JDBCTest04 {
public static void main(String[] args) {
Statement statement = null;
Connection conn = null;
ResultSet rs = null;
try {
//1.注册驱动
Driver driver = new com.mysql.jdbc.Driver();//多态 父类型指向子类型对象
DriverManager.registerDriver(driver);
//2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/text1?serverTimezone=Asia/Shanghai";
String user = "root";
String password = "root";
conn = DriverManager.getConnection(url,user,password);
System.out.println("数据库连接对象="+conn);
//3.获取数据库操作对象(statement专门执行SQL语句的)
statement = conn.createStatement();
//4.执行SQL语句
// int executeUpdate(insert delete update)
// ResultSet executeQuery(select)
String sql = "select * from class";
rs = statement.executeQuery(sql); //专门执行DQL语句的方法,
//5.处理查询结果集
//如果为真 说明光标指向的行有数据
//取数据
//getString()方法的特点是,不管数据库中的数据是什么类型,都已String形式取出
//以下程序说的 1 2 3是第几列
while(rs.next()){
//String cid = rs.getString(1); //jdbc中所有的下标从1开始.不是从0开始
//String caption = rs.getString(2);
//System.out.println(cid+","+caption);
//以下这个不是以下标获取 而是通过查询语句的列名获取
String cid = rs.getString("cid");
String caption = rs.getString("caption");
System.out.println(cid+","+caption);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
- 图解:
SQL注入
导致SQL注入的根本原因是什么?
- 用户输入的信息中含有sql语句的
关键字
,并且这些关键字参与sql语句的编译过程
,导致sql语句的原意被扭曲,进而达到sql注入。
怎么解决SQL注入问题?
- 只要用户提供的信息不参与SQL的编译过程 问题就解决了
- 即使用户提供的信息中含有SQL语句的关键字 但是不参与编译,就不会起作用
- 要想用户信息不参与SQL语句的编译 必须使用Java.sql.PreparedStatement
- PreparedStatement接口继承了java.sql.Statement
- PreparedStatement是属于预编译的数据库操作对象
- PreparedStatement的原理是,预先对SQL语句的框架进行编译,然后再给SQL语句传"值";
实例:
class JDBCTest05 {
public static void main(String[] args) {
// 初始化界面
Map<String,String> userLoginInfo = initUI();
// 验证用户名和密码
boolean loginSuccess = login(userLoginInfo);
// 输出最后结果
System.out.println(loginSuccess ? "登录成功" : "登录失败");
}
/**
* 用户登录
* @param userLoginInfo 用户登录信息
* @return true表示登录成功,false表示登录失败
*/
private static boolean login(Map<String, String> userLoginInfo) {
boolean loginSuccess = false;
//自定义变量
String username = userLoginInfo.get("username");
String password = userLoginInfo.get("password");
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 1、注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2、获取连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/text1?serverTimezone=Asia/Shanghai","root","root");
// 3、获取预编译的数据库操作对象
//SQL语句的框子 其中一个?代表一个占位符 一个?将来接收一个"值".注意: 占位符不能引用单引号括起来
String sql = "select * from login where username = ? and password = ?";
//程序执行到此处,会发送sql语句框子给DBMS,然后DBMS进行sql语句的预先编译。
ps = conn.prepareStatement(sql);
//给占位符?传值(第1个问号下标是1,第2个问号下标是2,JDBC中所有下标从1开始。)
ps.setString(1,"123");
ps.setString(2,"123");
// 4、执行sql语句
rs = ps.executeQuery();
// 5、处理结果集
if(rs.next()) {
loginSuccess = true;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
// 6、释放资源
if (rs != null) {
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return loginSuccess;
}
/**
* 初试化界面
* @return 用户输入的用户名和密码等登录信息
*/
private static Map<String, String> initUI() {
Scanner s = new Scanner(System.in);
System.out.print("请输入用户:");
String userName = s.nextLine();
System.out.print("请输入密码:");
String userPassword = s.nextLine();
Map<String,String> userLoginInfo = new HashMap<>();
userLoginInfo.put("userName",userName);
userLoginInfo.put("userPassword",userPassword);
return userLoginInfo;
}
}
测试结果:
请输入用户:123
请输入密码:456or
1=
1
登录失败
解决SQL注入的关键问题是什么?
- 用户提供的信息中即使含有sql语句的关键字,但是这些关键字并没有参与编译。不起作用