大师网-带你快速走向大师之路 解决你在学习过程中的疑惑,带你快速进入大师之门。节省时间,提升效率

6.JDBC学习笔记

本文内容

1.什么是JDBC以及为什么要使用JDBC

2.JDBC核心API的讲解

3.使用JDBC核心API进行CRUD操作

4.JDBC的工具类的抽取与改进

5.JDBC的SQL注入漏洞分析与解决方案

6.使用JDBC的PreparedStatement预编译对象进行CRUD操作(重点)

7.JDBC的批处理操作

使用JDBC的预编译对象进行CRUD操作(重点)

[if !supportLists]1.1[endif]1.JDBC的概述

JDBC:(Java DataBase Connectivity Java数据库连接).

*是一种用于执行SQL语句的Java 的API.可以为多种关系型数据库提供统一的访问.它是由一组使用Java语言编写的类或接口组成.


简说:用java语言编写的一组用于访问关系型数据库的接口和类.


作用:使用Java语言连接到数据库


驱动:两个设备之间的通信桥梁.

Java语言要连接数据库必须使用数据库的驱动

本质:

SUN公司提供了一组接口,各个数据库生产商提供了这套接口的实现.(这组规范就是JDBC规范.)



[if !supportLists]1.2[endif]02_JDBC的入门(写)

先解释下,再写


设置工作空间的编码为utf-8

SQL脚本:

create database web_test3;

use web_test3;

create table user(

id int primary key auto_increment,

username varchar(20),

password varchar(20),

nickname varchar(20),

age int

);

insert into user values (null,'aaa','123','小丽',34);

insert into user values (null,'bbb','123','大王',32);

insert into user values (null,'ccc','123','小明',28);

insert into user values (null,'ddd','123','大黄',21);


引入数据库的驱动.


注意:复制驱动包过来后,一定要选中, add to Build Path


1.加载驱动.

2.获得连接.

获得语句(Statement )对象

3.执行SQL

4.释放资源.


publicclassJDBCDemo1 {

@Test

/**

* JDBC的入门

*/

publicvoiddemo1() throwsException{

// 1.加载驱动

Class.forName("com.mysql.jdbc.Driver");

// 2.获得连接

Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/web_test3", "root", "abc");//注意:密码改成你的密码

// 3.基本操作:执行SQL

// 3.1获得执行SQL语句的对象

Statement statement= conn.createStatement();

// 3.2编写SQL语句:

String sql= "select * from user";

// 3.3执行SQL:

ResultSet rs= statement.executeQuery(sql);

// 3.4遍历结果集:

while(rs.next()){

System.out.print(rs.getInt("id")+" ");

System.out.print(rs.getString("username")+" ");

System.out.print(rs.getString("password")+" ");

System.out.print(rs.getString("nickname")+" ");

System.out.print(rs.getInt("age"));

System.out.println();

}

// 4.释放资源

rs.close();

statement.close();

conn.close();

}

}



[if !supportLists]1.3[endif]03_DriverManager的介绍

问题:

DriverManager对象有什么作用?

为什么没有使用registerDriver()注册驱动?

获取连接的url路径的含义?


1.DriverManager对象两个作用:①、注册驱动和②、获取连接;




2.为什么使用没有使用registerDriver注册驱动?


DriverManager类:


原来这样写:

DriverManager.registerDriver(newcom.mysql.jdbc.Driver());


com.mysql.jdbc.Driver源码:


现在这样写:

Class.forName(“com.mysql.jdbc.Driver”);//强制加载class到内存


结论:直接调用registerDriver方法会导致驱动加载2次.


[if !supportLists]3.[endif]获取连接的url路径的含义?



[if !supportLists]1.4[endif]04_Connection的介绍

[if !supportLists][endif]Connection对象有哪些作用?


有两个作用:①、创建执行SQL的Statement(语句)对象;②、管理事务

