JDBC基础

JDBC

  • java DataBase Connectivty(java语言连接数据库)
  • JDBC是sun制定的接口(interface):java.sql.*
    • 面向接口:解耦合:降低程序的耦合度,提高程序的扩展力
    • 每一个数据库底层实现原理都不一样
      在这里插入图片描述

idea导入JDBCjar包

  • JDBC开发前,先从官网下载对应的驱动jar包,然后将其配置到环境变量classpath当中
  • classpath = .;E:\JDBC\mysql-connector-java-8.0.27
  • 使用IDEA的时候,不需要配置环境变量
  • 新建空项目,在项目里面新建模块
  • 在对应的模块上,右击,选择open module setting
    在这里插入图片描述在这里插入图片描述

JDBC流程—六步

注册驱动

  • 告诉java程序,即将连接哪个数据库
  • 使用java.sql.Driver接口的DriverManager.registerDriver()方法,传入一个数据库驱动,该接口是sun公司提供,具体的实现类“驱动”是数据库公司提供,即创建对象是,需要找到数据库对应Driver接口的实现类——也是Driver。
  • 区分清楚这两个Driver

获取连接

  • 表示JVM和数据库的进程通道打开,使用完之后,关闭
  • DriverManager的getConnection()方法可以获取连接
  • 方法需要的参数:协议;IP;数据库端口号;数据库实例名
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

获取数据库操作对象

  • 专门执行sql语句的对象
  • Connection的createStatement()可以获取对象

执行SQL语句

  • DQL、DML…

处理查询结果集

  • 只有当第四步执行的select语句时,才有第五步处理查询结果集

释放资源

  • 使用完资源,就需要关闭资源。

在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

注册驱动——使用类加载

  • 该方法常用,参数是字符串,字符串可以写进配置文件
  • Class.forName(“E:\JDBC\mysql-connector-java-8.0.27\src\main\user-impl\java\com\mysql\cj\jdbc”);
    在这里插入图片描述

数据存放配置文件

  • 在jdbc.properties文件配置如下内容
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/yi
user=root
password=1230258

在这里插入图片描述

使用查询语句,处理结果集

  • 查询语句:String sql = “select empno,ename,sal from emp”;
  • stmt.executeQuery(sql); 执行语句,返回结果集ResultSet rs
  • ResultSet 有一个next() 方法,当该行有数据,rs.next()返回值为true
  • 当返回值为true时,可以遍历该行的数据在这里插入图片描述在这里插入图片描述

用户登录功能

  • 数据库内数据
    在这里插入图片描述
  • 获取用户登录时输入信息
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
package jdbcfrist;

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

/**
 * 实现功能:
 *  需求:模拟用户登录功能
 *  程序运行时,提供一个输入入口。让用户输入用户名、密码
 *  之后,提交信息java程序收集用户信息
 *  java程序连接数据库,验证用户和密码是否合法
 *  合法:登录成功
 *  不合法:登录失败
 *  */
public class loadFuction {
    public static void main(String[] args) {
        //初始化界面
        Map<String,String> unserinfo =initUI();
        //验证用户名和密码
        boolean result = login(unserinfo);
        //输出结果
        System.out.println(result?"登录成功":"登录失败");
    }
    /**
     * 初始化用户界面
     * @return  用户名和密码
     */
    private static Map<String,String> initUI() {
        Scanner s =new Scanner(System.in);
        System.out.println("用户名 :");
        String loginName =s.nextLine();
        System.out.println("密码 :");
        String loginPassword =s.nextLine();
        //获取完信息,加载到Map集合
        Map<String,String> user = new HashMap<>();
        user.put("loginName",loginName);
        user.put("loginPassword",loginPassword);
        return user;
    }

