一、JDBC基础
JDBC规范定义接口,具体的实现由各大数据库厂商来实现。
概述:JDBC是Java 访问数据库的标准规范,真正怎么操作数据库还需要具体的实现类,也就是数据库驱动。每个数据库厂商根据自家数据库的通信格式编写好自己数据库的驱动。所以我们只需要会调用JDBC接口中的方法即可,数据库驱动由数据库厂商提供。
1、jar包
需要使用的jar包根据数据库版本的不同,下载对应的jar包。我使用的是mysql-connectorjava-5.1.30.jar
2、导jar包步骤
创建一个普通的java项目,然后在根目录下创建一个lib包,导入我们的数据库jar包,然后把lib设置为library。
3、JDBC核心API
接口或类 | 功能 |
DriverManager类 | ①管理和注册数据库驱动②得到数据库连接对象 |
Connection接口 | 一个连接对象,可用于创建Statement和PrearedStatement对象 |
Statement接口 | 一个SQL对象,用于将SQL语句发送给数据库服务器 |
PreparedStatement接口 | 一个SQL语句对象,是Statement的子接口 |
ResultSet接口 | 用于封装数据库查询的结果集,返回给客户端java程序 |
4、注册驱动(JDBC4.0之后,就可以不用这个步骤)
格式:
Class.forName(数据库驱动实现类)
MySQL数据库驱动实现类 ---> "com.mysql.jdbc.Driver"
代码:
Class.forName("com.mysql.jdbc.Driver");//会有ClassNotFoundException异常,直接抛出即可
5、DriverManager类
作用:管理和注册驱动;创建数据库的连接
5.1、方法
静态方法 | 功能 |
Connection getConnection (String url, String user, String password) | 通过连接字符串,用户名,密码来得到数据库的连接对象 |
Connection getConnection (String url, Properties info) | 通过连接字符串,属性对象来得到连接对象 |
5.2、JDBC连接数据库的四个参数
参数名 | 说明 |
用户名 | 数据库登录用户名 |
密码 | 数据库登录密码 |
URL | 不同的数据库 URL 是不同的,mysql 的写法 jdbc:mysql://localhost:3306/数据 库名[?参数名=参数值] |
驱动类的字符串名 | com.mysql.jdbc.Driver |
[?参数名=参数值]:用于设置编码,防止乱码
例如:
?useUnicode=true&characterEncoding=utf8
String url="jdbc:mysql://localhost:3306/apsfc?useUnicode=true&characterEncoding=utf8";
二、连接数据库
1、获取连接对象
1.1 使用用户名、密码、URL 得到连接对象
public class JdbcConn {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
//1.加载驱动(jdbc4.0之后就可以省略)
Class.forName("com.mysql.jdbc.Driver");
System.out.println("加载驱动成功");
//2.连接数据库
/*
需要使用DriverManager类
静态方法:获取数据库连接对象
1.getConnection(url,root,password)
*/
//设置编码
String url="jdbc:mysql://localhost:3306/apsfc?useUnicode=true&characterEncoding=utf8";
Connection conn = DriverManager.getConnection(url,"root","1234");
System.out.println("数据库连接成功");
}
}
1.2 使用属性文件和 url 得到连接对象
public class JdbcConn2 {
//静态代码块加载驱动
static{
try {
Class.forName("com.mysql.jdbc.Driver");
System.out.println("驱动加载完成");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args){
//1.连接数据库
/*
static Connetion getConnection(String url,Properties info)
*/
//编写连接地址
String url="jdbc:mysql://localhost:3306/apsfc?useUnicode=true&characterEncoding=utf8";
//创建Properties对象
Properties pro = new Properties();
//设置用户名
pro.setProperty("user","root");
//设置密码
pro.setProperty("password","1234");
Connection conn = null;
try {
//连接数据库,获取连接对象
conn = DriverManager.getConnection(url, pro);
System.out.println("连接成功");
} catch (SQLException e) {
e.printStackTrace();
}finally {
if (conn!=null){
//关闭连接
try {
conn.close();
System.out.println("数据库连接已关闭");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
2、Connection接口
Connection接口:具体的实现类由数据库的厂商实现,代表一个连接对象。
方法 | 描述 |
Statement createStatement() | 创建一条 SQL 语句对象 |
3、Statement接口
代表一条语句对象,用于发送 SQL 语句给服务器,用于执行静态 SQL 语句并返回它所生成结果的对象。
①Statement 中的方法
方法 | 描述 |
int executeUpdate(String sql) | 用于发送 DML 语句,增删改的操作,insert、update、delete 参数:SQL 语句 返回值:返回对数据库影响的行数 |
ResultSet executeQuery(String sql) | 用于发送 DQL 语句,执行查询的操作。select 参数:SQL 语句 返回值:查询的结果集 |
②释放资源
由于连接数据库,进行操作之后,无论是否发生异常,我们都要执行释放资源这个步骤,那么,这个释放资源的操作,就可以放在finally代码块中。
4、JDBC具体操作
4.1、步骤
①注册和加载驱动(可以省略)
②获取连接
③Connection 获取 Statement 对象
④使用 Statement 对象执行 SQL 语句
⑤返回结果集 // DQL使用
⑥释放资源
4.2、DML操作
①创建一张表,名为apsfc——该步骤一般在数据库内编写
②通过java代码向student表中插入、删除、修改记录
public class DataBaseTest {
//加载驱动
static{
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
//2.连接数据库
String url="jdbc:mysql://localhost:3306/apsfc?useUnicode=true&characterEncoding=utf8";
Connection conn = null;
Statement sta = null;
try{
//(1)获取连接对象
conn = DriverManager.getConnection(url,"root","1234");
//(2)创建SQL语句对象
sta = conn.createStatement();
//(3)编写SQL语句
// String sql = "insert into admin values(null,'张三','12345','1')";//插入
// String sql = "delete from admin where id=5 or id=4";//删除
String sql = "update admin set name='GOD' where name='sa'";//更新/改
//(4)发送SQL语句,返回影响行数,此方法用于增删改
int i = sta.executeUpdate(sql);
System.out.println("成功插入" + i + "条数据");
}catch(Exception e ){
e.printStackTrace();
}finally {
//关闭资源
try {
if (conn != null){
conn.close();
}
if (sta != null){
sta.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
4.3、DQL操作
①ResultSet接口:封装数据库查询的结果集,对结果集进行遍历,取出每一条记录。
package com.jdbc.dql;
import java.sql.*;
//DQL语句:查询语句
public class DatabaseTest {
static{
//1.加载驱动
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
//2.连接数据库
String url="jdbc:mysql://localhost:3306/apsfc?useUnicode=true&characterEncoding=utf8";
Connection conn = null;
Statement sta = null;
ResultSet set = null;
try{
//(1)获取连接对象
conn = DriverManager.getConnection(url,"root","1234");
//(2)创建一个SQL语句对象
sta = conn.createStatement();
//(3)编写SQL语句
String sql="select * from admin";
//(4)发送SQL语句,返回值为ResultSet,存储的是查询到的结果集
set = sta.executeQuery(sql);
//(5)获取查询到的结果:判断后面还有没有
while (set.next()){
//获取id
int id = set.getInt("id");
//获取name
String name = set.getString("name");
//获取pwd
String pwd = set.getString("pwd");
//获取authority
String authority = set.getString("authority");
System.out.println(id+"-"+name+"-"+pwd+"-"+authority);
}
}catch (Exception e){
e.printStackTrace();
}finally {
try{
//关闭资源
if (conn!=null) {
conn.close();
}
if (sta!=null) {
sta.close();
}
if (set!=null) {
set.close();
}
}catch (Exception e){
}
}
}
}
练习题:实现用户登录
package com.hqyj.cl.dao;
import java.sql.*;
import java.util.Scanner;
public class DemoLogin {
//从控制台上输入的用户名和密码
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名:");
String name = sc.nextLine();
System.out.println("请输入密码:");
String password = sc.nextLine();
login(name, password);}
public static void login(String name, String password){
//创建连接对象
Connection con = null;
//创建Statement对象
Statement st = null;
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接对象
con =
DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql_info?
characterEncoding=utf8", "root", "112112");
//通过连接对象得到语句对象
st = con.createStatement();
//创建SQL语句
String sql = "select * from user where name='" + name + "' and
password='" + password + "'";
ResultSet rs = st.executeQuery(sql);
if (rs.next()) {
System.out.println("登录成功,欢迎您:" + name);
} else {
System.out.println("登录失败");
}
System.out.println("操作成功!");
rs.close();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
if (st != null) {
try {
st.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (con != null) {
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
问题:如果这样输入密码,也能登录成功。
SQL语句变成了:select * from user where name='张三' and password='123121' or '1'='1'。也就是说,即使我没有密码,我也能够改变SQL语句执行登录操作,这就是Statement引发的SQL注入问题。要想解决这个问题,就用其子类PreparedStatement替换掉Statement即可。
三、PreparedStatement
1、概述
PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法,它是一个预编译的 SQL 语 句。
2、PreparedStatement 与Statement 的比较
①Statement 在进行输入插入的时候,都会发送一条SQL语句给数据库,数据库先编译SQL语句,
然后执行,返回结果,如果有一万条插入的SQL语句,那么数据库就需要先编译一万次,这样就会导致
效率低下;PreparedStatement在进行数据插入的时候,会先发送SQL语句预编译,
PreparedStatement就会引用预编译的结果,如果多次插入的内容相同的话,就只需要预编译一次,只
是每一次执行SQL语句的时候参数不一样。这样就提高了效率。
②PreparedStatement可以有效的防止 SQL 注入的问题,安全性更高。
3、PreparedStatement使用步骤
①编写 SQL 语句,未知内容使用?占位:"SELECT * FROM user WHERE name=? AND
password=?";
②获得 PreparedStatement 对象;
③设置实际参数:setXxx(占位符的位置, 真实的值);
④执行参数化 SQL 语句;
⑤关闭资源。
public class DatabaseLogin {
//登录
public static boolean login(String name,String password) throws Exception{
//1.连接数据库
String url="jdbc:mysql://localhost:3306/apsfc?useUnicode=true&characterEncoding=utf8";
//(1)获取连接对象
Connection conn = DriverManager.getConnection(url,"root","1234");
//(2)编写SQL语句,使用?占位符来表示传的值
String sql = "select * from admin where name=? and pwd=?";
//(3)创建PrepareStatement对象
PreparedStatement pre = conn.prepareStatement(sql);
//(4)设置SQL语句中占位符?的值
pre.setString(1,name);//1表示给第一个占位符?设置值
pre.setString(2,password);//2表示给第一个占位符?设置值
//(5)发送sql语句
ResultSet set = pre.executeQuery();
//(6)关闭资源
conn.close();
pre.close();
//(7)判断是否查询到结果
if (set.next()){
set.close();
return true;
}else {
set.close();
return false;
}
}
public static void main(String[] args) throws Exception {
System.out.println(register());
}
}
4、PreparedStatement 的常用方法
PreparedStatement 中设置参数的方法 | 描述 |
void setDouble(int parameterIndex, double x) | 将指定参数设置为给定 Java double 值 |
void setFloat(int parameterIndex, float x) | 将指定参数设置为给定 Java REAL 值 |
void setInt(int parameterIndex, int x) | 将指定参数设置为给定 Java int 值 |
void setLong(int parameterIndex, long x) | 将指定参数设置为给定 Java long 值 |
void setObject(int parameterIndex, Object x) | 使用给定对象设置指定参数的值 |
void setString(int parameterIndex, String x) | 将指定参数设置为给定 Java String 值 |