超市管理系统-基础版(原生JDBC连接数据库+控制台输入输出)

391 阅读8分钟

因为程序要连接数据库所以要先在自己电脑上装好Mysql数据库,操作数据库可以用Idea中内置的,也可以下Navicat来操作。我们现在默认是已经安装好数据库,并且注册好了,知道自己电脑数据库的root和密码。

第一部分 什么是JDBC

• JDBC: (Java DataBase Connectivity), 就是使用Java语言操作关系型数据库的一套API 即接口。

是各个数据库厂商去实现这套接口,提供数据库驱动jar包

因为我们没有用maven或者springboot工程所以没有xml文件 不能直接引入依赖,所以我们要自己在项目中去导入Mysql的jar包,在mysql官网中下载MySQL :: Download Connector/J

当下载好了jar包,在项目结构中按照下面步骤导入jar包:

记得一定要勾选!

当外部库中有了,这步就成功了~


第二部分 在该项目中使用JDBC

我们先在mysql创建一个关于该项目的数据库 我这里用的命令行:

创建了一个名为test1的数据库;

在程序开始前:我们就需要先在Idea右侧面板中把数据库点开,选择Mysql

在这里输入账号密码和数据库的名称、测试、应用、确定。

数据库控制台就出来了,可以在里面输入SQL语句,当然在Idea中很方便,可以用图形化操作~

然后就可以创建项目中各种会用到的表,添加一些字段内容,以上就是在Idea中打开数据库的方法。如:


我们虽然打开了数据库但是程序还未连接上数据库,我们还需要在代码中配置一些数据库的信息。(关键点)

这段放在主函数上方,可以看到都是一些静态的变量 说明在程序中数据库信息是不变的。

并且这一段几乎都是在程序中写死的也叫硬代码(所以这也存在一些问题 后面会跟mybatis进行对比JDBC的缺点,就会发现为什么一般项目中不怎么用原始JDBC的原因)

    //本地电脑数据库信息
    static String driver = "com.mysql.cj.jdbc.Driver"; //配置mysql驱动
    static String url = "jdbc:mysql://localhost:3306/market?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC";
    static String username = "root";
    static String password = "2004ywj0619";
       static{
           try {
                Class.forName(driver);
            } catch (ClassNotFoundException e) {
        e.printStackTrace();
            }
        }

注意第二句的market是我电脑上的数据库名,你们要改成自己的数据库名;并且username和password也要改成自己的~


到这步已经配置好了数据库信息,但是还没有进行连接,我们在每次要使用数据库的时候才去进行连接,用完了要在结尾进行close(断开连接)比如我们来看一个登录login模块:

前面都是一些读入用户输入的代码,主要是从21行开始;

22行: 是用Connection的这个对象,通过传输我们之前定义好的url、username、password 进行对数据库的连接;

23行:获取操作数据库的对象 这里有个新来的Statement类和它相似的还有一个叫PrepareStatement,都可以用于执行修改和查询并获取结果集,他们之间有什么区别呢?简单来说①PrepareStatement比Statement更加安全,可以防止SQL注入攻击,因为数据库是允许用户输入操作的,那用户可能会试图去攻击、修改数据库,去公司删库跑路?这里的PreparedStatement 中它是用getset方法对属性进行了封装,只能通过getset方法去修改(就是我们课上在javabean中对每个属性进行getset方法一样)②PreparedStatement 可以预编译语句,处理性能更优!③Statement 的代码可读性较差

他们两个对象的返回值是一个结果集(ResultSet在26行),相当于把操作过后的数据放到一个集合中返回给数据库。

25行: 是编写该功能模块下会用到的SQL操作语句,比如在这个登录模块中 用户输入了用户名,我们就要把输入的用户名 拿去 和我们数据库中的用户名进行比对 看是否存在,这里的比对就会用到查询操作,所以我们上面的sql语句中就应该是select * 查询managers表中所有信息;

26行: 是stmt对象调用了他含有的一个方法executeQuery(sql),进行查询操作 参数是条sql语句,返回的是刚刚说的那个结果集ResultSet,这里是查询嘛。如果我们还想要执行插入操作,那么我再创一个prepareStatement对象(放入SQL的插入语句):

这里的?是占位符,对应的是表中的字段

当要插入时用pstmt去调用setString方法,这里这个索引1是对应的上面的第一个占位符,name是一个字符串对象

29行: 这里的循环条件是rs.next(),他是个游标并且在遍历,每调用一次 游标就会往后一位。在下面的30行中会用rs.去调用getString("name")方法,是去获取到遍历到当前这一行的name字段,用来和用户输入的进行equals比较。

其他就是一些输入的逻辑判断,在登录成功后,记得关闭刚刚创建的几个对象(6163行)。其他功能模块也大都类似

