JDBC实现DML,DQL以及注入现象解释和解决方案

JDBC

1、JDBC是什么?
    Java DataBase Connectivity(Java语言连接数据库)

2、JDBC的本质是什么?
    JDBC是SUN公司制定的一套接口(interface)
        java.sql.*; (这个软件包下有很多接口。)

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

    为什么要面向接口编程?
        解耦合:降低程序的耦合度,提高程序的扩展力。
        多态机制就是非常典型的:面向抽象编程。(不要面向具体编程)
            建议:
                Animal a = new Cat();
                Animal a = new Dog();
                // 喂养的方法
                public void feed(Animal a){ // 面向父类型编程。
                
                }
            不建议:
                Dog d = new Dog();
                Cat c = new Cat();
    
    思考:为什么SUN制定一套JDBC接口呢?
        因为每一个数据库的底层实现原理都不一样。
        Oracle数据库有自己的原理。
        MySQL数据库也有自己的原理。
        MS SqlServer数据库也有自己的原理。
        ....
        每一个数据库产品都有自己独特的实现原理。
    
    JDBC的本质到底是什么?
        一套接口。

3、JDBC开发前的准备工作,先从官网下载对应的驱动jar包,然后将其配置到环境变量classpath当中。

    classpath=.;D:\course\06-JDBC\resources\MySql Connector Java 5.1.23\mysql-connector-java-5.1.23-bin.jar

    以上的配置是针对于文本编辑器的方式开发,使用IDEA工具的时候,不需要配置以上的环境变量。
    IDEA有自己的配置方式。
    
4、JDBC编程六步(需要背会)
    
    第一步:注册驱动(作用:告诉Java程序,即将要连接的是哪个品牌的数据库)

    第二步:获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完之后一定要关闭通道。)

    第三步:获取数据库操作对象(专门执行sql语句的对象)

    第四步:执行SQL语句(DQL DML....)

    第五步:处理查询结果集(只有当第四步执行的是select语句的时候,才有这第五步处理查询结果集。)

图解

    第六步:释放资源(使用完资源之后一定要关闭资源。Java和数据库属于进程间的通信,开启之后一定要关闭。)

JDBC的本质

 

java中实现数据库的DML(insert,delete,update)

Connection conn=null;
Statement stmt=null;
try{
    //注册驱动
    Class.forName("com.mysql.jdbc.Driver");
    //获取连接
    conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");
    //获取数据库操作对象
    stmt=conn.createStatement();
    //执行sql语句
    String sql="delete from dept where deptno=50 or deptno=60";
    int count=stmt.executeUpdate(sql);
    System.out.println(count==2?"操作成功":"操作失败");
    //处理查询结果集
    //释放资源
}catch(SQLException|ClassNotFoundException e){
    e.printStackTrace();
}finally{
    if(stmt!=null){
        try{
            stmt.close();
        }catch(SQLException e){
            e.printStackTrace();
        }
    }
    if(conn!=null){
        try{
            conn.close();
        }catch(SQLException e){
            e.printStackTrace();
        }
    }
}

java中实现数据库的DQL(select)

Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
try{
    //注册驱动
    Class.forName("com.mysql.jdbc.Driver");
    //获取连接
    conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");
    //获取数据库操作对象
    stmt=conn.createStatement();
    //执行sql语句
    String sql="select empno,ename,sal from emp";
    rs=stmt.executeQuery(sql);
    //处理查询结果集
    while(rs.next()){
        String empno=rs.getString("empno");
        String ename=rs.getString("ename");
        int sal=rs.getInt("sal");
        System.out.println(empno+"\t"+ename+"\t"+sal);
    }
    //释放资源
}catch(ClassNotFoundException | 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();
        }
    }
}

分析JDBC中存在的注入问题:

通过以下实例了解什么是注入?

/*
实现功能:
    1、需求:模拟用户登录功能的实现。
    2、业务描述:
        程序运行的时候,提供一个输入的入口,可以让用户输入用户名和密码
        用户输入用户名和密码之后,提交信息,java程序收集到用户信息
        java程序连接数据库验证用户名和密码是否合法
        合法:显示登录成功
        不合法:显示登录失败
    3、数据的准备:
        在实际开发中,表的设计会使用专业的建模工具,安装PowerDesigner
        使用PD工具来进行数据库表的设计。
    4、当前程序存在问题:
        用户名:
        fdsa
        密码:
        fdsa' or '1'='1
        登录成功
        这种现象被称为SQL注入(安全隐患)。
    5、导致SQL注入的根本原因
        用户输入的信息含有sql语句的关键字,并且这些关键字参与了sql语句的编译过程
        导致了sql语句的原意被扭曲。进而达到sql注入。
*/

