初识JDBC-篇二

一、DAO设计规范

1.编写DAO组件

  1. 定义DAO接口

  2. 编写对应DAO实现类

为什么我们需要定义接口?

首先我们要知道接口就是只给出了函数声明,但是是没有函数体类。函数体在实现类中给出(必须实现)。我们可以根据客户提出的需求,定义接口,业务具体实现是通过实现类来完成。当客户提出新的需求,只需要编写该业务逻辑新的实现类。这就是面向接口编程,面向接口编程有以下几个好处

  • 业务逻辑更加清晰

  • 增强代码的扩展性,可维护性

  • 接口和实现相分离,适合团队协作开发

  • 降低耦合度。便于以后升级扩展

一个例子:

假设有一个数据库DAO,突然根据需要,程序要连接两个数据库,一个Oracle,一个MySQL。我们便可以利用多态的思想定义以下接口和实现类。

2.各种命名规范

1.包名规范

我们平时写java代码包名一般都是 域名倒写.模块名称.组件名称 这种格式,同样DAO也是符合这种格式。我们通常会建立以下四个包:

  • package com.ThinMoon.jdbc.domain 存储所有的domain
  • package com.thinmoon.jdbc.dao 存储所有的dao接口
  • package com.thinmoon.jdbc.dao.impl 存储所有的Dao接口实现类
  • package com.thinmoon.jdbc.dao.test 存储Dao组件的测试类
2.类名规范
起名规范 存储位置
domain类 见名之意即可 存储在domain包中。用于描述一个对象,是一个javaBean
dao接口 IDomainDao
接口-domain-dao
存储在dao包中,用于表示某一个对象的CRUD声明
dao实现类 DomainDAOImpl
domain-dao-impl
存储到dao.impl包中,用于表示DAO接口的实现类,要实现DAO接口

一个栗子:

Dao接口类:IStudentDao

public interface IStudentDao {
    //1.保存数据
    void save(Student stu);
    //2.修改数据
    void update(Student stu);
    //3.删除数据
    void delete(int id);
    //4.获取指定学生
    Student get(int id);
    //5.获取所有学生
    List<Student> getAll();

}

Dao实现类:StudentDaoImpl

public class StudentDaoImpl implements IStudentDao {

    @Override
    public void save(Student stu) {
        Connection conn = null;
        PreparedStatement ps = null;

        try {
            // 1.加载驱动
            // 2.连接数据库
            conn = JDBCUtil.getConn();
            // 3.创建语句
            int id = stu.getId();
            int age = stu.getAge();
            String name = stu.getName();
            String sql = "insert into student(id, age, name)values(?, ?, ?)";
            // 4.执行语句
            ps = conn.prepareStatement(sql);
            ps.setInt(1, id);
            ps.setInt(2, age);
            ps.setString(3, name);
            int row = ps.executeUpdate();
            // 5.释放
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 5.释放
            JDBCUtil.close(conn, ps, null);

        }

    }

    @Override
    public void update(Student stu) {
        Connection conn = null;
        PreparedStatement ps = null;

        try {
            // 1.加载驱动
            // 2.连接数据库
            conn = JDBCUtil.getConn();
            // 3.创建语句
            int id = stu.getId();
            int age = stu.getAge();
            String name = stu.getName();
            String sql = "update student set name=?, age=? where id=?;";
            ps = conn.prepareStatement(sql);
            ps.setInt(3, id);
            ps.setInt(2, age);
            ps.setString(1, name);
            int row = ps.executeUpdate();
            // 5.释放
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 5.释放
            JDBCUtil.close(conn, ps, null);

        }
    }

    @Override
    public void delete(int id) {
        Connection conn = null;
        PreparedStatement ps = null;

        try {
            // 1.加载驱动
            // 2.连接数据库
            conn = JDBCUtil.getConn();
            // 3.创建语句
            String sql = "delete from student where id = ?;";
            // 4.执行语句
            ps = conn.prepareStatement(sql);
            ps.setInt(1, id);
            int row = ps.executeUpdate();
            // 5.释放
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 5.释放
            JDBCUtil.close(conn, ps, null);

        }

    }

    @Override
    public Student get(int id) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet res = null;
        try {
            // 1.加载驱动
            // 2.连接数据库
            conn = JDBCUtil.getConn();
            // 3.创建语句
            String sql = "select * from student where id=?";
            // 4.执行语句
            ps = conn.prepareStatement(sql);
            ps.setInt(1, id);
            res = ps.executeQuery();
            if (res.next()) {
                Student stu = new Student();
                stu.setName(res.getString("name"));
                stu.setAge(res.getInt("age"));
                return stu;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtil.close(conn, ps, res);
        }

        return null;
    }

    @Override
    public List<Student> getAll() {
        Connection conn = null;
        Statement st = null;
        ResultSet res = null;
        try {
            // 1.加载驱动
            // 2.连接数据库
            conn = JDBCUtil.getConn();
            // 3.创建语句
            String sql = "select * from student;";
            // 4.执行语句
            st = conn.createStatement();
            res = st.executeQuery(sql);
            List<Student> list = new ArrayList<Student>();
            while (res.next()) {
                Student stu = new Student();
                stu.setId(res.getInt("id"));
                stu.setName(res.getString("name"));
                stu.setAge(res.getInt("age"));
                list.add(stu);
            }
            return list;

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 5.释放
            JDBCUtil.close(conn, st, res);
        }

        return null;
    }

}

domain类:Student

