给你推荐如何通俗易懂学习并掌握JDBC(完整版)

java基础知识——JDBC(重点)

前言:

​ 本人在学习jdbc知识之时,觉得学的懵懵懂懂,踩了很多坑,为了避免犯我同样的错误,我给大家分享一下如何快速学懂jdbc的技巧,要想通俗易懂的学习并掌握jdbc,我们需要先了解数据库驱动,掌握数据库的基本使用和对链表的一些基本理解

1.数据库驱动:

​ 数据库驱动程序:是一个动态链接库(DLL),用以将特定的开放式数据库连接的数据源和另一度个应用程序(客户端)相连接。但这样应用的话,每个应用都需要添加对应的驱动,才能连接到对应的数据库,需要用不同的数据库,就要不断的添加数据库驱动,导致很不方便.jdbc就能解决这个问题.

jdbc2.png

2.JDBC介绍

​ JDBC(Java DataBase Connectivity)是Java和数据库之间的一个桥梁,是一个规范而不是一个实现,能够执行SQL语句。它由一组用Java语言编写的类和接口组成。各种不同类型的数据库都有相应的实现,本文中的代码都是针对MySQL数据库实现的。

jdbc1.png

3.jdbc实现详细步骤

1.准备工作:

  • mysql-connector-java-5.0.8-bin.jar包(访问MySQL数据库需要用到第三方的类,这些第三方的类,都被压缩在一个.Jar的文件里),推荐去MAVEN下载:https://mvnrepository.com
  • 通过可视化工具打开数据库,创建一个新的数据库并添加数据:操作命令如下:
-- 创建一个新的数据库
CREATE DATABASE jdbcstudy CHARACTER SET utf8 COLLATE utf8_general_ci;
-- 切换到当前新建的数据库
USE jdbcstudy;
-- 在当前数据库中建一张表
CREATE TABLE users(
	`id` INT PRIMARY KEY,
	`name` VARCHAR(40),
	`password` VARCHAR(40),
	`email` VARCHAR(60),
	`birthday` DATE
)
-- 在新建表格中添加数据
INSERT into users(`id`,`name`,`password`,`email`,`birthday`) VALUES(1,'zhangsan','123456','zs@sina.com','1998-08-08')
,(2,'lisi','123456','lisi@sina.com','1999-09-09'),(3,'wanger','123456','wanger@sina.com','2000-01-01');

2.创建一个普通java项目,并建立一个lib文件夹(和src目录同级),导入数据库驱动,将mysql-connector-java-5.0.8-bin.jar放到lib文件夹中,mysql-connector-java-5.0.8-bin.ja右击,点击Add as Libary,将其添加到项目库中,才可以使用

jdbc4.png

3.项目一切准备就绪,如下图:

jdbc3.png

4.书写第一个jdbc代码

package com.mage;

import java.sql.*;

/**
 * @param
 * @author qzp
 * @create 2020-04-10 15:22
 */
//我的第一个jdbc程序
public class Myfristjdbc {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1.加载驱动(固定写法)
        Class.forName("com.mysql.jdbc.Driver");
        //2.用户信息和url
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String username = "root";//根据自己的数据库用户名来填写
        String password = "root";//根据自己的数据库密码来填写,没有密码就用""
        //3.与数据库进行连接,返回数据库对象Connection
        Connection conn = DriverManager.getConnection(url, username, password);
        //4.创建执行sql语句的对象Statement
        Statement statement = conn.createStatement();
        //5.书写sql语句
        String sql = "select * from users";
        //6.执行sql语句,可能存在返回结果或影响行数
        ResultSet resultSet = statement.executeQuery(sql);
        //7.打印结果
        while (resultSet.next()){
            System.out.println("id:"+resultSet.getObject("id"));
            System.out.println("name:"+resultSet.getObject("name"));
            System.out.println("password:"+resultSet.getObject("password"));
            System.out.println("email:"+resultSet.getObject("email"));
            System.out.println("birthday:"+resultSet.getObject("birthday"));
            System.out.println("------------------------------------------------");
        }
        //8.释放连接
        resultSet.close();
        statement.close();
        conn.close();
    }
}

一看上述代码,感觉不多,但发现有很多点想不通,也不好记,死记硬背,不是上上计策,如果你能把上述代码和可视化工具(例如:navicate)连接数据库开始的界面对应起来,联想到可视化工具如何执行sql语句并展示结果,你就能很快理解并掌握上述代码的书写