作用一、创建执行sql语句的对象:

作用二:管理事务


总结:

[if !supportLists]1.[endif]Connection对象的作用?

获取语句对象

Statement

CallableStatement(后面Oracle说)

PreparedStatement

管理事务

setAutoCommit(false);//手动开启事务

...

...

commit()

rollback();



[if !supportLists]1.5[endif]05_Statement的介绍

[if !supportLists][endif]Statement对象有哪些作用?

有两个作用:①、执行sql语句;②、进行批处理


作用一:执行sql语句





作用二:进行批处理:就是把几条sql语句添加到Statement对象命令列表中,一次性执行多条sql语句。





[if !supportLists]1.6[endif]06_ResultSet的介绍

ResultSet代表select查询后的结果集


方法:


*向下移动光标.


*获得结果集中整形数据.


*获得结果集中字符串类型的数据:



...


遍历结果集:

* while(rs.next()){

int id = rs.getInt("id");

String username = rs.getString("username");

String password = rs.getString("password");

System.out.println(id+" "+username+" "+password);

}

获得结果集中的数据:

* int id = rs.getInt("id");

String username = rs.getString("username");

String password = rs.getString("password");


如果结果集中只有一条记录:

* if(rs.next()){

...

}

原理:



总结:

1. Result rs = statement.executeQuery(“select * from user”);

2.while(rs.next()) {

rs.getInt(“id”);

rs.getString(“username”);

rs.getObject(“password”);

rs.getInt(4);

}

[if !supportLists]1.7[endif]07_JDBC的资源的释放

Connection的使用原则:尽量要晚创建,尽量早释放!!!


try{

..

...

}catch(){...}

finally {....}


要掌握,看看代码,晚上写

[if !supportLists][endif]掌握释放资源标准代码:一般释放资源的代码放到finally里面去执行

finally{

//5、方法资源

if(resultSet!=null) {

try{

resultSet.close();

} catch(SQLException e) {

e.printStackTrace();

}

resultSet=null;

}

if(statement!=null) {

try{

statement.close();

} catch(SQLException e) {

e.printStackTrace();

}

statement=null;

}

if(conn!=null) {

try{

conn.close();

} catch(SQLException e) {

e.printStackTrace();

}

conn=null;

}

}



1、为什么对象调用了close()方法以后还要把对象手动赋值为null?



资源释放的一段标准代码:

// 4.释放资源.

if (rs != null) {

try {

rs.close();

} catch (SQLException e) {

e.printStackTrace();

}

rs = null; // 为了让JVM垃圾回收更早回收该对象.

}

if (stmt != null) {

try {

stmt.close();

} catch (SQLException e) {

e.printStackTrace();

}

stmt = null;

}


if (conn != null) {

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

conn = null;

}


总结:

try {

//加载驱动

//获取连接

//创建statement

//执行SQL

//遍历结果集

}catch(Exception ex) {


}finally {

//释放资源

rs,stat,conn

if (rs!=null) {

try {

rs.close();

}catch() {}

rs = null;

}


}



[if !supportLists]1.[endif]08_JDBC的CRUD操作之保存(写)

思路:

加载驱动

获得连接

获得Statement对象,执行SQL

释放资源


@Test

/**

*保存操作的代码实现

*/

publicvoiddemo1(){

Connection conn= null;

Statement stmt= null;

try{

//注册驱动:

Class.forName("com.mysql.jdbc.Driver");

//获得连接:

conn = DriverManager.getConnection("jdbc:mysql:///web_test3", "root", "abc");

//执行操作:

//创建执行SQL语句对象:

stmt = conn.createStatement();

//编写SQL语句:

String sql= "insert into user values (null,'eee','123','阿黄',21)";

//执行SQL语句:

intnum = stmt.executeUpdate(sql);

if(num> 0){

System.out.println("保存用户成功!!!");

}

}catch(Exception e){

e.printStackTrace();

}finally{

//资源释放:

if(stmt!= null){

try{

stmt.close();

} catch(SQLException e) {

e.printStackTrace();

}

stmt= null;

}

if(conn!= null){

try{

conn.close();

} catch(SQLException e) {

e.printStackTrace();

}

conn= null;

}

}

}


