• JDBC、单元测试、DAO模式


    JDBC简介

    1、什么是JDBC?

      JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API(工具)。JDBC是Java访问数据库的标准规范。

      规范:在java中的直接体现是接口

      作用:为不同关系型数据库提供统一的访问,由一组用java语言编写的接口和工具类组成,由各大数据库厂商实现对应接口

    2、连接数据库时要先加载驱动

      什么是驱动?

      两个设备要进行通信时,需要满足一定通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信。

      Java和数据库要想进行链接,必须提前规定一些数据格式,格式由数据库厂商实现。

      mysql连接工具下载地址:https://dev.mysql.com/downloads/connector/j/

    3、JDBC是接口,而JDBC驱动才是接口的实现,没有驱动无法完成数据库连接!每个数据库厂商都有自己的驱动,用来连接自己公司的数据库。

    JDBC连接详解

    1.通过JDBC连接数据库需要五步

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.Statement;
    
    public class Demo01 {
    
        public static void main(String[] args) throws Exception {
            //1、加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2、创建连接
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db_test?serverTimezone=GMT%2B8", "root", "root");
            //3、编译sql语句 编译器
            Statement statement = conn.createStatement();
            String sql = "select * from test";
            //4、发送sql 并接受结果
            ResultSet eq = statement.executeQuery(sql);
            //根据列名获取数据 迭代器
            while(eq.next()) {
                int sid = eq.getInt(1);
                String name = eq.getString(2);
                int chinese = eq.getInt("chinese");
                int math = eq.getInt("math");
                System.out.println(sid+"	"+name+"	"+chinese+"	"+math);
            }
            //5、关闭资源 
            eq.close();
            statement.close();
            conn.close();
        }
    
    }

    2、详解每一步

      1、Class.forName("com.mysql.cj.jdbc.Driver"); //这里写下载的连接工具包中的驱动路径

        通过反射,建立驱动的对象

      2、Connection conn = DriverManager.getConnection(url,username,password);  //获取连接

      url="jdbc:mysql://localhost:3306/db_test?serverTimezone=GMT%2B8" 

      协议,有严格书写规范   主协议名:子协议名://主机名:端口号/数据库名  在连接工具到了6.0之后需要设置时区

        serverTimezone是时区,如果设定serverTimezone=UTC,会比中国时间早8个小时,设定中国则为GMT%2B8

      username = "root", password =  "root"  数据库的用户名和密码

      3、获取发送sql语句的对象

      Statement statement = conn.createStatement();

      4、发送sql,执行并接受结果

      executeQuery(String sql),只能执行select语句,如果执行insert into,update,delete from 都会报错,会把SQL语句传递给mysql数据库去执行

      executeUpdate(String sql),执行更新的SQL语句。只能执行insert into,update,delete from,如果执行select语句会报错,会把SQL语句传递给mysql数据库去执行

      execute(String sql)  执行任意语句,执行select 返回true,执行insert into,update,delete from  返回false

      5、释放资源

      eq.close();statement.close();conn.close();

    3、JDBC的增删改查

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.util.Scanner;
    
    public class Demo2 {
    
        public static void main(String[] args) throws Exception{
            Connection conn=null;
            Scanner sc=new Scanner(System.in);
            PreparedStatement ps =null;
            ResultSet eq =null;
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql:///db_701?serverTimezone=GMT%2B8", "root", "ccc");
            login(conn,sc,eq,ps);
            
        }
        public static void login(Connection conn,Scanner sc,ResultSet eq,PreparedStatement ps) throws Exception {
            ps = conn.prepareStatement("select username,pwd from users where id='1'");
            eq = ps.executeQuery();
            int flag=1;
            if(eq.next()) {
                do{
                    System.out.println("请输入用户名:");
                    String s1 = sc.nextLine();
                    String s2 = eq.getString(1);
                    System.out.println(s2);
                    if(s1.equals(s2)) {
                        System.out.println("请输入密码:");
                        String pwd1 = sc.nextLine();
                        String pwd2 = eq.getString(2);
                        if(pwd1.equals(pwd2)) {
                            System.out.println("登录成功,欢迎使用");
                            flag=0;
                        }else {
                            System.out.println("用户名密码错误 ,请重新输入");
                            continue;
                        }
                    }else {
                        System.out.println("用户名不存在,请重新输入");
                        continue;
                    }
                }while(flag==1);
                test(conn,sc,eq,ps);
            }
        }
        public static void test(Connection conn,Scanner sc,ResultSet eq,PreparedStatement ps) throws Exception{
            System.out.println("请选择功能:1、添加  2、删除  3、修改  4、查询  0、退出");
            int num =Integer.parseInt(sc.nextLine());
            switch(num){
                case 1:
                    add(conn,sc,eq,ps);
                    break;
                case 2:
                    delete(conn,sc,eq,ps);
                    break;
                case 3:
                    alter(conn,sc,eq,ps);
                    break;
                case 4:
                    select(conn,sc,eq,ps);
                    break;
                case 5 :
                    System.out.println("谢谢您的使用,再见");
                    after(conn,sc,eq,ps);
                    break;
            }
        }
        public static void add(Connection conn,Scanner sc,ResultSet eq,PreparedStatement ps) throws Exception {
            ps = conn.prepareStatement("insert into users values(null,?,?)");
            System.out.println("请输入用户名:");
            ps.setString(1, sc.nextLine());
            int flag=1;
            while(flag==1) {
                System.out.println("请输入密码 :");
                String pwd1 = sc.nextLine();
                System.out.println("确认密码:");
                String pwd2 = sc.nextLine();
                if(pwd1.equals(pwd2)) {
                    ps.setString(2, pwd2);
                    flag=0;
                }else {
                    System.out.println("两次密码输入不一致,请重新输入密码 ");
                    continue;
                }
            }
            int count=ps.executeUpdate();
            if(count>0) {
                System.out.println("添加成功");
            }else {
                System.out.println("添加失败");
            }
            test2(conn,sc,eq,ps);    
        }
        public static void delete(Connection conn,Scanner sc,ResultSet eq,PreparedStatement ps) throws Exception{
            ps = conn.prepareStatement("delete from users where username=? and pwd=?");
            int flag=1;
            while(flag==1) {
                System.out.println("请输入想要删除的用户名:");
                String s = sc.nextLine();
                ps.setString(1, s);
                System.out.println("请输入此用户的密码 :");
                String pwd1 = sc.nextLine();
                ps.setString(2, pwd1);
                int count=ps.executeUpdate();
                if(count>0) {
                    System.out.println("删除成功");
                    flag=0;
                }else {
                    System.out.println("用户名密码错误,删除失败  1.继续删除  0.返回 ");
                    String s1 = sc.nextLine();
                    if(s1.equals("1")) {
                        continue;
                    }else {
                        flag=0;
                        System.out.println("正在返回上一级");
                    }
                }
            }
            test2(conn,sc,eq,ps);    
        }
        public static void alter(Connection conn,Scanner sc,ResultSet eq,PreparedStatement ps) throws Exception {
            ps = conn.prepareStatement("update users set pwd=? where username=? and pwd=?");
            int flag=1;
            int flag1=1;
            while(flag==1) {
                System.out.println("请输入想要修改密码的用户名:");
                String s1 = sc.nextLine();
                ps.setString(2, s1);
                System.out.println("请输入原密码 ");
                String pwd = sc.nextLine();
                ps.setString(3, pwd);
                
                while(flag1==1) {
                    System.out.println("请输入修改的密码 :");
                    String pwd1 = sc.nextLine();
                    System.out.println("确认密码:");
                    String pwd2 = sc.nextLine();
                    if(pwd1.equals(pwd2)) {
                        ps.setString(1, pwd2);
                        flag1=0;
                    }else {
                        System.out.println("两次密码输入不一致,请重新输入 ");
                        continue;
                    }
                }
                int count=ps.executeUpdate();
                if(count>0) {
                    System.out.println("修改成功");
                    flag=0;
                }else {
                    System.out.println("修改失败");
                    System.out.println("用户名密码错误,修改失败  1.继续修改  0.返回 ");
                    String s3 = sc.nextLine();
                    if(s3.equals("1")) {
                        continue;
                    }else {
                        flag=0;
                        System.out.println("正在返回上一级");
                    }
                    
                }
            }
            test2(conn,sc,eq,ps);
        }
        public static void select(Connection conn,Scanner sc,ResultSet eq,PreparedStatement ps) throws Exception {
            System.out.println("1.查询全部  2.指定用户名查询");
            String s = sc.nextLine();
            if(s.equals("2")) {
                ps = conn.prepareStatement("select * from users where username=?");
                System.out.println("请输入要查询的用户名:");
                String s1 = sc.nextLine();
                ps.setString(1, s1);
                eq = ps.executeQuery();
            }else if(s.equals("1")) {
                ps = conn.prepareStatement("select * from users");
                eq = ps.executeQuery();    
            }
            if(eq.next()) {
                do{
                    String username = eq.getString(2);
                    String pwd = eq.getString(3);
                    System.out.println(username+"	"+pwd);
                }while(eq.next()) ;
            }else {
                System.out.println("查询失败");
            }
            test2(conn,sc,eq,ps);
        }
        public static void test2(Connection conn,Scanner sc,ResultSet eq,PreparedStatement ps) throws Exception{
            System.out.println("1.继续  0.退出");
            String s3 = sc.nextLine();
            if(s3.equals("1")) {
                test(conn,sc,eq,ps);
            }else {
                System.out.println("谢谢您的使用,再见");
                after(conn,sc,eq,ps);
            }
        }
        public static void after(Connection conn,Scanner sc,ResultSet eq,PreparedStatement ps) throws Exception{
            if(conn!=null) {
                conn.close();
            }
            if(ps!=null) {
                ps.close();
            }
            if(sc!=null) {
                sc.close();
            }
            if(eq !=null) {
                eq.close();
            }
        }
    }
    JDBC增删改查练习之用户管理系统mini

    4、工具类的抽取

      将重复的加载驱动和获取连接和关闭资源封装到工具类,方便使用

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class JDBCUtils {
        public static final String driver = "com.mysql.cj.jdbc.Driver";
        public static final String url = "jdbc:mysql://localhost:3306/db_test?serverTimezone=GMT%2B8";
        public static final String user = "root";
        public static final String password="root";
        static {
            try {
                Class.forName(driver);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            
        }
        public static Connection getConn() {
            try {
                return DriverManager.getConnection(url,user,password);
            } catch (SQLException e) {
                e.printStackTrace();
                return null;
            }
        }
        public static void closeAll(ResultSet rs,Statement st,Connection conn) {
            if(rs!=null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(st!=null) {
                try {
                    st.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn!=null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    工具类

    SQL注入问题

    1、在上面的JDBC使用中,存在着一个安全问题,那就是SQL的注入问题

      这个问题主要发生在编译对象身上,因为statement对象每次都是将字符串拼接完毕之后才发送给数据库执行,因此就产生了安全问题。

      eg:用户登录  假设用户名密码必须是root 和root才能登录获得查看结果

      sql语句为  String sql = "select * from users where username='"+username+"' and password='"+password+"'";

      username  和 password需要用户输入

      注入问题如下:

      username = a' or 'a'='a;

      password = a' or 'a'='a;

      此时sql语句变为 select * from users where username = 'a' or 'a'='a' and password='a' or 'a'='a'

      虽然用户名密码均不正确,但依然可以登录成功进行查看,这就是SQL注入问题

    2、那么该如何解决呢?

      使用预编译对象 preparedStatement

      PreparedStatement与Statement的区别:

        前者对sql语句进行了预编译

        PreparedStatement将语句先送回数据库

        使语句的逻辑已经确定为select * from users where username=? and password=?

        此时用户如果输入同样的内容,却无法改变原有的逻辑,会产生语法错误,所以避免了注入问题

      且预编译对象在使用同一条语句传不同内容时,也只需编译一次,大大提高了效率

    3、PreparedStatement的预编译是数据库进行的,编译后的函数key是缓存在PreparedStatement中的,编译后的函数是缓存在数据库服务器中的。预编译前有检查sql语句语法是否正确的操作。只有数据库服务器支持预编译功能时,JDBC驱动才能够使用数据库的预编译功能,否则会报错。

      jdbc:mysql://localhost:3306/db?useServerPrepStmts=true  可以设置数据库开启预编译

    4、使用不同的PreparedStatement对象来执行相同的SQL语句时,还是会出现编译两次的现象,这是因为驱动没有缓存编译后的函数key,导致二次编译。如果希望缓存编译后函数的key,那么就要设置cachePrepStmts参数为true

      jdbc:mysql://localhost:3306/db?useServerPrepStmts=true&cachePrepStmts=true

    5、PreparedStatement的预编译还有注意的问题,在数据库端存储的函数和在PreparedStatement中存储的key值,都是建立在数据库连接的基础上的,如果当前数据库连接断开了,数据库端的函数会清空,建立在连接上的PreparedStatement里面的函数key也会被清空,各个连接之间的预编译都是互相独立的。

    6、PreparedStatement的使用

    setInt(int index,int value)

    为?占位符,赋予int值

    setString(int index,String value)

    为?占位符,赋予String值

    setObject(int index,Object value)

    executeQuery()

    执行查询的SQL语句。

    只能执行select语句,

    如果执行insert into,update,delete from 都会报错

    会把SQL语句传递给mysql数据库去执行

    返回结果:ResultSet对象---一张二维表格

    executeUpdate()

    执行更新的SQL语句。

    只能执行insert into,update,delete from

    如果执行select语句会报错

    会把SQL语句传递给mysql数据库去执行

    返回结果:int   SQL语句执行后更新了几行数据

    上面的代码练习中采用的就是PreparedStatement。

    单元测试

    1、导包 右击项目-->prooerties-->java build path -->libraries-->add library-->JUint-->next finish

    2、给想要测试的方法加上注解(在上方加上 @Test)

    3、可以在其他方法上加@Before 这个方法会在测试方法之前执行  用来加载资源

       @After 这个方法会在测试方法之后执行   用来关闭资源

    DAO模式

    Database  Access  Object

    把对数据库进行的JDBC操作(增、删、改、查) 都放在一个类中,用不同的方法分别来完成增、删、改、查。

    一张数据库表做一个实体类,数据库的列是类的属性,数据库的一行数据是类的一个对象

  • 相关阅读:
    erlang转化中文为url
    erlang中检查内存泄露
    git找回当前目录下误删的所有文件
    使用rebar编译lager,deps列表,lager要放到第一位。
    Visualizing Concurrency in Go--转
    erlang init:stop()不起效
    linux设置时间
    erlang驱动使用mysql-otp
    mysql-otp 驱动中设置utf8mb4
    erlang node time ticket
  • 原文地址:https://www.cnblogs.com/xfdhh/p/11372071.html
Copyright © 2020-2023  润新知