    /**
     * @param unserinfo
     * @return
     */
    private static boolean login(Map<String, String> unserinfo) {
        //jdbc代码
        ResourceBundle bundle =ResourceBundle.getBundle("jdbc");
        Connection conn=null;
        Statement stmt =null;
        ResultSet rs =null;
        //取出数据
        String username =unserinfo.get("loginName");
        String password =unserinfo.get("loginPassword");
        //标志
        boolean flag =false;
        try {
            Class.forName(bundle.getString("driver"));
            conn= DriverManager.getConnection(bundle.getString("url"),bundle.getString("user"),
                    bundle.getString("password"));
            stmt = conn.createStatement();
            String sql = "select * from login where user ='"+username+"' and password='"+password+"'";
            rs=stmt.executeQuery(sql);
            if(rs.next()){
                flag=true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.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;
    }
}

sql注入

  • 用户登录出现的问题:
    • 用户名:aaa
    • 密码:aaa’or’1’='1
      在这里插入图片描述
  • 这样的现象被称为sql注入(安全隐患)
  • 导致sql注入的根本原因
    • 用户输入的信息含有sql语句的关键字,并且这些关键字参与sql语句的编译过程
    • 导致sql原意被扭曲,达到sql注入
      在这里插入图片描述

sql注入解决—perparementStatement

  • 目标:用户提供的信息不参与sql语句的编译过程,问题就可以解决
  • 要想用户提供的信息不参与sql语句的编译,那么就需要使用java.sql.PreparedStatement
  • preparedStatement接口继承了java.sql.Statement,属于预编译的数据库操作对象
  • 执行效果
    在这里插入图片描述在这里插入图片描述
package jdbcfrist;

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

/**
 * 实现功能:
 *  需求:模拟用户登录功能
 *  程序运行时,提供一个输入入口。让用户输入用户名、密码
 *  之后,提交信息java程序收集用户信息
 *  java程序连接数据库,验证用户和密码是否合法
 *  合法:登录成功
 *  不合法:登录失败
 *  */
public class loadFuction {
    public static void main(String[] args) {
        //初始化界面
        Map<String,String> unserinfo =initUI();
        //验证用户名和密码
        boolean result = login(unserinfo);
        //输出结果
        System.out.println(result?"登录成功":"登录失败");
    }
    /**
     * 初始化用户界面
     * @return  用户名和密码
     */
    private static Map<String,String> initUI() {
        Scanner s =new Scanner(System.in);
        System.out.println("用户名 :");
        String loginName =s.nextLine();
        System.out.println("密码 :");
        String loginPassword =s.nextLine();
        //获取完信息,加载到Map集合
        Map<String,String> user = new HashMap<>();
        user.put("loginName",loginName);
        user.put("loginPassword",loginPassword);
        return user;
    }

    /**
     * @param unserinfo
     * @return
     */
    private static boolean login(Map<String, String> unserinfo) {
        //jdbc代码
        ResourceBundle bundle =ResourceBundle.getBundle("jdbc");
        Connection conn=null;
        Statement stmt =null;
        ResultSet rs =null;
        //取出数据
        String username =unserinfo.get("loginName");
        String password =unserinfo.get("loginPassword");
        //标志
        boolean flag =false;
        try {
            Class.forName(bundle.getString("driver"));
            conn= DriverManager.getConnection(bundle.getString("url"),bundle.getString("user"),
                    bundle.getString("password"));
            stmt = conn.createStatement();
            String sql = "select * from login where user ='"+username+"' and password='"+password+"'";
            rs=stmt.executeQuery(sql);
            if(rs.next()){
                flag=true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.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;
    }
}

PerparementStatement ; Statement

  • Statement存在sql注入问题;PerparementStatement解决sql注入问题
  • Statement编译一次执行一次;PerparementStatement编译一次,可执行N次。PerparementStatement效率高一些
  • PerparementStatement会在编译阶段做类型的安全检查
  • 即:PerparementStatement使用较多,但极少数情况下仍需要使用Statement

Statement

  • 使用场景
    • 业务方面要求sql注入的情况
    • 凡是业务要求是sql语句拼接的,必须使用Statement。单纯的传“值”,使用PerparementStatement
package jdbcfrist;

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

/**
 * 用户在控制台输入desc:降序;asc升序
 */
public class Orderby {
    public static void main(String[] args) {
        Scanner s =new Scanner(System.in);
        System.out.println("请输入desc或者asc,desc为降序;asc为升序");
        String m = s.nextLine();
        //jdbc
        ResourceBundle bundle =ResourceBundle.getBundle("jdbc");
        Connection conn =null;
        Statement stmt =null;
        ResultSet rs =null;
        try {
            Class.forName(bundle.getString("driver"));
            conn = DriverManager.getConnection(bundle.getString("url"),
                    bundle.getString("user"),bundle.getString("password"));
            stmt =conn.createStatement();
            String sql = "select sal ,ename from emp order by sal "+m;
            rs= stmt.executeQuery(sql);
            while(rs.next()){
                int sal = rs.getInt("sal");
                String name =rs.getString("ename");
                System.out.println(sal+"  "+name);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.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();
                }
            }
        }

    }
}

PerparementStatement

  • 使用PerparementStatement 完成增删改:出现的问题
package jdbcfrist;

import java.sql.*;
import java.util.ResourceBundle;
/**
 * 使用PerparementStatement 完成增删改
 */
public class jdbcTest04 {
    public static void main(String[] args) {
        //注册驱动
        ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
        Connection conn = null;
        PreparedStatement ps =null;

        try {
            //建立连接
            Class.forName(bundle.getString("driver"));
            conn= DriverManager.getConnection(bundle.getString("url"),bundle.getString("user"),
                    bundle.getString("password"));
            //获取预编译数据库对象
            String sql = "update dept set dname =? where deptno =?";
            ps =conn.prepareStatement(sql);
                //传值
            ps.setString(1,"x部门");
            ps.setInt(2,30);
            int count = ps.executeUpdate();
            /**
             * 在 int count = ps.executeUpdate();处加断点可以看出
             * jdbc只要执行任意一条DML语句,就提交一次。即jdbc自动提交
             * 这样的处理方式是操作者不想要的,因为在业务中可能需要多个sql语句
             * 当前面的sql语句执行完,如果有一个sql语句发生异常,不再执行
             * 但是之前的sql的修改已经写进数据库
             *
             */
            ps.setString(1,"y部门");
            ps.setInt(2,20);
            count = ps.executeUpdate();

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.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存在自动提交sql语句,如果一个事务未执行完,就出现异常。那么就会造成数据的错误。如图所示
    在这里插入图片描述在这里插入图片描述
setAutoCommit(false)
  • 解决方法
    在这里插入图片描述
package jdbcfrist;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ResourceBundle;

/**
 * 数据库中有两个银行账户
 *  111 存款20000
 *  222 存款0
 *      现在111账户给222账户转账10000
 *      使得两个账户都有10000存款
 */
public class bank {
    public static void main(String[] args) {
        //注册驱动
        ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
        Connection conn = null;
        PreparedStatement ps =null;

        try {
            //建立连接
            Class.forName(bundle.getString("driver"));
            conn= DriverManager.getConnection(bundle.getString("url"),bundle.getString("user"),
                    bundle.getString("password"));
                //将自动提交修改为手动提交
            //开启事务
            conn.setAutoCommit(false);
            //获取预编译数据库对象
            String sql = "update t_act set banlance=? where actno=?";
            ps =conn.prepareStatement(sql);
            //传值
            ps.setInt(1,10000);
            ps.setInt(2,111);
            int 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) {
            //回滚事务
            if(conn!=null){
                try {
                    conn.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.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封装工具类

package jdbcfrist;

import java.sql.*;

/**
 * JDBC工具类,简化JDBC编程
 */
public class DBUtil {
    /**
     * 工具类的构造方法是私有的
     * 因为工具类的方法都是静态的,不需要new对象,直接采用类名调用
     */
    private DBUtil(){

    }

    /**
     * 静态代码块在类加载时执行,只执行一次
     */
    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static Connection getConnection() throws Exception{
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/yiyu", "root", "970619");
    }

    /**
     * 关闭
     * @param conn 连接对象
     * @param ps    数据库操作对象
     * @param rs    结果集
     */
    public static  void close(Connection conn, Statement ps, ResultSet rs){
        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();
            }
        }
    }
}

模糊查询

package jdbcfrist;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
/**
 * 1 测试DBUtil
 * 2 模糊查询
 */
public class DBUtilTest {
    public static void main(String[] args) {
        Connection conn = null;
        ResultSet rs=null;
        PreparedStatement ps = null;
        try {
            //获取连接
            conn = DBUtil.getConnection();
            //获取预编译的数据库操作对象
            String sql="select ename from emp where ename like ?";
            ps=conn.prepareStatement(sql);
            ps.setString(1,"%A%");
            rs=ps.executeQuery();
            while (rs.next()){
                System.out.println(rs.getString("ename"));
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            DBUtil.close(conn,ps,rs);
        }
    }
}

行级锁

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值