jdbc-210321-01

本文详细介绍了JDBC的基础概念,包括其作为Java连接数据库的接口、编程步骤(连接数据库、预编译处理防止SQL注入、事务机制的管理),并展示了如何从资源文件读取配置参数和处理查询结果集。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

jdbc - 210321 - 01

  • 了解JDBC
  • JDBC编程
    • JDBC编程步骤 连接方法01/02
    • 从资源文件读取数据库配置参数
    • 处理查询结果集
  • 登录实例(sql注入)
  • 预编译处理
  • 事务机制

JDBC了解

什么是JDBC

​ Java DataBase Connective(Java语言连接数据库)


JDBC的本质是什么
JDBC是SUN公司指定的一套接口(interface)
java.sql.*;     这个包下的接口


接口都有调用者和实现者。
面向接口调用,面向接口写实现类,这都属于面向接口编程

为什么要面向接口编程:
	解耦合,降低程序的耦合性,提高程序的扩展性
	多态机制就是典型的面向抽象编程
	

JDBC的本质实则就是------>一套接口

每个数据库的底层实现原理都是不一样的,
所以SUN公司制定了JDBC这样的一套接口,用来规范,方便了程序员开发

JDBC编程

JDBC编程步骤
1.	注册驱动		(告诉Java程序,要连接哪个数据库)
2.	获取连接		(表示JVM的进程和数据库之间的进程打开了,这属于进程之间的通信,使用完要关闭资源)
3.	获取数据操作对象 (用来执行SQL语句)
4.	执行SQL语句		(DQL,DML...)
5.	处理查询结果集	  (只有第4步执行的是select语句的时候,才会使用到这第5步处理查询结果集)	
6.	释放资源		(使用完资源一定要关闭,Java和数据库属于进程间的通信,开启之后一定要关闭)

        url: 统一资源定位符
        url组成部分:
            协议
            ip
            port    端口号
            资源名

        一下两个都是百度
            https://www.baidu.com/
            http://110.242.68.3:80/index.html
                http://     通信协议
                110.242.68.3    服务器IP地址
                index.html     服务器上的某个资源名
连接方法01

/*
	这是jar包为mysql-connector-java-5.1.25-bin的,,
	我的jar包为mysql-connector-java-8.0.22
	
	我的8版本的不能运行此代码,,但是5版本的能,
	因为我的数据库也是mysql-8.0.22-winx64,,,对应着jar包为mysql-connector-java-8.0.22
*/
import com.mysql.jdbc.Driver;
import java.sql.*;
public class Demo02 {
    private static final String URL1 = "jdbc:mysql://localhost:3306/test";
    private static final String ROOT = "root";
    private static final String PASSWORD = "admin";

    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;

