JavaWeb(篇第二周)之JDBC

本文详细介绍了Java数据库连接(JDBC)的基本概念、环境搭建、核心API及开发步骤,包括使用PreparedStatement避免SQL注入,以及通过综合案例展示账户系统功能实现。

JDBC

一、引言

1.1 如何操作数据

使用客户端工具访问数据库,需要手工建立链接,输入用户名和密码登陆,编写SQL语句,点击执行,查看操作结果(结果集或受影响行数)。

1.2实际开发中,会采用客户端操作数据库吗?

在实际开发过程中,当用户的数据发生改变时,不会通过客户端操作执行SQL语句,因为操作量过大,无法保证效率和正确性。

二、JDBC (JAVA DATABASE CONNECTIVITY)

2.1 什么是JDBC?

JDBC(Java DataBase Connectivity) JAVA 连接数据库,可以使用Java语言连接数据库完成CRUD操作

2.2 JDBC核心思想

JAVA 中定义了访问数据库的而接口,可以为多种关系型数据库提供了统一的访问方式

由数据库厂商提供数据库驱动实现类(Driver驱动)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sz7KqPgm-1585619491326)(C:\Users\fanhu\AppData\Roaming\Typora\typora-user-images\1585381106311.png)]

2.2.1 MySQL 数据库驱动
  • mysql-connector-java-5.1.x 适用于5.x版本
  • mysql-connector-java-8.0.x 适用于8.x 版本
2.2.2 JDBC API

JDBC 是由多个接口和类进行功能实现

类型全限定名简介
classjava.sql.DriverManage管理多个数据库驱动类,提供了获取数据库连接的方法
interfacejava.sql.Connection代表一个数据库连接(当Connection不是NULL时,标识已连接一个数据)
interfacejava.sql.Statement发送SQL语句到数据库的工具
interfacejava.sql.ResultSet保存SQL查询语句的结果数据(结果集)
classjava.sql.SQLException处理数据库应用程序时所发生的异常
2.3 环境搭建

1.在项目中创建一个lib文件夹用于存放jar文件

2.将jar包放输入lib文件夹下

3.将lib文件夹作为library

三、JDBC开发步骤[重点]

3.1 注册驱动

使用Class.forName(“com.mysql.jdbc.Driver”)手动加载字节码文件到JVM中

Class.forName("com.mysql.jdbc.Driver");
3.2 连接数据库
  • 通过DriverManager.getConnection(url,user,password) 获得数据库连接对象
    • URL:jdbc:mysql://主机名(ip):端口号/数据库名
    • user:用户名
    • password:密码
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf8","root","123");
3.3 获取发送SQL的对象

通过Connection对象获得Statement对象,用于对数据库进行通用访问的

Statement statement = connection.createStatement();
3.4执行SQL语句

编写SQL语句,并执行,接收执行后的数据