public static void main(String[] args) {
        //用户登录界面
        Map<String,String> userLoginInfo=initUI();

        //登录验证
        boolean loginSuccess=login(userLoginInfo);

        System.out.println(loginSuccess==true?"登录成功":"用户名或密码不对");
    }

    /**
     * 登录验证
     * @param userLoginInfo 用户的用户名和密码
     * @return返回true表示登录成功,返回false表示登录失败
     */
    private static boolean login(Map<String, String> userLoginInfo) {
        Boolean loginSuccess=false;
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;
        try{
            //注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //获取连接
            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");
            //获取数据库操作对象
            stmt=conn.createStatement();
            //执行sql语句
            String sql="select * from t_user where loginName='"+userLoginInfo.get("loginName")+"'and loginPwd='"+userLoginInfo.get("loginPwd")+"'";
            //以上正好完成了sql语句的拼接,以下代码的含义是,发送sql语句给DBMS,DBMS进行sql编译。
            //正好将用户提供的“非法信息”编译进去。导致了原sql语句的含义被扭曲了
            rs=stmt.executeQuery(sql);
            //处理查询结果集
            if(rs.next()){
                loginSuccess=true;
            }
/*            //执行sql语句
            String sql="select loginName,loginPwd from t_user";
            rs=stmt.executeQuery(sql);
            //处理查询结果集
            while (rs.next()){
                String loginName=rs.getString("loginName");
                String loginPwd=rs.getString("loginPwd");
                //System.out.println(loginName+"\t"+loginPwd);
                if(loginName.equals(userLoginInfo.get("loginName"))&&loginPwd.equals(userLoginInfo.get("loginPwd"))){
                //if(loginName==userLoginInfo.get("loginName")&&loginPwd==userLoginInfo.get("loginPwd")){
                    return true;
                }
            }*/

            //释放资源
        }catch(SQLException |ClassNotFoundException 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 loginSuccess;
    }

    /**
     * 用户登录界面
     * @return返回一个HashMap集合,里面包含用户的用户名和密码。
     */
    private static Map<String, String> initUI() {
        Scanner s=new Scanner(System.in);

        System.out.println("用户名:");
        String loginName=s.nextLine();

        System.out.println("密码:");
        String loginPwd=s.nextLine();

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

/**
* 1、解决SQL注入问题
*      只要用户提供的信息不参与SQL语句的编译过程。
*      即使用户提供的信息中含有SQL语句的关键字,但是没有参与编译,不起作用。
*      要想用户信息不参与SQL语句的编译,那么必须使用java.sql.PreparedStatement
*      PreparedStatement接口继承了java.sql.Statement
*      PreparedStatement是属于预编译的数据库操作对象
*      PreparedStatement的原理是:预先对SQL语句的框架进行编译,然后再给SQL语句传值
* 2、对比一下PreparedStatement和Statement?
*      -Statement存在SQL注入问题,PreparedStatement解决的SQL注入问题。
*      -Statement是编译一次执行一次。PreparedStatement是编译一次,执行N次。PreparedStatement的效率高一些
*      -PreparedStatement会在编译阶段做类型安全检查。
*
*      综上所述:PrepareStatement使用较多,只有极少数的情况下需要使用Statement。
* 3、什么情况下必须使用Statement呢?
*      业务方面要求必须支持SQL注入的时候。
*/

public static void main(String[] args) {
    //用户登录界面
    Map<String,String> userLoginInfo=initUI();
    //登录验证
    boolean loginSuccess=login(userLoginInfo);
    System.out.println(loginSuccess?"登录成功":"用户名或密码错误");
}

/**
* 登录验证
* @return返回true表示登录成功,返回false表示登录失败
*/
private static boolean login( Map<String,String> userLoginInfo){
    //获取用户输入的值
    String loginName=userLoginInfo.get("loginName");
    String loginPwd=userLoginInfo.get("loginPwd");
    //执行JDBC语句
    Boolean loginSuccess=false;
    Connection conn=null;
    PreparedStatement ps=null;
    ResultSet rs=null;
    try{
        //注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        //获取连接
        conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");
        //获取数据库操作对象
        //SQL语句的框架。其中一个占位符,一个?将来接受一个"值",注意:占位符不能使用单引号括起来。
        String sql="select *from t_user where loginName= ? and loginPwd= ?";
        //程序执行到此处,会发发送sql语句框架给DBMS,然后DBMS进行SQL语句的预先编译。
        ps=conn.prepareStatement(sql);
        //给占位符传值,第一个?的下标是1,JDBC中的所有下标从1开始。
        ps.setString(1,loginName);
        ps.setString(2,loginPwd);
        //执行sql语句
        rs=ps.executeQuery();
        //处理查询结果集
        if (rs.next()){
            loginSuccess=true;
        }
        //释放资源
    }catch(SQLException | ClassNotFoundException 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 loginSuccess;
}

/**
* 用户登录界面
* @return用户的用户名和密码
*/
private static Map<String, String> initUI() {
    Scanner s=new Scanner(System.in);

    System.out.println("用户名:");
    String loginName=s.nextLine();

    System.out.println("密码:");
    String loginPwd=s.nextLine();

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

}

/*
演示Statement的用途
*/

public static void main(String[] args) {
    //用户操作界面
    String s=initUI();

    //排序
    sort(s);
}

private static void sort(String s) {
    Connection conn=null;
    Statement stmt=null;
    ResultSet rs=null;
    try{
        //注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        //获取连接
        conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");
        //获取数据库操作对象
        stmt=conn.createStatement();
        //执行sql语句
        String sql="select empno,ename,sal from emp order by sal "+s+"";
        rs=stmt.executeQuery(sql);
        //处理查询结果集
        while(rs.next()){
            String empno=rs.getString(1);
            String ename=rs.getString(2);
            int sal=rs.getInt("sal");
            System.out.println(empno+'\t'+ename+'\t'+sal);
        }
        //释放资源
    }catch(Exception 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();
            }
        }
    }
}


private static String initUI() {
    Scanner scanner=new Scanner(System.in);
    System.out.println("desc or asc?");
    String s=scanner.nextLine();
    return s;
}

/*
JDBC使用PreparedStatement实现DML
*/

public static void main(String[] args) {
    Scanner s=new Scanner(System.in);

    System.out.println("loginName:");
    String loginName=s.nextLine();

    System.out.println("loginPwd:");
    String loginPwd=s.nextLine();

    Connection conn=null;
    PreparedStatement ps=null;

    try{
        //注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        //获取连接
        conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");
        //获取预处理数据库操作对象
        String sql="insert into t_user(loginName,loginPwd)values(?,?)";
        ps=conn.prepareStatement(sql);
        ps.setString(1,loginName);
        ps.setString(2,loginPwd);
        //执行sql语句
        int count=ps.executeUpdate();
        System.out.println(count==1?"操作成功":"操作失败");
        //处理查询结果集
        //释放资源
    }catch(ClassNotFoundException | 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();
            }
        }
    }
}

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中可以使用数据库连接池来连接数据库进行操作,然后通过拼接SQL语句的方式实现SQL生成器。下面是一个简单的示例: 1. 定义一个数据库连接池的类,用于获取数据库连接: ```java import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; public class DBUtil { private static DataSource ds = new ComboPooledDataSource(); public static Connection getConnection() throws SQLException { return ds.getConnection(); } } ``` 2. 定义一个SQL生成器类,用于生成DDL、DMLDQL语句: ```java import java.util.ArrayList; import java.util.List; public class SQLBuilder { private String tableName; private List<String> columns = new ArrayList<>(); private List<String> values = new ArrayList<>(); private List<String> conditions = new ArrayList<>(); public SQLBuilder(String tableName) { this.tableName = tableName; } public SQLBuilder addColumn(String column) { columns.add(column); return this; } public SQLBuilder addValue(String value) { values.add(value); return this; } public SQLBuilder addCondition(String condition) { conditions.add(condition); return this; } public String createDDL() { StringBuilder sb = new StringBuilder(); sb.append("CREATE TABLE ").append(tableName).append("("); for (String column : columns) { sb.append(column).append(","); } sb.deleteCharAt(sb.length() - 1); sb.append(")"); return sb.toString(); } public String createDML() { StringBuilder sb = new StringBuilder(); sb.append("INSERT INTO ").append(tableName).append(" ("); for (String column : columns) { sb.append(column).append(","); } sb.deleteCharAt(sb.length() - 1); sb.append(") VALUES ("); for (String value : values) { sb.append(value).append(","); } sb.deleteCharAt(sb.length() - 1); sb.append(")"); return sb.toString(); } public String createDQL() { StringBuilder sb = new StringBuilder(); sb.append("SELECT * FROM ").append(tableName); if (!conditions.isEmpty()) { sb.append(" WHERE "); for (String condition : conditions) { sb.append(condition).append(" AND "); } sb.delete(sb.length() - 5, sb.length()); } return sb.toString(); } } ``` 3. 使用SQL生成器生成SQL语句: ```java public class Main { public static void main(String[] args) { SQLBuilder builder = new SQLBuilder("user"); String ddl = builder.addColumn("id INT PRIMARY KEY AUTO_INCREMENT") .addColumn("name VARCHAR(50)") .addColumn("age INT") .createDDL(); System.out.println(ddl); String dml = builder.addValue("1") .addValue("'Tom'") .addValue("20") .createDML(); System.out.println(dml); String dql = builder.addCondition("age > 18") .createDQL(); System.out.println(dql); } } ``` 上述代码生成的SQL语句分别为: ```sql CREATE TABLE user(id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50),age INT) INSERT INTO user (id,name,age) VALUES (1,'Tom',20) SELECT * FROM user WHERE age > 18 ``` 当然,这只是一个简单的示例,实际应用中可能需要更复杂的SQL操作和更灵活的生成方式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值