jdbc6.png

4.分析上述代码

DriverManager

//方式一:注册驱动并加载驱动(不推荐使用)
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");

//方式二:加载驱动(固定写法)
Class.forName("com.mysql.jdbc.Driver");

i.这两者方式的区别?分析:打开com.mysql.jdbc.Driver的源码中,有一个static静态代码块,这个类加载到JVM中,加载的时候,就会执行其中的静态初始化块,完成驱动的初始化的相关工作,对于DriverManager.registerDriver(new Driver()); 多new一个Driver浪费;而Class.forName(“com.mysql.jdbc.Driver”); 就可以搞定一切.对于反射使用,

ii.为什么不获取反射的对象,因为我们不需要使用反射的对象

URL

String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";

分析如下:

//mysql默认的端口:3306
//jdbc:mysql://主机名:端口/数据库名称?参数1&参数2
//oracle默认端口:1521
//jdbc:oracle:thin:@localhost:1521:sid

useUnicode=true&characterEncoding=UTF-8&useSSL=true

  • 添加的作用是:指定字符的编码、解码格式。

分析如下:

​ 例如:mysql数据库用的是gbk编码,而项目数据库用的是utf-8编码。这时候如果添加了useUnicode=true&characterEncoding=UTF-8 ,那么作用有如下两个方面:

  • 存数据时:数据库在存放项目数据的时候会先用UTF-8格式将数据解码成字节码,然后再将解码后的字节码重新使用GBK编码存放到数据库中。

  • 取数据时:在从数据库中取数据的时候,数据库会先将数据库中的数据按GBK格式解码成字节码,然后再将解码后的字节码重新按UTF-8格式编码数据,最后再将数据返回给客户端。

  • useSSL=true建立安全连接

Connection

//3.与数据库进行连接,返回数据库对象Connection
Connection conn = DriverManager.getConnection(url, username, password);

分析如下:

//conn代表数据库,可以对数据库数据进行管理
conn.rollback();//事务的回滚
conn.commit();//事务的提交
conn.setAutoCommit(true);//设置数据库自动提交

Statement

//4.创建执行sql语句的对象Statement
Statement statement = conn.createStatement();

分析如下:

//执行sql语句的对象Statement
String sql = "select * from users";
statement.execute(sql);//执行任何sql
statement.executeQuery(sql);//执行查询操作返回ResultSet
statement.executeUpdate(sql);//执行更新、插入、删除,返回一个受影响行

注意:PreparedStatement和Statement都是执行sql对象,PreparedStatement后面会说明

ResultSet 查询结果集,封装了所有的查询结果

//6.执行sql语句,可能存在返回结果或影响行数
ResultSet resultSet = statement.executeQuery(sql);

分析如下:

//获取指定的数据类型
resultSet.getObject();//--在不知道列类型的情况下使用
resultSet.getInt();//--对应列属性数值int
resultSet.getString();//--对应列属性字符串varchar
resultSet.getDate();//--对应列属性时间日期
resultSet.getFloat();//--对应列属性float

//遍历,指针
resultSet.beforeFirst();//移动到最前面
resultSet.afterLast();//移动到最后
resultSet.next();//移动到下一个数据
resultSet.previous();//移动到前一行
resultSet.absolute(row);//移动到指定行

释放资源:内存开销大,一定要关闭

//8.释放连接
resultSet.close();
statement.close();
conn.close();

5.Statement对象

​ jdbc中的Statement对象用于向数据库发送SQL语句,完成对数据库的增删查改

  • Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate方法执行完毕后,将会返回一个整数(即增删改语句导致数据库中的数据发生变化的记录总数)
  • Statement对象的executeQuery方法,用于向数据库发送查sql语句,executeQuery方法执行完毕后,返回查询结果集ResultSet对象

6.CURD操作

create

使用executeUpdate(String sql)方法完成对数据的添加操作,实例如下:

Statement statement = conn.createStatement();
String sql = "INSERT into users(`id`,`name`,`password`,`email`,`birthday`) VALUES(1,'zhangsan','123456','zs@sina.com','1998-08-08')";
int row = statement.executeUpdate(sql);
if(row > 0){
     System.out.println("插入成功!");
}

update

使用executeUpdate(String sql)方法完成对数据的删除操作,实例如下:

