1. JDBC 概念
JDBC:
Java Data Base Connectivity - Java数据库连接技术
这是一种用于执行SQL语句的Java API, 可以为多种关系数据库提供统一的访问, 是SUN公司提供的一套连接并操作数据库的技术.
使用要求:
JDBC需要连接驱动:
我们操作数据库是在控制台使用SQL语句来操作
而JDBC是用Java语言向数据库发送SQL语句,帮助我们完成执行数据库的操作.
注意:
JDBC连接不同的数据库, 需要导入不同的数据库驱动包!
2. JDBC工作原理
3. JDBC初步应用示例
3.1 创建表并新增数据
create database singerdb;
use singerdb;
create table singer(
id int(4) primary key auto_increment,
name VARCHAR(20),
age int(3),
birthday date,
works VARCHAR(50) not null,
sex char(1),
idcard VARCHAR(20) not null UNIQUE
);
use singerdb;
INSERT into singer values (null,'汪峰',50,'2010-10-10','飞得更高','男','34535434535675467567');
INSERT into singer values (null,'杰伦',50,'2010-10-20','双杰伦','男','345354345356754673');
INSERT into singer values (null,'哈林',56,'2010-11-10','情非得已','男','3453543453567543');
INSERT into singer values (null,'娜姐',60,'2010-10-13','征服','女','345354345356754676');
3.2 将mysql驱动包导入当前工程当中
3.3 完成程序编译
public class Demo1 {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/singerdb?useUnicode=true&characterEncoding=utf-8", "root", "123");
st = conn.createStatement();
String sql = "SELECT * FROM singer";
rs = st.executeQuery(sql);
System.out.println("编号\t姓名\t年龄\t生日\t作品\t性别\t身份证号");
while (rs.next()) {
int id = rs.getInt("ID");
String name = rs.getString("NAME");
int age = rs.getInt("AGE");
String birthday = rs.getString("BIRTHDAY");
String works = rs.getString("WORKS");
String sex = rs.getString("SEX");
String idcard = rs.getString("IDCARD");
System.out.println(id+"\t"+name+"\t"+age+"\t"+birthday+"\t"+works+"\t"+sex+"\t"+idcard);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if(rs!=null){
rs.close();
}
if(st!=null){
st.close();
}
if(conn!=null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
4. JDBC API详解
4.1 DriverManager类
DriverManager是驱动管理类, JDBC程序中DriverManager用于加载驱动并创建与数据库的连接.
获取DriverManager方式:
Class.forName("com.mysql.jdbc.Driver");
此方法会将com.mysql.jdbc.Driver中的静态代码块执行, 实现驱动的注册, 将指定的类加载到内存中.
DriverManager.getConnection(url, user, password);
url: 连接到某一个具体的数据库, 通过URL地址告诉JDBC程序需要连接哪个数据库
URL写法如下:
jdbc:mysql://localhost:3306/test?参数名:参数值
协议:子协议:// 主机:端口/数据库
user:
数据库用户名
password:
数据库用户名对应的密码
此方法会返回一个Connection类对象, 并将建立到给定数据库URL的连接.
常用属性:
useUnicode=true&characterEncoding=UTF-8
作用:
解决入库乱码问题
url最终格式:
jdbc:mysql://主机IP:端口/库名?useUnicode=true&characterEncoding=UTF-8
4.2 Connection类
作用:
用于代表数据库的链接, Collection是数据库编程中最重要的一个对象, 客户端与数据库所有交互都是通过connection对象完成的
常用API:
createStatement();
创建向数据库发送sql的statement对象
prepareStatement(sql);
创建向数据库发送预编译sql的PrepareSatement对象
prepareCall(sql);
创建执行存储过程的callableStatement对象
setAutoCommit(boolean autoCommit);
设置事务是否自动提交
commit();
在链接上提交事务
rollback();
在此链接上回滚事务
4.3 Statement类
作用:
Statement对象用于向数据库发送SQL语句
常用API:
executeQuery(String sql);
用于向数据发送查询语句
executeUpdate(String sql);
用于向数据库发送insert、update或delete语句
execute(String sql);
用于向数据库发送任意sql语句
addBatch(String sql);
把多条sql语句放到一个队列处理中
executeBatch();
向数据库发送一个队列的sql语句执行
4.4 ResultSet类
作用:
ResultSet用于代表Sql语句的执行结果
Resultset封装执行结果时,采用的类似于表格的方式, ResultSet 对象维护了一个指向表格数据行的游标
初始的时候,游标在第一行之前,调用ResultSet.next() 方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据
常用API:
getObject(int index);
getObject(string columnName);
getString(int index);
getString(String columnName);
next();
移动到下一行
Previous();
移动到前一行
absolute(int row);
移动到指定行
beforeFirst();
移动resultSet的最前面。
afterLast();
移动到resultSet的最后面。
5. Statement面对SQL注入攻击问题 - PreparedStatement
5.1 完成一个登录操作
CREATE database userdb;
USE userdb;
CREATE TABLE users(
id int PRIMARY key auto_increment,
username VARCHAR(20) not null,
`password` VARCHAR(20) not null,
age int not null,
email VARCHAR(20) not null,
phone VARCHAR(20) not null UNIQUE
);
insert into users values(null,'悟空','admin',50,'wukong@163.com','13367899901');
insert into users values(null,'八戒','12346',52,'bajie@163.com','13367896601');
package com.bruce.demo2;
import java.sql.*;
import java.util.Scanner;
public class Demo1 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
System.out.print("请输入您的账号:");
String name=input.next();
System.out.print("请输入您的密码:");
String pass=input.next();
Connection conn=null;
Statement st=null;
ResultSet result=null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn= DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/userdb?useUnicode=true&characterEncoding=UTF-8","root","123456");
st=conn.createStatement();
String sql="select * from users where username='"+name+"' and password='"+pass+"'";
System.out.println("登录的SQL语句是:"+sql);
result=st.executeQuery(sql);
if(result.next()){
System.out.println("登录成功,欢迎您:"+name);
}else{
System.out.println("登录失败,账号或密码错误!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(result!=null){
result.close();
}
if(st!=null){
st.close();
}
if(conn!=null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
}
}
}
}
请输入您的账号:ffff
请输入您的密码:6'or'8'='8
登录的SQL语句是:select * from users where username='ffff' and password='6'or'8'='8'
登录成功,欢迎您:ffff
5.2 总结
上述登录程序,存在一些安全隐患,容易遭到黑客的恶意攻击!这种攻击叫做SQL注入攻击!
为什么会遭到攻击?
登录的SQL语句是人为字符串拼接的!账号和密码是拼接到SQL语句中的,容易导致SQL拼接恒成立!而且拼接SQL还容易出错!
Statement和PreparedStatement的对比:
1.PreparedStatement是Statement子接口
2.PreparedStatement的SQL是预编译,可以执行多次,执行效率高于Statement
3.PreparedStatement中SQL中使用问号来占位,不是直接把变量拼接到SQL中,所以没有SQL注入问题。安全性比Statement要好!
5.3 使用PreparedStatement完成登录代码
package com.bruce.demo2;
import java.sql.*;
import java.util.Scanner;
public class Demo2 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("请输入您的账号:");
String name = input.next();
System.out.print("请输入您的密码:");
String pass = input.next();
Connection conn = null;
PreparedStatement st = null;
ResultSet result = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/userdb?useUnicode=true&characterEncoding=UTF-8", "root", "123456");
String sql = "select * from users where username=? and password=?";
st = conn.prepareStatement(sql);
st.setObject(1, name);
st.setObject(2, pass);
result = st.executeQuery();
if (result.next()) {
System.out.println("登录成功,欢迎您:" + name);
} else {
System.out.println("登录失败,账号或密码错误!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (result != null) {
result.close();
}
if (st != null) {
st.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
}
}
}
}