[if !supportLists]1.9[endif]09_JDBC的CRUD操作之修改操作(写)

@Test

/**

*修改操作的代码实现

*/

publicvoiddemo2(){

Connection conn= null;

Statement stmt= null;

try{

//注册驱动:

Class.forName("com.mysql.jdbc.Driver");

//获得连接

conn= DriverManager.getConnection("jdbc:mysql:///web_test3", "root", "abc");

//执行操作:

//创建执行SQL语句的对象:

stmt= conn.createStatement();

//编写SQL语句:

String sql = "update user set password='abc',nickname='旺财' where id = 5";

//执行SQL语句:

intnum= stmt.executeUpdate(sql);

if(num> 0){

System.out.println("修改用户成功!!!");

}

}catch(Exception e){

e.printStackTrace();

}finally{

//资源释放:

if(stmt!= null){

try{

stmt.close();

} catch(SQLException e) {

e.printStackTrace();

}

stmt= null;

}

if(conn!= null){

try{

conn.close();

} catch(SQLException e) {

e.printStackTrace();

}

conn= null;

}

}

}

[if !supportLists]1.10[endif]10_JDBC的CRUD操作之删除操作

@Test

/**

*删除操作的代码实现

*/

publicvoiddemo3(){

Connection conn= null;

Statement stmt= null;

try{

//注册驱动:

Class.forName("com.mysql.jdbc.Driver");

//获得连接:

conn= DriverManager.getConnection("jdbc:mysql:///web_test3", "root", "abc");

//创建执行SQL语句对象:

stmt= conn.createStatement();

//编写SQL:

String sql = "delete from user where id = 5";

//执行SQL:

intnum= stmt.executeUpdate(sql);

if(num> 0){

System.out.println("删除用户成功!!!");

}

}catch(Exception e){

e.printStackTrace();

}finally{

//资源释放:

if(stmt!= null){

try{

stmt.close();

} catch(SQLException e) {

e.printStackTrace();

}

stmt= null;

}

if(conn!= null){

try{

conn.close();

} catch(SQLException e) {

e.printStackTrace();

}

conn= null;

}

}

}


[if !supportLists]1.11[endif]11_JDBC的CRUD操作之查询操作

@Test

/**

*查询多条记录

*/

publicvoiddemo4(){

Connection conn= null;

Statement stmt= null;

ResultSet rs= null;

try{

//注册驱动

Class.forName("com.mysql.jdbc.Driver");

//获得连接

conn= DriverManager.getConnection("jdbc:mysql:///web_test3", "root", "abc");

//执行操作

//创建执行SQL语句的对象:

stmt= conn.createStatement();

//编写SQL:

String sql= "select * from user";

//执行SQL:

rs= stmt.executeQuery(sql);

//遍历结果集:

while(rs.next()){

System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password"));

}

}catch(Exception e){

e.printStackTrace();

}finally{

//资源释放:

if(rs!= null){

try{

rs.close();

} catch(SQLException e) {

e.printStackTrace();

}

rs= null;

}

if(stmt!= null){

try{

stmt.close();

} catch(SQLException e) {

e.printStackTrace();

}

stmt= null;

}

if(conn!= null){

try{

conn.close();

} catch(SQLException e) {

e.printStackTrace();

}

conn= null;

}

}

}




[if !supportLists]1.12[endif]12_JDBC的工具类的抽取(写)

[if !supportLists][endif]总结一下抽取的原则:把相同的操作抽到一个方法里,可以重复利用。


关于JDBC我们可以抽取:加载驱动、获取连接、释放资源这三部分的代码。