public class Student {
    Integer id;
    Integer age;
    String name;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

工具类:JDBCUtil

public class JDBCUtil {
    public static String url = "jdbc:MySQL://localhost:3306/jdbc_db?serverTimezone=UTC&characterEncoding=utf-8";
    public static String user = "root";
    public static String pwd = "123456";
    public static String driver = "com.mysql.cj.jdbc.Driver";
    static {
        // 1.加载驱动
        try {
            Class.forName(JDBCUtil.driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void close(Connection conn, Statement st, ResultSet res) {
        // 5.释放
        if (res != null) {
            try {
                res.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();
            }
        }

    }

    public static Connection getConn() {

        try {
            // 2.连接数据库
            return DriverManager.getConnection(JDBCUtil.url, JDBCUtil.user, JDBCUtil.pwd);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}

测试类:StudentDaoTest

public class StudentDaoTest {

    @Test
    public void save() {
        Student stu = new Student();
        stu.setId(1);
        stu.setName("李白");
        stu.setAge(16);

        IStudentDao dao = new StudentDaoImpl();
        dao.save(stu);
    }

    @Test
    public void delete() {
        IStudentDao dao = new StudentDaoImpl();
        dao.delete(1);
    }

    @Test
    public void update() {
        Student stu = new Student();
        stu.setId(1);
        stu.setAge(16);
        stu.setName("老王");

        IStudentDao dao = new StudentDaoImpl();
        dao.update(stu);
    }

    @Test
    public void get() {
        IStudentDao dao = new StudentDaoImpl();
        Student stu = dao.get(1);
        if (stu != null) {
            System.out.println(stu.getName());
            System.out.println(stu.getAge());
        }else {
            System.out.println("null");
        }
    }
    @Test
    public void getAll() {
        IStudentDao dao = new StudentDaoImpl();
        List<Student> list = dao.getAll();
        
    }

}

二、SQL注入问题

从上文中我们可以发现sql语句和第一篇文章中好像不一样了,并且代码中Statement变成了PreparedStatement,接下来我们就开始介绍什么是PreparedStatement,以及什么是sql注入问题和PreparedStatement是怎么防止sql注入的。

1.什么是PreparedStatement

PreparedStatement是Statement的一个子接口,又叫做预编译语句。见名之意,就是我们可以预先写好sql语句然后再后续代码中给我们在预先写好的sql语句中的占位符赋值,这样就简化了我们书写sql语句时需要拼接的麻烦步骤。

// 3.创建语句
int id = stu.getId();
int age = stu.getAge();
String name = stu.getName();
String sql = "insert into student(id, age, name)values(?, ?, ?)";
// 4.执行语句
ps = conn.prepareStatement(sql);
ps.setInt(1, id);
ps.setInt(2, age);
ps.setString(3, name);
int row = ps.executeUpdate();

类似上述代码般,我们可以给利用setXxx()给占位符赋值方便我们的书写。

2.什么是sql注入

在了解什么是sql注入前我们先看一个例子:

上面代码是一个简单的登录代码,通过和数据库对比用户名、密码返回是否登陆成功。可以看到我们上面还是使用之前sql语句需要自己进行拼接的情况,那么这种情况会出现什么问题呢?

在1中我们假设数据库中存在用户zs并且密码也是正确的,那么我们很自然的会登入成功这毋庸置疑。那么在2中呢?可以看到我们把2中的用户名写成" ' or 1=1 or ' "这种形式,那么当他与我们写的sql进行拼接时就会变成

select * from user where name = ' ' or 1=1 or ' ' and pwd = '12'

这样我们就得到一个返回值不为null的res了那么我们就可以成功进入系统了,这是一个极其危险的问题,我们把它称之为sql注入。

所以我们知道了什么是sql注入,SQL注入就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

3.PreparedStatement是怎么防止sql注入的?

我们将上面代码替换成PreparedStatement后再次用原来" ' or 1=1 or ' "这种恶意代码去尝试登入会有什么结果呢?结果当然是登陆失败啦。当我们使用PreparedStatement时再用原来的恶意代码去尝试登陆,我们得到的拼接字符串是像下面代码一般:

select * from user where name = '\' or 1=1 or \' ' and pwd = '12'

可以看到恶意代码上的'都被加上了转移字符,这就是PreparedStatement能够防止大部分sql注入的原理。PreparedStatement会对非法字符加上转义字符后在进行拼接!

三、调用存储过程

调用存储过程需要用到CallableStatement,CallableStatement也是Statement的一个子接口。

1.调用无输出参数存储过程

public static void main(String[] args) throws Exception {
        Connection conn = JDBCUtil.getConn();
        //1.调用存储过程
        CallableStatement cs = conn.prepareCall("{ call getStu(?)}");
        //2.设置参数
        cs.setString(1, "老王");
        //3.执行存储过程
        ResultSet res = cs.executeQuery();
        if(res.next()) {
            Student stu = new Student();
            stu.setId(res.getInt("id"));
            stu.setAge(res.getInt("age"));
            stu.setName(res.getString("name"));
            System.out.println(stu);
        }
    }

2.调用有输出参数存储过程

public static void main(String[] args) throws Exception {
        Connection conn = JDBCUtil.getConn();
        //1.调用存储过程
        CallableStatement cs = conn.prepareCall("{ call getName(?,?)}");
        //2.设置参数
        cs.setInt(1, 1);
        cs.registerOutParameter(2, Types.VARCHAR);
        //3.执行存储过程
        cs.execute();
        
        String name = cs.getString(2);
        System.out.println(name);
        
    }

猜你喜欢

转载自www.cnblogs.com/ThinMoon/p/12308396.html