int result = statement.executeUpdate("update stu set student_name='李敢敢',sex='女' where
student_id = 'S1003'");
3.5处理结果

接收并处理操作结果

if(result > 0){
	System.out.println("执行成功");
}
3.6释放资源

遵循的是先开后关的原则,释放过程中用到的资源连接

statement.close()
connection.close()
3.7综合案例

综合六步:实现增删改

public class BasicJDBC {
    public static void main(String[] args) {
        try {
            // 注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 连接数据库
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf-8","root","root");
            // 获取发送SQL对象
            Statement statement = connection.createStatement();
            // 编写SQL语句,执行SQL语句(返回受影响行数)
            String sql = "";
            int i = statement.executeUpdate(sql);
            //处理数据
            if(i>0){
                System.out.println("执行成功");
            }
            //释放资源
            statement.close();
            connection.close();
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
}
四、ResultSet(结果集)

在执行查询SQL后,存放查询到的查询结果集数据

4.1接收结果集

ResultSet rs = statement.executeQuery(sql)

Result rs =statement.executeQuery("");
4.2 遍历ResultSet中的数据

ResultSet以表(Table)结构进行临时结果的存储,需要通过JDBC API将其中的数据进行依此获取

  • 数据行指针:初始位置在第一行数据前,没调用依此boolean next()方法,ResultSet中指针向下移动一行,结果true,表示当前行有数据
  • rs.getXxx(“列名”); 根据列名获得数
  • rs.getXxx(“整数下标”);根据列的编号舒徐获得!从1开始
boolean next() throws SQLException;//判断rs结果集中下一行是否有数据
4.2.1遍历方法
int getInt(int columnIndex) throws SQLException;// 获取当前行的第N列的int值
int getInt(String columnLabel) throws SQLException;//获得当前行column
4.3综合案例

对stu表所有数据进行遍历

4.3.1根据列的名称进行遍历

public class TestDql {
    public static void main(String[] args) {
        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.获得连接
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/companyDB?useUnicode=true&characterEncoding=utf-8","root","lixiaoning12144014");
            //3.获得SQL执行对象
            Statement statement = connection.createStatement();
            //4.执行SQL语句
            String sql = "select * from `Student`";
            ResultSet resultSet = statement.executeQuery(sql);
            //5.对结果集进行处理
            while(resultSet.next()){ // 判断结果集中是否有下一行!
                // 根据列名获取当前行的每一列数据
                String id= (String)resultSet.getObject("student_id");
                String name = (String)resultSet.getObject("student_name");
                String sex = (String)resultSet.getObject("sex");
                Date borndate = resultSet.getDate("borndate");
                String phone = (String)resultSet.getObject("phone");
                Integer gradeid = (Integer)resultSet.getObject("GradeId");
                System.out.println(id+"\t"+name+"\t"+sex+"\t"+borndate.toString()+"\t"+phone+"\t"+gradeid);
            }
            //6.释放资源
            resultSet.close();
            statement.close();
            connection.close();
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
}
4.3.2根据列的编号获取
public class BasicJDBC {
    public static void main(String[] args) {
        try {
            // 注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 连接数据库
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf-8","root","lixiaoning12144014");
            // 获取发送SQL对象
            Statement statement = connection.createStatement();
            // 编写SQL语句,执行SQL语句(返回受影响行数)
            String sql = "";
            int i = statement.executeUpdate(sql);
            //处理数据
            if(i>0){
                System.out.println("执行成功");
            }
            //释放资源
            statement.close();
            connection.close();
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
}
五、常见的错误
  • java.lang.ClassNotFoundException 找不到类 或者 没有导入jar包
  • com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:Unkonen colum ‘列名’ 与SQL语句相关的错误(表名 列名 书写错误 、约束错误、插入的值是String类型,但是没有加单引号)
  • com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:Duplicate entry ‘S1003’ for key ‘PRIMARY’ 原因:主键值已经存在!更改要插入的主键值
  • com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:Unknown column ‘password’ in
    • 可能输入的值的类型不对,确定插入元素时,对应的值的类型是否争取
六、综合案例登陆

6.1创建表
  • 创建一张用户表User
    • id:主键 自增长
    • username 字符串类型 非空
    • password 字符串类型 非空
    • phone 字符串类型 11为
  • 插入两条数据
6.2实现登录
  • 通过控制台,用户输入用户名和密码
  • 用户输入的用户名和密码作为参数,编写SQL语句
  • 如果查询到用户,则用户存在,提示登陆成功,反之,提示失败
七、SQL注入问题
7.1什么是SQL注入

当用户输入的数据中有SQL关键字或语法时,并且参与了SQL语法的编译,导致SQL语句编译后条件结果为true时

7.2 如何避免SQL注入

由于编写的SQL语句,是在用户输入数据后,整合后再编译成SQL语句。所以为了避免SQL注入的问题,使得SQL语句再用户输入数据前,SQL语句已经完成编译,成为了完整的SQL语句,在进行填充数据。

八、PreparedStatement[重点]

PreparedStatement接口继承了Statement接口,执行SQL语句的方法没有区别!

8.1 PreparedStatement 的应用

作用:1.预编译SQL语句,效率高!

​ 2.安全,可以避免SQL注入

​ 3.可以动态的填充数据,执行多个同构的SQL语句

8.1.1参数标记
//1.预编译SQL语句
PreparedStatement pstms = connection.prepareStatement(sql);
8.1.2 动态参数绑定

pstmt.setXxx(下标,值); 参数下标是从1开始,为指定占位符下标绑定值

//2.为占位符下标赋值
pstm.setString(1,username)
pstm.setString(2,password)
九、综合练习

9.1创建数据库、表

数据库 Account

  • 创建一张表Account,有以下列
    • cardId:字符串,主键
    • password:字符串,非空
    • username,字符串,非空
    • balance:小数,非空
    • phone:字符串,非空
9.2.创建项目通过JDBC实现功能

创建AccountSystem类,完成下列功能

  • 开户:控制台输入所有的账户信息,使用PreparedStatement添加至t_account表
  • 存款:控制台输入卡号、密码、存储金额进行修改
  • 取款:输入卡号、密码、取款金额
  • 转账:输入卡号、密码、对方卡号、转账金额进行修改
  • 修改密码:控制台输入卡号、密码、在输入新密码进行修改
  • 注销:控制台输入卡号、密码,删除对应的账户信息
创建表
CREATE DATABASE if not exists Account CHARACTER SET utf8;
USE Account;
CREATE TABLE t_account(
	`cardId` VARCHAR(20) PRIMARY KEY not null,
	`password` varchar(20) not null,
	`balance` DOUBLE NOT NULL,
	`phone` varchar(11)
	)charset=utf8;
	
	try-catch  ctrl+alt+t
	代码格式化  ctrl+alt+L
	快速定位异常处: F2
package com.qfedu.jdbc.t4;

import java.sql.*;
import java.util.Scanner;

public class AccountSystem {
    Scanner scanner = new Scanner(System.in);
    private static Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
    static {
        // 1.注册驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
            // 2.创建数据库连接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/Account?useUnicode=true&characterEncoding=utf-8","root","lixiaoning12144014");
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
    // 开户
    public void regiter(){
        System.out.println("请输入卡号:");
        String cardId = scanner.next();
        System.out.println("请输入密码");
        String password = scanner.next();
        System.out.println("请输入用户名");
        String username = scanner.next();
        System.out.println("请输入存款金额");
        String balance = scanner.next();
        System.out.println("请输入预留手机号码:");
        String phone = scanner.next();
        try {
           //3.创建Preparement
            String sql ="insert into `t_account`(`cardId`,`password`,`username`,`balance`,`phone`) values(?,?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            //4.为占位符赋值
            preparedStatement.setString(1,cardId);
            preparedStatement.setString(2,password);
            preparedStatement.setString(3,username);
            preparedStatement.setString(4,balance);
            preparedStatement.setString(5,phone);
            //5.执行SQL语句
            int i = preparedStatement.executeUpdate();
            if(i>0){
                System.out.println("开户成功");

            }else{
                System.out.println("开户失败");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
                try {
                    if(preparedStatement!=null){
                        preparedStatement.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
        }
    }
    // 更新
    public void saveMoney(){
        System.out.println("请输入卡号:");
        String cardId = scanner.next();
        System.out.println("请输入密码:");
        String pasword = scanner.next();
        System.out.println("请输入存款金额");
        double money = scanner.nextDouble();
        if(money > 0){
        //存款操作
            String sql = "update t_account set balance = balance + ? where cardId=? and password=?";
            try {
                preparedStatement = connection.prepareStatement(sql);
                preparedStatement.setDouble(1,money);
                preparedStatement.setString(2,cardId);
                preparedStatement.setString(3,pasword);
                // 执行,接收返回结果
                int i = preparedStatement.executeUpdate();
                if(i>0){
                    System.out.println("存款成功");
                }else{
                    System.out.println("存款失败!用户名和密码请核对!");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                if(preparedStatement!=null){
                    try {
                        preparedStatement.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }else{
            System.out.println("您输入的金额不正确");
        }
    }
    // 取款
    public void takeMoney(){
        System.out.println("请输入卡号:");
        String cardId = scanner.next();
        System.out.println("请输入密码:");
        String password = scanner.next();
        System.out.println("请输入取款金额");
        double money = scanner.nextDouble();
        if(money > 0){
            String sql = "select balance from t_account where cardId=? and password=?";
            try {
                preparedStatement =connection.prepareStatement(sql);
                preparedStatement.setString(1,cardId);
                preparedStatement.setString(2,password);
                resultSet = preparedStatement.executeQuery();
                if(resultSet.next()){
                    double balance = resultSet.getDouble(1);
                    if(money<=balance){
                        //取款成功
                        String sql2="update t_account set balance = balance-? where cardId=? and password=?";
                        preparedStatement = connection.prepareStatement(sql2);
                        preparedStatement.setDouble(1,money);
                        preparedStatement.setString(2,cardId);
                        preparedStatement.setString(3,password);
                        int i = preparedStatement.executeUpdate();
                        if(i>0){
                            System.out.println("取款成功!");
                        }else{
                            System.out.println("取款失败!");
                        }
                    }else{
                        System.out.println("余额不足!");
                    }
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                if(resultSet!=null){
                    try {
                        resultSet.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }

                }
                if(preparedStatement!=null){
                    try {
                        preparedStatement.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }

                }
            }
        }else{
            System.out.println("输入金额有误!");
        }
    }
    // 转账
    public void transferAccountS() {
        System.out.println("请输入转账方卡号:");
        String cardId = scanner.next();
        System.out.println("请输入转账方密码:");
        String pasword = scanner.next();
        System.out.println("请输入转账金额");
        double money = scanner.nextDouble();
        System.out.println("请输入接收方卡号:");
        String cardId2 = scanner.next();
        // 确定转账金额大于0
        if(money > 0){
            // 查询转账方是否存在
            String sql =  "select balance from t_account where password=? and cardId=?";
            try {
                preparedStatement = connection.prepareStatement(sql);
                preparedStatement.setString(1,pasword);
                preparedStatement.setString(2,cardId);
                resultSet = preparedStatement.executeQuery();
                if(resultSet.next()){
                    // 账号密码存在
                    double aDouble = resultSet.getDouble(1);
                    // 判断转账金额是否小于银行卡金额
                    connection.setAutoCommit(false);
                    if(aDouble >= money){
                        // 关闭事务的自动提交
                        // 减钱
                        String sql2="update t_account set balance = balance-? where password=? and cardId=?";
                        preparedStatement = connection.prepareStatement(sql2);
                        preparedStatement.setDouble(1,money);
                        preparedStatement.setString(2,pasword);
                        preparedStatement.setString(3,cardId);
                        int num1 = preparedStatement.executeUpdate();
                        // 加钱
                        String sql3="update t_account set balance = balance+? where cardId=?";
                        preparedStatement = connection.prepareStatement(sql3);
                        preparedStatement.setDouble(1,money);
                        preparedStatement.setString(2,cardId2);
                        int num2 = preparedStatement.executeUpdate();
                        if(num1>0 && num2>0){
                            System.out.println("转账成功!");
                        }else {
                            System.out.println("转账失败");
                        }
                        connection.commit();
                    }else{
                        System.out.println("余额不足");
                    }
                }else{
                    System.out.println("账号或密码不存在");
                }
            } catch (SQLException e) {
                try {
                    if(connection!=null){
                        connection.rollback();
                    }
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
                e.printStackTrace();
            }finally {
                if(resultSet!=null){
                    try {
                        resultSet.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                try {
                    connection.setAutoCommit(true);
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                if(preparedStatement!=null){
                    try {
                        preparedStatement.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
            // 转账金额是否小于卡内余额
            //
        }else{
            System.out.println("转账金额输入有误");
        }

    }
    // 关闭Connection
    public void closeConnection(){
        if(connection!=null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    // 修改密码
    public void changePassword() {
        System.out.println("请输入卡号:");
        String cardId = scanner.next();
        System.out.println("请输入密码:");
        String password = scanner.next();

        String sql = "select * from t_account where cardId=? and password=?";
        try {
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,cardId);
            preparedStatement.setString(2,password);
            ResultSet resultSet = preparedStatement.executeQuery();
            if(resultSet.next()){
                System.out.println("用户名密码正确");
                System.out.println("请输入新密码:");
                String newPassword = scanner.next();
                System.out.println("请再次输入新密码:");
                String newRewardPassword = scanner.next();
                if(newPassword.equals(newRewardPassword)){
                    String sql1 ="update t_account set password=? where cardId=?";
                    preparedStatement = connection.prepareStatement(sql1);
                    preparedStatement.setString(1,newRewardPassword);
                    preparedStatement.setString(2,cardId);
                    int i = preparedStatement.executeUpdate();
                    if(i>0){
                        System.out.println("修改成功");
                    }else{
                        System.out.println("修改失败");
                    }
                }else{
                    System.out.println("两次密码输入不一致,修改失败!");
                }
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {

            if(resultSet!=null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                if(preparedStatement!=null){
                    try {
                        preparedStatement.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }
    // 注销
    public void writeOff() {
        System.out.println("请输入卡号:");
        String cardId = scanner.next();
        System.out.println("请输入密码:");
        String password = scanner.next();
        String sql = "select * from t_account where cardId=? and password=?";
        try {
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,cardId);
            preparedStatement.setString(2,password);
            boolean execute = preparedStatement.execute();
            if(execute){
                System.out.println("是否一定要注销此账号? 1.是 2.否");
                int result = scanner.nextInt();
                if(result==1){
                 // 确认注销
                    String sql1 ="delete from t_account where cardId=?";
                    preparedStatement =connection.prepareStatement(sql1);
                    preparedStatement.setString(1,cardId);
                    int i = preparedStatement.executeUpdate();
                    if(i>0){
                        System.out.println("销户成功!");
                    }else{
                        System.out.println("销户失败!");
                    }

                }

            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(preparedStatement!=null){
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(resultSet!=null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}




package com.qfedu.jdbc.t4;

import java.util.Scanner;

public class TestAccount {
    public static void main(String[] args) {
        AccountSystem as = new AccountSystem();
        Scanner in  = new Scanner(System.in);
        System.out.println("欢迎进入此系统");
        int choice = 0;
        do{
            System.out.println("1、开户 2、存款 3、取款 4、转账 5、修改密码 6、注销 0、退出");
            System.out.println("请选择");
            choice = in.nextInt();
            switch (choice){
                // 开户
                case 1:
                    as.regiter();
                    break;
                // 存款
                case 2:
                    as.saveMoney();
                    break;
                // 取款
                case 3:
                    as.takeMoney();
                    break;
                // 转账
                case 4:
                    as.transferAccountS();
                    break;
                // 修改密码
                case 5:
                    as.changePassword();
                    break;
                // 注销
                case 6:
                    as.writeOff();
                    break;
                case 0: as.closeConnection();return;
                default:
                    System.out.println("暂无此功能");
                    return;
            }
        }while(choice!=0);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值