/**

* JDBC的工具类

* @authoritheima

*/

publicclassJDBCUtils {

privatestaticfinalString driverClassName;

privatestaticfinalString url;

privatestaticfinalString username;

privatestaticfinalString password;

static{

driverClassName="com.mysql.jdbc.Driver";

url="jdbc:mysql:///web_test3";

username="root";

password="abc";

}


/**

*注册驱动的方法

*/

publicstaticvoidloadDriver(){

try{

Class.forName(driverClassName);

} catch(ClassNotFoundException e) {

e.printStackTrace();

}

}

/**

*获得连接的方法

*/

publicstaticConnection getConnection(){

Connection conn= null;

try{

//将驱动一并注册:

loadDriver();

//获得连接

conn= DriverManager.getConnection(url,username, password);

}catch(Exception e){

e.printStackTrace();

}

returnconn;

}

/**

*释放资源的方法

*/

publicstaticvoidrelease(Statement stmt,Connection conn){

if(stmt!= null){

try{

stmt.close();

} catch(SQLException e) {

e.printStackTrace();

}

stmt= null;

}

if(conn!= null){

try{

conn.close();

} catch(SQLException e) {

e.printStackTace();

}

conn= null;

}

}

publicstaticvoidrelease(ResultSet rs,Statement stmt,Connection conn){

//资源释放:

if(rs!= null){

try{

rs.close();

} catch(SQLException e) {

e.printStackTrace();

}

rs= null;

}

if(stmt!= null){

try{

stmt.close();

} catch(SQLException e) {

e.printStackTrace();

}

stmt= null;

}

if(conn!= null){

try{

conn.close();

} catch(SQLException e) {

e.printStackTrace();

}

conn= null;

}

}

}

测试工具类

@Test

/**

*查询操作:使用工具类

*/

publicvoiddemo1(){

Connection conn= null;

Statement stmt= null;

ResultSet rs= null;

try{

//获得连接:

conn= JDBCUtils.getConnection();

// 创建执行SQL语句的对象:

stmt= conn.createStatement();

//编写SQL:

String sql= "select * from user";

//执行查询:

rs= stmt.executeQuery(sql);

//遍历结果集:

while(rs.next()){

System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password"));

}

}catch(Exception e){

e.printStackTrace();

}finally{

//释放资源:

JDBCUtils.release(rs, stmt, conn);

}

}


[if !supportLists]1.13[endif]13_JDBC的配置信息提取到配置文件

[if !supportLists][endif]如何定义配置文件以及加载配置文件中的信息?

定义配置文件:


获取配置文件中的信息:



[if !supportLists]1.14[endif]14_JDBC的SQL注入漏洞(SQL演示)

[if !supportLists][endif]什么是sql注入漏洞?

在我们的网站中肯定会有登录的操作,用户之所以能登录成功,肯定是通过用户名和对应的密码去数据库中能找到对应的一条数据,假设某个人不清楚密码,只通过输入用户名就能从数据库中找到一条对应的数据,那么这就称为sql注入漏洞。


简单说:

通过表单或界面输入一些SQL字符串,能到达服务器执行,达到非法操作的目的.

正常的基本登录流程代码:


sql注入代码演示:


输入用户名

[if !supportLists]n[endif]aaa’or ‘1=1密码随意

[if !supportLists]n[endif]aaa’-- 密码随意注意:--后面有空格



SQL环境演示:

SELECT * FROM USER WHERE username='aaa' AND PASSWORD='123'

SELECT * FROM USER WHERE username='aaa' OR '1=1' AND PASSWORD='wrwrw'

SELECT * FROM USER WHERE username='aaa'-- ' AND PASSWORD='wrwrw'


代码参见:/jdbc/src/com/itheima/jdbc/demo4/UserDao.java

[if !supportLists]1.15[endif]15_JDBC的SQL注入漏洞分析及解决