//登录: debug完成 √
private static void login() {

    try {
        Scanner sc = new Scanner(System.in);
        boolean flag1 = false; //用于表示登录的用户名是否注册过
        //(1)对象参数传递
        Manager m = new Manager();  //m为登录时 用户输入的一个临时对象
        System.out.println("请输入用户名:");
        String name = sc.nextLine();
        m.setUsername(name);

        System.out.println("请输入密码:");
        String userPassword = sc.nextLine();

        m.setPassword(userPassword);
        String randomNumber1 = checkNumber();
        System.out.println("验证码为:"+randomNumber1);


        //获取数据库连接
        Connection conn = DriverManager.getConnection(url, username, password);
        Statement stmt = conn.createStatement();//获取操作数据库的对象

        String sql = "select * from managers";
        ResultSet rs1 = stmt.executeQuery(sql);


        while (rs1.next()) {
            if (m.getUsername().equals(rs1.getString("name"))) {
                System.out.println("账号存在");
                flag1 = true;
                break;
            }
        }
        if (flag1 == false) {
            System.out.println("用户名未注册,请先注册!");
            rs1.close();
            stmt.close();
            conn.close();
            return;
        }
        //已注册:
        if(flag1 == true){
            //判断验证码是否正确
            int count = 3;//验证码输入错误次数
            loop2:while(true){
                System.out.println("请输入验证码:");
                String randomNumber2 = sc.nextLine();
                if(randomNumber1.equalsIgnoreCase(randomNumber2)){  //若验证码输入正确 继续判断用户名和密码是否正确
                    //根据用户去找密码 看是否与输入的密码相同
                    System.out.println("验证码正确");

                    String sql2 = "select * from managers";
                    ResultSet rs2 = stmt.executeQuery(sql2);

                    while(rs2.next()){
                        if(rs2.getString("name").equals(m.getUsername())){//如果找到了此用户名 根据当前的i 去找密码 进行比较
                            if(rs2.getString("password").equals(m.getPassword())){ //如果密码也相同 则登录成功
                                System.out.println("登录成功!");
                                rs1.close();
                                stmt.close();
                                conn.close();
                                //创建对象调用方法,启动超市管理系统!
                                GoodsTest st = new GoodsTest();
                                st.startGoodsTest();
                                break loop2;
                            }else{
                                System.out.println("密码错误!");
                                count--;
                                System.out.println("你还有"+count+"次机会!");
                                System.out.println("请再次输入密码");
                                String newPassword = sc.next();
                                m.setPassword(newPassword);
                                break;
                            }
                        }
                    }

                }else{
                    System.out.println("验证码有误,请重新输入");
                }
                if(count == 1) {
                    System.out.println("机会已用完!");
                    break;
                }
            }

        }

    } catch (Exception e) {
        e.printStackTrace();
    }
}

还有每次进行修改之后都记得去更新一下executeUpdate():


第三部分 JDBC的弊端

在上面详细的过了一遍login方法,我们还有forgetPassword、register等方法,那我们可以发现我们在每个单独的方法中 每次都要去连接数据库,结束后又断开数据库。频繁的连接断开,会导致 资源浪费、性能降低!所以JDBC其实有很多的弊端:

原生的JDBC的存在的弊端:

①代码量很大,注册驱动、获取连接 在项目开发中是比较容易变动的,特别是获取连接 在开发时会连接开发数据库,在测试时会连接测试数据库,在生产阶段会连接生产数据库,url、username、password都会变!

而这部分都是被写死在代码中(也称为硬代码),一旦变化,就要重新编译,打包之后才能运行。

②在封装解析结果时,要一个字段一个字段的解析,还要考虑字段类型该调用什么方法,字段一多就愈发的繁琐。

③在执行SQL语句前,先要获取连接,sql语句执行完毕之后,又要关闭连接;在项目中去频繁的获取连接会导致 资源浪费、性能降低


我们再来对比在Mybatis中是如何解决这些问题的!!

①首先关于硬编码,Mybatis是将数据库连接的四要素直接配置在application.properties中,可以直接在它里面操作就好~

②在解析结果时,Mybatis它会自动的将查询的结果封装到这个集合当中,查询返回的每一条记录都会封装为一个user对象,所有的user对象又会封装到一个List集合中,整个过程自动化进行

③关于频繁获取连接、释放连接 浪费资源问题,Mybatis中,在application.properties中每条配置语句前面都有spring.datasource前缀,springboot底层就会自动的采用数据库连接池技术来统一管理和分配这些连接

其实指的就是JDBC中的Connection对象那一行,有了连接池之后,每一次在执行sql语句的时候,我们只需要从连接池中获取一个连接去执行sql语句,完毕后,再将这个连接还给连接池,那这样就可以做到连接的复用,后面会再讲数据库连接池技术。

没有对比就没有伤害,Mybatis完胜!在我们使用springboot整合mybatis进行数据库操作时,我们主要关注两点:一个就是在application.properties中关于mybatis的相关配置;另一个方面就是mapper接口以及我们所定义的SQL语句~