        try {
            // 1. 注册驱动
            Driver driver = new com.mysql.jdbc.Driver();
            DriverManager.registerDriver(driver);

            // 2.连接数据库
            conn = DriverManager.getConnection(URL1,ROOT,PASSWORD);

            System.out.println(conn);

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
连接方法02
import java.sql.*;
public class Demo01 {
    private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
    private static final String URL1 = "jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC";
    private static final String ROOT = "root";
    private static final String PASSWORD = "admin";

    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        try{
            // 1.注册驱动
            Class.forName(DRIVER);

            // 2.获取连接
            conn = DriverManager.getConnection(URL1,ROOT,PASSWORD);
            // 输出连接对象
            System.out.println(conn);       //com.mysql.cj.jdbc.ConnectionImpl@51081592

            // 3.获取数据库操作对象
            stmt = conn.createStatement();

            // 4.执行SQL语句
            String insersql = "insert into student(name,sex,address) values('张三','男','Chain')";
            String updatesql = "update student set name='lisi' , address='henan' where id=5";
            String deletesql = "delete from student where id=6";
            int count1 = stmt.executeUpdate(insersql);
            int count2 = stmt.executeUpdate(updatesql);
            int count3 = stmt.executeUpdate(deletesql);
            System.out.println(count1 == 1 ? "添加成功":"添加失败");
            System.out.println(count2 == 1 ? "修改成功":"修改失败");
            System.out.println(count3 == 1 ? "删除成功":"删除失败");

            // 5.处理查询结果集

        }catch (SQLException e){
            e.printStackTrace();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 6.释放资源
            try {
                if(stmt != null){
                    stmt.close();
                }
            }catch (SQLException e){
                e.printStackTrace();
            }

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

从资源文件读取参数
import java.sql.*;
import java.util.ResourceBundle;
public class Demo03 {

    // 从 jdbc.properties 文件中读取资源
    static ResourceBundle rb = ResourceBundle.getBundle("jdbc");
    static String driver = rb.getString("driver");
    static String url = rb.getString("url");
    static String user = rb.getString("user");
    static String password = rb.getString("password");

    public static void main(String[] args) {

        Connection conn = null;
        Statement stmt = null;

        try{
            // 1.注册驱动
            Class.forName(driver);

            // 2.获取连接
            conn = DriverManager.getConnection(url,user,password);
            // 输出连接对象
            System.out.println(conn);       //com.mysql.cj.jdbc.ConnectionImpl@51081592

            // 3.获取数据库操作对象
            stmt = conn.createStatement();

            // 4.执行SQL语句
            String updatesql = "update student set name='lisi' , address='henan' where id=5";
            int count2 = stmt.executeUpdate(updatesql);
            System.out.println(count2 == 1 ? "修改成功":"修改失败");

            // 5.处理查询结果集

        }catch (SQLException e){
            e.printStackTrace();
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }finally {
            // 6.释放资源
            try {
                if(stmt != null){
                    stmt.close();
                }
            }catch (SQLException e){
                e.printStackTrace();
            }

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

jdbc.properties

driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC
user = root
password = admin

#jdbc.properties

处理查询结果集
import java.sql.*;
public class Demo04 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;

        try {
            // 1.加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 2.连接数据库
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC","root","admin");

            // 3.获取数据操作对象
            stmt = conn.createStatement();

            // 4.执行SQL语句
            // int executeUpdate(sql)           sql语句是insert,delete,update,,,返回一个int类型
            // ResultSet executeQuery(sql)      sql语句是select,,,返回一个ResultSet类型
            String sql = "select id,name,sex,address from student";
            rs = stmt.executeQuery(sql);        //执行DQL语句

            // 5.返回结果集

            // 5.1
            // 光标所有行数据
            // 根据下标找数据,,,1,2,3 代表数据库表中的类,,,数据库中的下标从1开始
            // getString(),,,方法不管从数据库中取出什么类型的数据,都以String类型返回
//            boolean flag = rs.next();
//            if(flag){
//                String name = rs.getString(1);
//                String sex = rs.getString(2);
//                String address = rs.getString(3);
//                System.out.println(name + " " + sex + " " + address);
//            }
//            flag = rs.next();
//            if(flag){
//                String name = rs.getString(1);
//                String sex = rs.getString(2);
//                String address = rs.getString(3);
//                System.out.println(name + " " + sex + " " + address);
//            }

//            while (rs.next()){
//                String name = rs.getString(1);
//                String sex = rs.getString(2);
//                String address = rs.getString(3);
//                System.out.println(name + " " + sex + " " + address);
//            }

            // 5.2
            // 根据数据库的列明找数据
            while (rs.next()){
                // 取出特定类型的数据
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String sex = rs.getString("sex");
                String address = rs.getString("address");
                System.out.println(id + " " + name + " " + sex + " " + address);
            }
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }catch (SQLException e){
            e.printStackTrace();
        }finally {
            // 6.关闭资源
            try{
                if(rs != null){
                    rs.close();
                }
            }catch (SQLException e){
                e.printStackTrace();
            }
            try {
                if(stmt != null){
                    stmt.close();
                }
            }catch (SQLException e){
                e.printStackTrace();
            }
            try {
                if(conn != null){
                    conn.close();
                }
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
    }
}

登录实例(sql注入)

/**
 * Statement存在sql注入问题
      请输入登录名:
      111
      请输入密码:
      111' or '1'='1
      登录成功

    导致sql注入问题:
        用户输入的信息中,含有sql语句关键字,,,
        并且在编译sql时,编译了进去,从而导致sql语句失去原来的含义
 */

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

public class Demo01 {
    public static void main(String[] args) {
        // 接收页面用户登录信息
        Map<String , String> userLoginInfo = intiUI();

        boolean loginIsSuccess = login(userLoginInfo);
        System.out.println(loginIsSuccess ? "登录成功":"登录失败");
    }

    /**
     * 初始化用户登录界面
     * @return  返回一个Map类型的数组,用来保存用户数据的登录信息
     */
    private static Map<String, String> intiUI() {
        Scanner s = new Scanner(System.in);

        System.out.println("请输入登录名:");
        String loginName = s.nextLine();
        System.out.println("请输入密码:");
        String loginPwd = s.nextLine();

        Map<String,String> loginInfo = new HashMap<>();
        loginInfo.put("loginName",loginName);
        loginInfo.put("loginPwd",loginPwd);

        return loginInfo;
    }

    /**
     *
     * @param userLoginInfo
     * @return  返回一个boolean,用来判断数据库中的数据和userLoginInfo是否一致
     */
    private static boolean login(Map<String, String> userLoginInfo) {
        boolean flag = false;
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;

        try {
            // 注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC","root","admin");

            // 获取数据库操作对象
            stmt = conn.createStatement();

            // 执行sql语句
            /*
                以下语句完成了sql语句拼接,发送sql语句给DBMS,DBMS进行编译
                正好将用户提供的,,非法信息,,编译进去,,导致原来sql语句含义被扭曲
             */
            String sql = "select * from t_user where loginname='"+userLoginInfo.get("loginName")+"' and loginpwd='"+userLoginInfo.get("loginPwd")+"'";
            rs = stmt.executeQuery(sql);

            // 处理结果集
            if(rs.next()){
                flag = true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e){
            e.printStackTrace();
        }finally{
            if(rs != null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(stmt != null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

        return flag;
    }
}

预编译处理(PreparedStatement)

/*
    解决SQL注入问题:
        只要用户体统的信息不参与SQL语句的编译过程,就OK
        所以要是用PreparedStatement
         PreparedStatement接口继承了java.sql.Statement
         PreparedStatement是属于预编译数据库操作对象
         PreparedStatement原理是,,预先对sql语句的框架进行编译,然后宰割sql语句传值

    Statement 和 PreparedStatement :
        Statement存在sql注入问题,,PreparedStatement解决了sql注入问题
        Statement是编译一次执行一次,,PreparedStatement是编译一次,可执行多次,,PreparedStatement效率高
        PreparedStatement在编译阶段做类型安全检查


   Statement也不是没有用,,如果业务方面必须要sql注入时,就必须是Statement
*/

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

public class Demo02 {
    public static void main(String[] args) {
        // 页面初始化,接收用户信息
        Map<String,String> userLoginInfo = initUI();
        // 验证用户信息
        boolean isSucceedLogin = login(userLoginInfo);
        System.out.println(isSucceedLogin ? "登录成功":"登录失败");
    }

    private static boolean login(Map<String, String> userLoginInfo) {
        boolean flag = false;

        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        String driver = "com.mysql.cj.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC";
        String user = "root";
        String password = "admin";

        try {
            // 注册驱动
            Class.forName(driver);

            // 获取连接
            conn = DriverManager.getConnection(url,user,password);

            // 获取预编译操作对象
            String sql = "select * from t_user where loginname=? and loginpwd=?";
            ps = conn.prepareStatement(sql);
            ps.setString(1,userLoginInfo.get("loginName"));         // 数字1,,代表第一个?
            ps.setString(2,userLoginInfo.get("loginPwd"));          // 数字2,,代表第二个?

            // 执行sql语句
            rs = ps.executeQuery();

            //  处理结果
            if(rs.next()){
                flag = true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e){
            e.printStackTrace();
        }finally {
            if(rs != null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(ps != null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return flag;
    }

    private static Map<String, String> initUI() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("please input you loginNumber:");
        String loginName = scanner.nextLine();
        System.out.println("please input you loginPassword:");
        String loginPwd = scanner.nextLine();

        Map<String , String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);

        return userLoginInfo;
    }
}

PreparedStatement增删改

package bgy02;

import java.sql.*;

public class Demo03 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;

        int count = 0;

        String driver = "com.mysql.cj.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC";
        String user = "root";
        String password = "admin";

        try {
            // 注册驱动
            Class.forName(driver);

            // 连接数据库
            conn = DriverManager.getConnection(url,user,password);

            // 预编译sql语句

            // 添加
//            String sql = "insert into t_user (id,loginname,loginpwd) values(?,?,?)";
//            ps = conn.prepareStatement(sql);
//            ps.setInt(1,10);
//            ps.setString(2,"hhh");
//            ps.setString(3,"hhh");

            // 修改
//            String sql = "update t_user set loginname=? ,loginpwd=? where id=?";
//            ps = conn.prepareStatement(sql);
//            ps.setString(1,"hhh01");
//            ps.setString(2,"hhh01");
//            ps.setInt(3,10);

            // 删除
            String sql = "delete from t_user where id=?";
            ps = conn.prepareStatement(sql);
            ps.setInt(1,10);

            // 执行sql语句
            count = ps.executeUpdate();

            System.out.println(count);
            System.out.println(count == 1 ? "操作成功":"操作失败");

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e){
            e.printStackTrace();
        }finally {
            if(ps != null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

事务机制

JDBC事务机制:
	JDBC中的事务是自动提交的。只要执行任意一条DML语句,则提交一次,这是JDBC默认的事务行为。
	在实际的业务当中,通常是N条DML语句共同联合才能完成的,必须要保证他们这些DML语句在同一个事务中同		时成功或同时失败
失败Demo
package bgy02;

import java.sql.*;

public class Demo04 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        int count = 0;

        String driver = "com.mysql.cj.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC";
        String user = "root";
        String password = "admin";

        try {
            // 1.
            Class.forName(driver);

            // 2.
            conn = DriverManager.getConnection(url,user,password);

            // 3.
            String sql = "update t_act set balance=? where actno=?";
            ps = conn.prepareStatement(sql);

            // 传值
            ps.setInt(1,10000);
            ps.setInt(2,111);
            count = ps.executeUpdate();

            //  这个会抛出异常,,,以至于不会执行下面的程序,,到这就直接结束了
            String s =null;
            s.toString();

            /*
                会造成数据的丢掉
             */

            // 传值
            ps.setInt(1,10000);
            ps.setInt(2,222);
            count += ps.executeUpdate();

            System.out.println(count == 2 ? "转账成功":"转账失败");

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e){
            e.printStackTrace();
        }finally {
            if(ps != null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

运行前:

运行后:

报错:


解决
/*
    三步:
        conn.setAutoCommit(false);

        conn.commit();

        if(conn != null){
             try{
                 conn.rollback();
             }catch (SQLException e1){
                 e1.printStackTrace();;
             }
        }
 */

import java.sql.*;
public class Demo05 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        int count = 0;

        String driver = "com.mysql.cj.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC";
        String user = "root";
        String password = "admin";

        try {
            // 1.
            Class.forName(driver);

            // 2.
            conn = DriverManager.getConnection(url,user,password);

            //  将 ‘自动提交机制’ 修改为 ‘手动提交’
            //  将 ‘自动提交机制’ 修改为 ‘手动提交’
            //  将 ‘自动提交机制’ 修改为 ‘手动提交’
            //  开启事务
            //  开启事务
            //  开启事务
            conn.setAutoCommit(false);

            // 3.
            String sql = "update t_act set balance=? where actno=?";
            ps = conn.prepareStatement(sql);

            // 传值
            ps.setInt(1,10000);
            ps.setInt(2,111);
            count = ps.executeUpdate();

            String s =null;
            s.toString();

            /*
                会造成数据的丢掉
             */

            // 传值
            ps.setInt(1,10000);
            ps.setInt(2,222);
            count += ps.executeUpdate();

            System.out.println(count == 2 ? "转账成功":"转账失败");

            //  程序能走到这,说明上面程序没异常,事务结束,手动提交数据
            //  程序能走到这,说明上面程序没异常,事务结束,手动提交数据
            //  程序能走到这,说明上面程序没异常,事务结束,手动提交数据
            //  提交事务
            //  提交事务
            //  提交事务
            conn.commit();

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e){
            e.printStackTrace();
        } catch (Exception e){
            // 回滚事务,,,,就是出了异常的话就,,数据恢复
            // 回滚事务,,,,就是出了异常的话就,,数据恢复
            // 回滚事务,,,,就是出了异常的话就,,数据恢复
            if(conn != null){
                try{
                    conn.rollback();
                }catch (SQLException e1){
                    e1.printStackTrace();;
                }
            }
        }finally {
            if(ps != null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值