Statement statement = conn.createStatement();
String sql = "update users set name="qzp" where id = 1;
int row = statement.executeUpdate(sql);
if(row > 0){
     System.out.println("更新成功!");
}

delete

使用executeUpdate(String sql)方法完成对数据的删除操作,实例如下:

Statement statement = conn.createStatement();
String sql = "delete from users where id = 1";
int row = statement.executeUpdate(sql);
if(row > 0){
     System.out.println("删除成功!");
}

read

使用executeUpdate(String sql)方法完成对数据的删除操作,实例如下:

Statement statement = conn.createStatement();
String sql = "select * from users";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
    System.out.println("id:"+resultSet.getObject("id"));
    System.out.println("name:"+resultSet.getObject("name"));
    System.out.println("password:"+resultSet.getObject("password"));
    System.out.println("email:"+resultSet.getObject("email"));
    System.out.println("birthday:"+resultSet.getObject("birthday"));
}

7.代码封装

在src目录下创建,db.properties配置文件,目的:方便下次调试使用不同的数据库

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=UTF-8&useSSL=true
username=root
password=root

封装增删查改需要重复写的代码,将其封场成为一个工具类,方便下次调用

因为在进行数据库的增删改查的时候都需要与数据库建立连接,所以可以在项目中将建立连接写成一个工具方法,用的时候直接调用即可:

package com.mage.util;

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * @param
 * @author qzp
 * @create 2020-04-10 20:57
 */