[if !supportLists][endif]sql注入漏洞的原因是什么?

[if !supportLists][endif]如何解决sql注入的漏洞?


[if !supportLists]1、[endif]原因:主要是用户输入了sql中规定的关键字,导致我们的sql语句的判断条件发生了变化。

使用Statement对象来执行一个sql语句是这样的:

resultSet=statement.executeQuery("select * from user where username='"+username+"' and password='"+password+"';");

我们把用户输入的内容放到上面的sql语句对应的变量处:

or前面的一部分判断成立就能查到结果。


[if !supportLists]2、[endif]解决sql注入的漏洞:使用PreparedStatement对象而不是Statement对象。

PreparedStatement有一个预编译的过程,这个过程会固定sql语句的格式,对于变量要求是用?来占位,那么传递过来的数据即使包含了sql关键字也不会当做关键字来识别。


publicclassUserDao {

publicbooleanlogin(String username,String password){

Connection conn= null;

PreparedStatement pstmt= null;

ResultSet rs= null;

//定义一个变量:

booleanflag= false;

try{

//获得连接:

conn= JDBCUtils.getConnection();

//编写SQL语句:

String sql = "select * from user where username = ? and password = ?";

//预编译SQL

pstmt= conn.prepareStatement(sql);

//设置参数:

pstmt.setString(1, username);

pstmt.setString(2, password);

//执行SQL语句:

rs= pstmt.executeQuery();//无需传入SQL

if(rs.next()){

//说明根据用户名和密码可以查询到这条记录

flag= true;

}

}catch(Exception e){

e.printStackTrace();

}finally{

JDBCUtils.release(rs, pstmt, conn);

}

returnflag;

}

代码参见:/jdbc/src/com/itheima/jdbc/demo4/UserDao.java


[if !supportLists]1.16[endif]16_JDBC的CRUD操作之PreparedStatement保存操作(写)

@Test

/**

*保存操作

*/

publicvoiddemo1(){

Connection conn= null;

PreparedStatement pstmt= null;


try{

//获得连接:

conn= JDBCUtils.getConnection();

//编写SQL语句:

String sql = "insert into user values (null,?,?,?,?)";

//预编译SQL:

pstmt= conn.prepareStatement(sql);

//设置参数:

pstmt.setString(1, "eee");

pstmt.setString(2, "abc");

pstmt.setString(3, "旺财");

pstmt.setInt(4, 32);

//执行SQL

intnum= pstmt.executeUpdate();//不传SQL

if(num> 0){

System.out.println("保存成功!");

}

}catch(Exception e){

e.printStackTrace();

}finally{

JDBCUtils.release(pstmt, conn);

}

}



[if !supportLists]1.17[endif]17_JDBC的CRUD操作之PreparedStatement修改操作

@Test

/**

*修改操作

*/

publicvoiddemo2(){

Connection conn= null;

PreparedStatement pstmt = null;

try{

//获得连接:

conn= JDBCUtils.getConnection();

//编写SQL语句:

String sql = "update user set username = ?,password =?,nickname=?,age = ? where id = ?";

//预编译SQL:

pstmt= conn.prepareStatement(sql);

//设置参数:

pstmt.setString(1, "abc");//设置第一个?的值

pstmt.setString(2, "1234");

pstmt.setString(3, "旺旺");

pstmt.setInt(4, 23);

pstmt.setInt(5, 4);

//执行SQL:

intnum= pstmt.executeUpdate();

if(num> 0){

System.out.println("修改成功!");

}

}catch(Exception e){

e.printStackTrace();

}finally{

JDBCUtils.release(pstmt, conn);

}

}


[if !supportLists]1.18[endif]18_JDBC的CRUD操作之PreparedStatement删除操作

@Test

/**

*删除操作

*/

publicvoiddemo3(){

Connection conn= null;

PreparedStatement pstmt= null;

try{

//获得连接:

conn= JDBCUtils.getConnection();

//编写SQL语句:

String sql = "delete from user where id = ?";

//预编译SQL

pstmt= conn.prepareStatement(sql);

//设置参数:

pstmt.setInt(1, 4);

//执行SQL:

intnum= pstmt.executeUpdate();

if(num> 0){

System.out.println("删除成功!");

}

}catch(Exception e){

e.printStackTrace();

}finally{

JDBCUtils.release(pstmt, conn);

}

}


[if !supportLists]1.19[endif]19_JDBC的CRUD操作之PreparedStatement查询操作

@Test

/**

*查询操作

*/

publicvoiddemo4(){

Connection conn= null;

PreparedStatement pstmt= null;

ResultSet rs= null;

try{

//获得连接:

conn= JDBCUtils.getConnction();

//编写SQL:

String sql = "select * from user";

//预编译SQL:

pstmt= conn.prepareStatement(sql);

//设置参数:

//执行SQL:

rs= pstmt.executeQuery();

//遍历结果集:

while(rs.next()){

System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password")+" "+rs.getString("nickname"));

}

}catch(Exception e){

e.printStackTrace();

}finally{

JDBCUtils.release(rs, pstmt, conn);

}

}



[if !supportLists]1.20[endif]20_JDBC的批处理操作

批处理:一批SQL一起执行


@Test

/**

*批处理基本操作

*/

publicvoiddemo1(){

Connection conn= null;

Statement stmt= null;

try{

//获得连接:

conn= JDBCUtils.getConnection();

//创建执行批处理对象:

stmt= conn.createStatement();

//编写一批SQL语句:

String sql1= "create database test1";

String sql2= "use test1";

String sql3= "create table user(id int primary key auto_increment,name varchar(20))";

String sql4= "insert into user values (null,'aaa')";

String sql5= "insert into user values (null,'bbb')";

String sql6= "insert into user values (null,'ccc')";

String sql7= "update user set name = 'mmm' where id = 2";

String sql8= "delete from user where id = 1";

//添加到批处理

stmt.addBatch(sql1);

stmt.addBatch(sql2);

stmt.addBatch(sql3);

stmt.addBatch(sql4);

stmt.addBatch(sql5);

stmt.addBatch(sql6);

stmt.addBatch(sql7);

stmt.addBatch(sql8);

//执行批处理:

stmt.executeBatch();

}catch(Exception e){

e.printStackTrace();

}finally{

JDBCUtils.release(stmt, conn);

}

}

批量插入(使用PreparedStatement)

@Test

/**

*批量插入记录:

*需要在url后面拼接一个参数即可,效率高

?rewriteBatchedStatements=true

*/

publicvoiddemo2(){

//记录开始时间:

longbegin= System.currentTimeMillis();

Connection conn= null;

PreparedStatement pstmt= null;

try{

//获得连接:

conn= JDBCUtils.getConnection();

//编写SQL语句:

String sql= "insert into user values (null,?)";

//预编译SQL:

pstmt= conn.prepareStatement(sql);

for(inti=1;i<=10000;i++){

pstmt.setString(1, "name"+i);

//添加到批处理

pstmt.addBatch();

//注意问题:

//执行批处理

if(i% 1000 == 0){

//执行批处理:

pstmt.executeBatch();

//清空批处理:

pstmt.clearBatch();

}

}

}catch(Exception e){

e.printStackTrace();

}finally{

JDBCUtils.release(pstmt, conn);

}

longend= System.currentTimeMillis();

System.out.println((end-begin));

}

1.21总结:

阐述什么是JDBC以及为什么要使用JDBC

独立完成使用JDBC核心API对数据库表记录的CRUD操作(重点)

完成JDBC工具类的抽取与改进(重点)

阐述什么是SQL注入漏洞并给出解决方法

独立完成使用JDBC的预编译对象进行CRUD操作(重点)

JDBC的批处理操作