zoukankan      html  css  js  c++  java
  • JDBC-扩展

    一:用户登录实现:

      1.需求:模拟用户登录功能的实现

      2.业务描述:程序运行的时候,提供一个输入接口,可以让用户输入用户名和密码,并提交信息,JAVA连接数据库核实信息,合法,登录成功,不合法,登陆失败。

      3.数据准备:需要一个建模工具:PowerDesigner

     

      4.懒得写那么多,直接上代码:

    package cc.bb.aa;
    ​
    ​
    import java.sql.*;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Scanner;
    ​
    ​
    ​
    ​
    public class Ui_user {
        public static void main(String[] args) {
            //1.初始化界面:
            Map<String,String> userLogininfo=initUI();//需要返回一个给用户输入的对象,用来验证用户名和密码
            //2.验证用户名和密码
            boolean loginSuccess =Login(userLogininfo);
            //3.输出结果:
            System.out.println(loginSuccess?"登录成功":"登录失败");
        }
    ​
        
        /**
         * 用户登录
         * @param userLogininfo用户信息
         * @return false表示失败,true表示成功
         * */
        private static boolean Login(Map<String, String> userLogininfo) {
            //JDBC代码
            //打一个boolean的一个标记
            boolean loginSuccess=false;
            Connection conn = null;
            Statement stmt = null;
            ResultSet rs=null;
            
            try {
                conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","");
                //statement专门执行SQL语句的
                stmt=conn.createStatement();//create statement对象
                //专门执行DML语句
                //注意:这里补充一个知识点:双引号里面添加两个加号意思是变量所代表的值的字符串:格式为:"+loginInfo.get("loginName")+";
                //返回值是“影响数据库中的记录条数”
                String sql="select * from user where name='"+userLogininfo.get("loginName")+"' and password='"+userLogininfo.get("loginPwd")+"'";
                rs=stmt.executeQuery(sql);
                //处理结果集:
                if(rs.next()) {
                    //登录成功
                    loginSuccess=true;
                }else {
                    //登陆失败
                    loginSuccess =false;
                }
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally {//这里关闭数据,释放资源
                try{
                    if(stmt!=null){
                        stmt.close();
                    }
                }catch(SQLException e){
                    e.printStackTrace();
                }
                try{
                    if(conn!=null){
                        conn.close();
                    }
                }catch(SQLException e){
                    e.printStackTrace();
                }
            }
            return loginSuccess;
        }
        
        
        /**
         * 初始化界面
         * @return 用户输入的用户名和密码等登录信息
         * */private static Map<String, String> initUI() {
            // TODO Auto-generated method stub
            Scanner scanner=new Scanner(System.in);
            
            System.out.println("用户名:");
            String loginName=scanner.nextLine();
            
            System.out.println("密码:");
            String loginPwd=scanner.nextLine();
            
            Map<String,String> userLoginInfoMap=new HashMap<>();
            userLoginInfoMap.put("loginName", loginName);
            userLoginInfoMap.put("loginPwd", loginPwd);
            
        return userLoginInfoMap;
        }
    }
    ​
    fdsa
    
    fdsa' or '1'='1

     

     

    二:SQL注入:

    1.导致注入的根本原因:

    用户输入的信息中含有sql语句的关键字,并且这些关键字参与sql语句的编译过程,导致sql语句的原意被扭曲,进而达到sql注入

     

    2.解决SQL注入:

    /**
    *只要用户提供的信息中不参与SQL语句的编译过程,问题就解决了
    *及时用户提供的信息中含有SQL语句的关键字,但是没有参加编译,不起作用
    *想要用户信息不参与SQL语句的编译,那么必须使用java.sql.PreparedStatement
    *PreparedStatement接口继承了java.sql.Statement
    *PreparedStatement是属于预编译的数据库操作对象
    *PreparedStatement的原理是:与预先对SQL语句的框架进行编译,然后再给SQL语句传“值”
    *
    *解决SQL注入的关键是什么?
    *   用户提供的信息中含有sql语句的关键字,,但是这些关键字并没有参与编译,不起作用
    */

    注意:跟之前的使用statement相比较,还是有很大的区别的

    //提前打标记:
        boolean loginSuccess=false;
    //单独定义变量
        String loginName=userLogininfo.get("loginName");
        String loginPwd=userLogininfo.get("loginPwd");
    ​
    //提前定义:
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
    ​
    //1.注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
    //2.获取连接
        conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","");
    //3.获取与预编译的数据库操作对象
    //SQL语句的框架,其中一个?,表示以一个占位符,一个?将来接受一个“值”,注意:占位符不能使用单引号括起来
        String sql="select * from user where name=? and password=?";
    //程序执行到此,会发送一个sql语句框子给DBMS,然后DBMS进行sql语句的预先编译
        ps=conn.prepareStatement(sql);
    //给占位符?传值(第一个问好下标是1,第二个问好下标是2,JBDBC中所有的下标都是从1开始)
        ps.setString(1,loginName);
        ps.setString(2,loginPwd);
    //4.执行sql
        rs=ps.executeQuery();
    //5.处理结果集
        if(rs.next()){
        //登录成功
            loginSuccess=true;
    }else{
        //登录失败
        loginSuccess=false;
    }
        return loginSuccess;

    注意:这里没有使用try,catch块,而且资源也没有finally释放,记得之后看代码的时候,对应前面的代码来看

     

     

     

    三:使用preparedStatement进行增删查改:

    //1.注册驱动
    Class.forName("com.mysql.cj.jdbc.Driver");
    //2.获取连接
    conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","");
    //3.获取预编译的操作对象
    String sql="insert into dept(deptno,dname,loc) values(?,?,?)";//这里写增删查改语句就好了,不会下去自己看看把
    ps=conn.prepareStatement(sql);
    ps.setInt(1,60);
    ps.setString(2,"销售部");
    ps.setString(3,"上海");
    ​
    //4.执行SQL
    int count=ps.executeUpdate();
    System.out.println(count);

     

     

    四:JDBC事务提交:

    1.JDBC的事务时自动提交:只要执行任意一条DML语句,则自动提交一次,但是实际业务当中,通常都是N条DML语句共同联合才能完成

     

    五:乐观锁和悲观锁:

    乐观锁:事务不需要排队,支持并发

    悲观锁:书屋排队执行,数据锁住了,不允许并发

    一、悲观锁

    顾名思义,悲观锁就是考虑事情发生的最坏情况。默认认为一定会有其它线程抢着修改当前线程正在使用的数据。分为,读锁和写锁。

    • 读锁,又称共享锁,可以被其它线程所共享,所有线程都可以添加该锁。当没有其它线程添加读锁时,本线程可以修改数据,否则将无法修改数据。

    • 写锁,也成排它锁,不能被共享。只要有线程添加该锁时,直到事务提交之前,其它线程都无法添加该锁。

    如何实现(数据库提供实现方法):

    1. 读锁

    select * from table lock in share mode

    2. 写锁

    select * from table for update

    二、乐观锁

    乐观锁,认为没有其它线程和本线程同时修改数据。一般使用版本号来控制(类似于SVN版本控制器),在提交事务前,比较自身持有的版本号和数据库中存在的版本号,只有自身持有的版本号大于数据库中的版本号时才能修改数据,否则无法修改数据。

    例如:

    在hibernate中,提供了乐观锁的解决方案

    首先,在实体类中,添加一个字段代表版本号,并添加get/set方法。

    img

    然后在实体的配置文件中添加version属性

    img

    结果:在测试代码中加入断点,当程序运行完该断点后,立即修改数据库t_customer表中version属性,使其加1,放行代码,结果将出现SatleObjectStateException异常。

    img

    img

     

  • 相关阅读:
    pydensecrf的inference.py代码的学习
    pydensecrf的使用
    Example of DenseCRF with non-RGB data
    scipy.stats.multivariate_normal的使用
    np.mgrid的用法
    Linux后台命令的使用说明
    实现能够在训练过程中手动更改学习率
    pytorch Debug —交互式调试工具Pdb (ipdb是增强版的pdb)-1-在pytorch中使用
    pytorch实现性别检测
    svn冲突意思
  • 原文地址:https://www.cnblogs.com/instead-everyone/p/13620079.html
Copyright © 2011-2022 走看看