JDBC:
虽然由于快节奏的开发,编程速度的追求,越爱越多的MVC框架出现,比如持久层的hibernate,
mybatis等等,他们对Dao层的支持都很强大,既快速,又简便。但是他们的底层同样是使用了JDBC,
为了追求高速简便,我们可以不使用JDBC,但一定要了解JDBC。了解JDBC也有助于学习其他持久层框架。
java和数据库交互需要中间程序作为中转。在很早以前,数据库厂商还没有一套统一的API作为
java语言和数据库的接口,开发程序是一件很头疼的事。对不同的数据库需要写不同的程序来作为交互。
java访问-----oracle程序-----oracle数据库
java访问------mysql程序------mysql数据库
java访问-------db2程序--------db2数据库
那到底什么是JDBC呢:
JDBC是代表Java数据库连接,这对java编程语言和广泛的数据库之间独立于数据库的连接标准的Java API
有了JDBC开发就统一了很多。
java访问-----JDBC程序-----oracle数据库
java访问------JDBC 程序------mysql数据库
java访问------JDBC 程序--------db2数据库
以下简介JDBC针对oracl和mysql数据库。
oracle提供的jdbc接口的实现类-------ojdbc5.jar------jdk5.0 ojdbc6.jar-----jdk6.0
mysql提供的jdbc接口实现类--------mysql-connector-java-6.0.6
如果要开发JDBC程序,必然少不了这些jar包。下载可以去官网
https://dev.mysql.com/downloads/connector/
JDBC常用API简介:
java.sql.Connection:代表一个数据库连接;
java.sql.Statement:发送sql语句1至数据库;(发送sql的工具)
DriverManager:(类) 管理多个数据库驱动类
java.sql.ResultSet:结果集,存放查询语句执行后返回的数据结果
下图1.0为JDBC访问数据库流程
图1.0
JDBC开发步骤
1: 加载驱动
如果是oracle数据库:
将oracle ojdbc.jar 复制到项目里,点击项目,右键build path --add to buidpath
Class.forName("oracle.jdbc.OracleDriver");
如果是mysql数据库:
将mysql mysql-connector-java-6.0.6-bin 复制到项目里,build path --add to buidpath
Class.forName("com.mysql.jdbc.Driver") ;
2:连接数据库
user:root----数据库用户名
password:root------数据库密码
url: oracle ----协议 :子协议 :thin:@ip:端口:SID(SID数据库的实例名)。
eg:String url = "jdbc:oracle:thin:@localhost:1521:XE";
url:mysql ------ 协议:子协议://ip:端口:数据库名
eg:String url = "jdbc:mysql://localhost:3306/zdx";
3:准备sql
sql字符串中不能有分号;
4:Statement将sql发送至数据库
int i= executeUpdate(sql); //返回受影响的行数
5:如果是查询语句,返回结果集,处理ResultSet。
6:关闭连接,释放资源,按照先打开后关闭的原则。
以上6步骤时开发JDBC程序的标准步骤。
ResultSet结果集简介及使用方法:
ResultSet结果集:存放查询结果数据。
ResultSet rs = Statement.executeQuery();
rs指针初始位置在第一行数据之前
boolean rs.next(): ,
将rs的指针向下移动一位,当前行无数据返回false,有数据返回true,并获得查询数据。
提供一组getXXX(int列序号或String列名)方法用于取得数据
以上是JDBC简介,下面是JDBC例子,例子才是王道。
JDBC1.0版本------是1.0版本。后面还会有更优秀的版本娓娓道来!
JDBC_ResultSet.java
public class JDBC_ResultSet {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1:加载驱动
//Class.forName("oracle.jdbc.OracleDriver");
Class.forName("com.mysql.jdbc.Driver");
//2:获得数据库连接
String user = "root";
String password = "root";
//String url = "jdbc:oracle:thin:@localhost:1521:XE";
String url = "jdbc:mysql://localhost:3306/zdx?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url,user,password);
//3:准备sql
String sql = "select * from student";
//4:创建Statement,发送sql
Statement stm = conn.createStatement();//获的statement对象
//5:如果是查询,处理结果集
ResultSet rs = stm.executeQuery(sql);
while(rs.next()){
int id = rs.getInt(1);
String name = rs.getString(2);
int age = rs.getInt(3);
String phone = rs.getString(4);
System.out.println(id+"---"+name+"---"+age+"---"+phone);
}
//6:关闭连接,释放资源,原则,先打开后关闭
stm.close();
conn.close();
}
}
到了此处,我们的JDBC1.0已经写完了,但是为什么说是1.0呢,因为这个版本有一个很大的漏洞。
没错,那就是——依赖注入问题。
===================华丽丽的分割线==============================
下面我们可以看这个例子
JDBC_Statement.java
public class JDBC_Statement {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("请输入卡号");
String card_id = sc.nextLine();
System.out.println("请输入密码");
String pwd = sc.nextLine();
//1:加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2:获得数据库连接
String user = "root";
String password = "root";
String url = "jdbc:mysql://localhost:3306/zdx?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url,user,password);
//3:准备sql
String sql = "select * from account where card_id ="+card_id
+" and password = '"+pwd+"'";
System.out.println(sql);
//4:创建Statement,发送sql
Statement stm = conn.createStatement();//获的statement对象
//5:如果是查询,处理结果集
ResultSet rs = stm.executeQuery(sql);
if(rs.next()){
System.out.println("可以取钱了");
}else{
System.out.println("密码账户不正确");
}
//6:关闭连接,释放资源,原则,先打开后关闭
stm.close();
conn.close();
}
}
这是一个银行取钱的例子,如代码所写。
数据库有这样一张account表,数据和字段如下:
现在在控制台输入卡号密码,卡号密码正确即可取钱,
错误即提示账户不正确。
现在控制台输入正确卡号密码
然后,我输入错误的卡号密码竟然也可以取钱!输入错误的卡号 “123 or 1=1 -- ”密码 "zxc"结果如下
可见依然能访问数据库,这对于银行可是致命性错误,密码错误还可以取钱。
这就是依赖注入引起的著名错误。
依靠人为输入破坏sql结构.
select * from account where id = 1001 or 1=1 -- and password = 'xxx'
这条sql里,其中--是sql里的注释 or 1=1 永远为真并且还是or连接,
所以这条sql只执行到 or 1=1 ,1=1又是恒等。所以跳过了密码。
为了解决这个问题,我们就要说PreparedStatement!
PreparedStatement简介及使用
PreparedStatement构建动态SQL,通过PreparedStatement执行SQL语句,解决注入***。
PreparedStatement是Statement的子接口。
通过连接创建PreparedStatement,创建时将SQL语句中发生变化的部分用占位符“?“ 代替。
功能:和statement一样,发送sql语句。
但是执行多个同构sql效率高。同构sql能省去①②③步骤。
使用步骤:
1.创建pstm
String sql = "select * from account where card_id = ? and password = ?"
PreparedStateement pstm = conn.prepareStatement(sql);
①验证权限
②验证语法
③将sql转换内部指令
2.绑定参数
pstm.setInt(1,值);
pstm.setString(2,值);
3.发送绑定参数至DB数据库
pstm.executeUpdate();//曾删改
pstm.executedQuery();//查询
④执行内部指令操作数据库
mysql内部执行sql步骤:
①验证权限
②验证语法
③将sql转换内部指令
④执行内部指令操作数据库
使用PareparedStatement解决注入***问题后的代码如下:
JDBC2.0版本 是2.0版本>_< 。后面还会有更优秀的版本娓娓道来!
JDBC_PreparedStatement.java
public class JDBC_PreparedStatement {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("请输入卡号");
String card_id = sc.nextLine();
System.out.println("请输入密码");
String pwd = sc.nextLine();
//1:加载驱动
//Class.forName("com.mysql.jdbc.Driver");
//2:获得数据库连接
String user = "root";
String password = "root";
String url = "jdbc:mysql://localhost:3306/zdx?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url,user,password);
//3:准备sql
String sql = "select * from account where card_id =? and password =?";
PreparedStatement pstm = conn.prepareStatement(sql);
pstm.setInt(1, Integer.valueOf(card_id));
pstm.setString(2, pwd);
//5:如果是查询,处理结果集
ResultSet rs = pstm.executeQuery();
if(rs.next()){
System.out.println("可以取钱了");
}else{
System.out.println("密码账户不正确");
}
//6:关闭连接,释放资源,原则,先打开后关闭
rs.close();
pstm.close();
conn.close();
}
}
现在用PreparedStatement程序执行,输入卡号,密码
出现异常,不会再出现密码错误却取钱的问题了!!!
总结对比一下 Statement 和PreparedStatement
Statement | PreparedStatement | |
关系 | 父接口 | 子接口 |
安全 | 存在注入隐患 | 解决sql注入 |
效率 | 执行异构sql快 | 执行同构sql快 |
至此JDBC2.0结束。JDBC基本内容结束,以下是JDBC进阶内容。和优化版JDBC例子。
=====================华丽丽的分割线===========================
由于 篇幅有限,后续部分请参阅下篇博客。由浅到深学习JDBC二
不妥之处恳请读者批评指正,共同进步。
转载于:https://blog.51cto.com/zhangdongxu/1921704