@SuppressWarnings("all")
public class Jdbcutils {
    private static String driver = null;
    private static String url = null;
    private static String username = null;
    private static String password = null;
    static {
        try {
            InputStream in = jdbcutils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(in);
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            //1.加载驱动且加一次
            Class.forName(driver);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    //2.获取连接
    public static Connection getconnection(){
        try {
            return DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }

    //释放连接资源,先开后关
    public static void close(Connection connection, Statement statement, ResultSet resultSet){
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(connection !=null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

8.测试工具类

引用工具类实现插入数据:

package com.mage.jdbc;
import com.mage.util.Jdbcutils;
import javax.lang.model.element.VariableElement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
/**
 * @param
 * @author qzp
 * @create 2020-04-10 21:30
 */
public class Myjdbcutilstest {
    public static void main(String[] args) {
        Connection conn = null;
        Statement statement = null;
        try {
            conn = Jdbcutils.getconnection();
            statement = conn.createStatement();
            String sql = "INSERT into users(`id`,`name`,`password`,`email`,`birthday`) VALUES(4,'wjw','123456','wjw@sina.com','1998-06-12')";
            int i = statement.executeUpdate(sql);
            if(i>0){
                System.out.println("插入成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            Jdbcutils.close(conn, statement, null);
        }
    }
}

9.SQL注入问题

​ SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息

模拟登录,呈现SQL注入问题

package com.mage.jdbc;
import com.mage.util.Jdbcutils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * @param
 * @author qzp
 * @create 2020-04-10 21:58
 */
//模拟登录,呈现SQL注入问题
@SuppressWarnings("all")
public class SqlTest {
    public static void main(String[] args) {
        //正常登录
        login("qzp", "123456");
        //SQL注入
        login("' or '1=1 ", "123456");
        login("' or '1=1 ", " ' or '1=1");
    }
    public static void login(String name,String password){
        Connection conn = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            conn = Jdbcutils.getconnection();
            statement = conn.createStatement();
            //SELECT * from users WHERE `name` = 'qzp' AND `password` = '123456';--正常查询
            //SELECT * from users WHERE `name` = '' or '1=1' AND `password` = '123456';--SQL注入
            //SELECT * from users WHERE `name` = '' or '1=1' AND `password` = '' or '1=1';--SQL注入
            String sql = "SELECT * from users WHERE `name` = '"+name+"' AND `password` = '"+password+"'";
            resultSet = statement.executeQuery(sql);
            //7.打印结果
            while (resultSet.next()){
                System.out.println("id:"+resultSet.getInt("id"));
                System.out.println("name:"+resultSet.getString("name"));
                System.out.println("password:"+resultSet.getObject("password"));
                System.out.println("email:"+resultSet.getObject("email"));
                System.out.println("birthday:"+resultSet.getObject("birthday"));
                System.out.println("------------------------------------------------");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            Jdbcutils.close(conn, statement, resultSet);
        }
    }
}

10.PreparedStatement对象

代码实现CRUD:

create

package com.mage.jdbc;
import com.mage.util.Jdbcutils;
import java.sql.*;
import java.util.Date;

/**
 * @param
 * @author qzp
 * @create 2020-04-10 22:27
 */
public class PreparedStatementTest {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement preparedStatement = null;
        try {
            conn = Jdbcutils.getconnection();
            //String sql = "INSERT into users(`id`,`name`,`password`,`email`,`birthday`) VALUES(4,'wjw','123456','wjw@sina.com','1998-06-12')";
            //使用? 占位符代替参数
            String sql = "INSERT into users(`id`,`name`,`password`,`email`,`birthday`) VALUES(?,?,?,?,?)";
            //预编译sql,先书写sql,但不执行
            preparedStatement = conn.prepareStatement(sql);
            //手动给每个参数赋值
            preparedStatement.setInt(1,4);
            preparedStatement.setString(2, "wjw");
            preparedStatement.setInt(3, 123456);
            preparedStatement.setString(4, "wjw@sina.com");
            //注意点: java.sql.Date:数据库
            //         java.util.Date:java
            preparedStatement.setDate(5, new java.sql.Date(new Date().getTime()));
            //执行sql
            int i = preparedStatement.executeUpdate();
            if(i>0){
                System.out.println("插入成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            Jdbcutils.close(conn, preparedStatement, null);
        }
    }
}

update

package com.mage.jdbc;
import com.mage.util.Jdbcutils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * @param
 * @author qzp
 * @create 2020-04-10 22:27
 */
public class PreparedStatementTest3 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement preparedStatement = null;
        try {
            conn = Jdbcutils.getconnection();
            //使用? 占位符代替参数
            String sql = "update users set name=? where id = ?";
            //预编译sql,先书写sql,但不执行
            preparedStatement = conn.prepareStatement(sql);
            //手动给每个参数赋值
            preparedStatement.setString(1,"王佳雯");
            preparedStatement.setInt(2,4);
            //执行sql
            int i = preparedStatement.executeUpdate();
            if(i>0){
                System.out.println("更新成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            Jdbcutils.close(conn, preparedStatement, null);
        }
    }
}

delete

package com.mage.jdbc;
import com.mage.util.Jdbcutils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

/**
 * @param
 * @author qzp
 * @create 2020-04-10 22:27
 */
public class PreparedStatementTest2 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement preparedStatement = null;
        try {
            conn = Jdbcutils.getconnection();
            //使用? 占位符代替参数
            String sql = "delete from users where  id = ?";
            //预编译sql,先书写sql,但不执行
            preparedStatement = conn.prepareStatement(sql);
            //手动给每个参数赋值
            preparedStatement.setInt(1,4);
            //执行sql
            int i = preparedStatement.executeUpdate();
            if(i>0){
                System.out.println("删除成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            Jdbcutils.close(conn, preparedStatement, null);
        }
    }
}

read

package com.mage.jdbc;

import com.mage.util.Jdbcutils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

/**
 * @param
 * @author qzp
 * @create 2020-04-10 22:27
 */
public class PreparedStatementTest4 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            conn = Jdbcutils.getconnection();
            //使用? 占位符代替参数
            String sql = "select * from users where id = ?";
            //预编译sql,先书写sql,但不执行
            preparedStatement = conn.prepareStatement(sql);
            //手动给每个参数赋值
            preparedStatement.setInt(1,4);
            //执行sql
            resultSet = preparedStatement.executeQuery();
            //获取查询出的结果
            while (resultSet.next()){
                System.out.println("id:"+resultSet.getInt("id"));
                System.out.println("name:"+resultSet.getString("name"));
                System.out.println("password:"+resultSet.getObject("password"));
                System.out.println("email:"+resultSet.getObject("email"));
                System.out.println("birthday:"+resultSet.getObject("birthday"));
                System.out.println("------------------------------------------------");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            Jdbcutils.close(conn, preparedStatement, resultSet);
        }
    }
}

注意:

  • PreparedStatement是继承Statement,所以封装好的代码可以不用改动!!!!!!
  • PreparedStatement可以防止SQL注入,效率比Statement高

本片文章就分享到这里,如果文章中有小问题或者你有什么疑问,欢迎大家在评论区留言提出类,我会及时给大家提供解决方法,谢谢

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

QZP51ZX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值