Java——JDBC(Java DataBase Connectivity)数据库连接技术

目录

1、什么是JDBC?

2、JDBC的本质

3、JDBC入门案例

3.1、前期准备

3.2、mysql数据库准备

3.3、测试类代码

3.4、异常处理

4、抽取工具类

4.1、抽取重复代码

4.2、抽取jdbc.properties配置文件

5、封装实体类

6、 解决SQL注入问题

1、什么是JDBC?

通过Java语言操作数据库,操作表中的数据。

SUN公司为了简化、统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC。

2、JDBC的本质

是官方(sun公司)定义的一套操作所有关系型数据库的规则(接口)。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,运行时的代码其实是驱动jar包中的实现类。

在Java中要想访问数据库只能通过JDBC,JDBC是Java访问数据库的基础,其他数据库访问技术都是对JDBC的封装(Hibernate,MyBatis),JDBC是为了访问不同的数据库,提供了一种统一的访问方式,JDBC本身是Java连接数据库的一个标准,是进行数据库连接的抽象层。由Java编写的一组类和接口,接口的实现由各大数据库厂商来实现。

3、JDBC入门案例

3.1、前期准备

 为了能够测试JDBC,这里利用junit进行测试,首先创建一个JavaWeb项目,在项目src包下创建一个测试类UserTest,并导入mysql-connector的jar包,这就是JDBC的核心jar包,没有它是不能调用其中的类方法的,jar包放到WEB-INF下的lib包内。

这里提供了mysql5版本和mysql8版本的jar包,对应的就是mysql的版本,如果是mysql5系列版本的就用5.16的jar包,如果是mysql8系列的版本就用8.0.16版本jar包。

链接:https://pan.baidu.com/s/1loxaN41BXlfdePT_8DDBDw 
提取码:388i

添加到lib包下的jar包需要手动去导入一下右键jar包,点击ADD Library

3.2、mysql数据库准备

创建一个t_user表,自行添加数据

CREATE TABLE `t_user` (
  `id` int(11) NOT NULL,
  `username` varchar(20) DEFAULT NULL,
  `password` varchar(20) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

这里是我添加的数据 

3.3、测试类代码

前期工作准备就绪后,就开始连接数据库,编写代码了,下面就演示一下CRUD操作

public class UserTest {
    @Test
    public void select_User() throws ClassNotFoundException, SQLException {
        //加载mysql数据库JDBC驱动
        Class.forName("com.mysql.jdbc.Driver");
        //后面test是我t_user存放的数据库名
        String url="jdbc:mysql://localhost:3306/test";
        //数据库账户
        String username="xxx";
        //数据库密码
        String password="xxx";
        //获取connection对象
        Connection con = DriverManager.getConnection(url, username, password);
        //创建statement对象
        Statement statement = con.createStatement();
        //查询语句得到一个ResultSet类型的结果集
        ResultSet resultSet = statement.executeQuery("select * from t_user");
        //遍历结果集  输出控制台 next()方法如果有结果就返回true
        while (resultSet.next()){
            int id = resultSet.getInt("id");
            String username1 = resultSet.getString("username");
            String password1 = resultSet.getString("password");
            int age = resultSet.getInt("age");
            System.out.println(id+" "+username1+" "+password1+" "+age);
        }
        //后创建的先关闭
        resultSet.close();
        statement.close();
        con.close();

    }
    @Test
    public void add_User() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        String url="jdbc:mysql://localhost:3306/test";
        String username="xxx";
        String password="xxx";
        //获取connection对象
        Connection con = DriverManager.getConnection(url, username, password);
        //创建statement对象
        Statement statement = con.createStatement();
        //返回int 类型 代表的是修改的条数  executeUpdate可以为insert、delete、update操作
        int i = statement.executeUpdate("insert into t_user value(6,'王五','wda4822',26)");
        System.out.println(i);
        //后创建的先关闭
        statement.close();
        con.close();
    }
    @Test
    public void delete_User() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        String url="jdbc:mysql://localhost:3306/test";
        String username="xxx";
        String password="xxx";
        //获取connection对象
        Connection con = DriverManager.getConnection(url, username, password);
        //创建statement对象
        Statement statement = con.createStatement();
        int i = statement.executeUpdate("delete from t_user where id=6");
        System.out.println(i);
        //后创建的先关闭
        statement.close();
        con.close();
    }
    @Test
    public void update_User() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        String url="jdbc:mysql://localhost:3306/test";
        String username="xxx";
        String password="xxx";
        //获取connection对象
        Connection con = DriverManager.getConnection(url, username, password);
        //创建statement对象
        Statement statement = con.createStatement();
        int i = statement.executeUpdate("update t_user set username='宋浩',password='555sss4',age=24 where id=5 ");
        System.out.println(i);
        //后创建的先关闭
        statement.close();
        con.close();
    }

}

3.4、异常处理

在之前的代码中我们都是通过throws抛出异常,但是实际开发中需要我们去手动处理异常,下面我就以查询语句为例,演示如何处理异常

public class UserTestException {
    @Test
    public void select_User() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //因为try里面为局部变量 所以需要在外面定义初始化,为后面释放资源提供方便
        Connection con = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            String url = "jdbc:mysql://localhost:3306/test";
            String username = "root";
            String password = "xxxx";
            //获取connection对象
            con = DriverManager.getConnection(url, username, password);
            //创建statement对象
            statement = con.createStatement();
            //查询语句得到一个ResultSet类型的结果集
            resultSet = statement.executeQuery("select * from t_user");
            //遍历结果集  输出控制台 next()方法如果有结果就返回true
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String username1 = resultSet.getString("username");
                String password1 = resultSet.getString("password");
                int age = resultSet.getInt("age");
                System.out.println(id + " " + username1 + " " + password1 + " " + age);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //后创建的先关闭
            try {
                if (resultSet != null) {
                    //先判断是否为null 不为null就释放掉
                    resultSet.close();
                    //手动把资源赋值为null,提示gc垃圾回收机制释放资源
                    resultSet = null;
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (statement != null) {
                    statement.close();
                    statement = null;
                }

            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (con != null) {
                    con.close();
                    con = null;
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }
}

4、抽取工具类

4.1、抽取重复代码

以上代码虽然能够实现功能,但是代码的耦合度太高,比如加载驱动和定义url路径、用户、密码,以及最后的清除资源等,这都是重复工作,为了降低耦合度,我们需要把这些重复代码抽取出来到一个工具类中。

首先创建一个utils包,里面存放的就是工具类

public class JDBCUtils {
    //利用静态代码块去加载驱动,随着类的加载而加载且加载一次
    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    //获取连接对象
    public static Connection getConnection(){
        String url="jdbc:mysql://localhost:3306/test";
        String user="root";
        String password="xxxx";
        Connection con = null;
        try {
            con = DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return  con;
    }
    //释放查询语句资源
    public static void close(ResultSet rs,Statement stmt,Connection con){
        try {
            if (rs != null) {
                rs.close();
                rs = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (stmt != null) {
                stmt.close();
                stmt = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (con != null) {
                con.close();
                con = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    //释放insert、delete、update语句的资源
    public static void close(Statement stmt,Connection con){
        try {
            if (stmt != null) {
                stmt.close();
                stmt = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (con != null) {
                con.close();
                con = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

我们再去测试功能时,代码就会得到简化,下面就是使用工具类以后 

 @Test
    public void select_user(){
        Connection con = JDBCUtils.getConnection();
        Statement stmt = null;
        ResultSet rs = null;
        try {
            stmt = con.createStatement();
            rs = stmt.executeQuery("select * from t_user");
            while (rs.next()) {
                int id = rs.getInt("id");
                String username = rs.getString("username");
                String password = rs.getString("password");
                int age = rs.getInt("age");
                System.out.println(id + " " + username + " " + password + " " + age);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(rs,stmt,con);
        }

    }
  

4.2、抽取jdbc.properties配置文件

目前还是有一点尚且优化的地方,就是我们填写jdbc的信息,以后肯定是会改变这些信息的,为了方便维护和查看,我们需要把这些信息抽取出来到一个配置文件进行存放,然后通过获取这个配置文件去加载内容。

在src目录下创建一个文件名为jdbc.properties

jdbc.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.user=root
jdbc.password=xxxx

在工具类中进行优化

public class JDBCUtils2 {
    public JDBCUtils2() {
    }

    private static String className;
    private static String url;
    private static String username;
    private static String password;
    private static Connection con = null;

    static {
        //初始化properties对象
        Properties pro = null;
        InputStream is=null;
        try {
            //通过反射获取配置文件io对象
            is = JDBCUtils2.class.getClassLoader().getResourceAsStream("jdbc.properties");
            pro = new Properties();
            //调用load方法读取jdbc.properties配置文件内容
            pro.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //分别调用getProperty方法获取对应的value值
        className = pro.getProperty("jdbc.className");
        url = pro.getProperty("jdbc.url");
        username = pro.getProperty("jdbc.user");
        password = pro.getProperty("jdbc.password");

        //加载驱动
        try {
            Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //创建连接
        try {
            con = DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() {
        return con;
    }

    //释放查询语句资源
    public static void close(ResultSet rs, Statement stmt, Connection con) {
        try {
            if (rs != null) {
                rs.close();
                rs = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (stmt != null) {
                stmt.close();
                stmt = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (con != null) {
                con.close();
                con = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //释放insert、delete、update语句的资源
    public static void close(Statement stmt, Connection con) {
        try {
            if (stmt != null) {
                stmt.close();
                stmt = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (con != null) {
                con.close();
                con = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

测试类代码 

 @Test
    public void delete_user(){
        Connection con = JDBCUtils2.getConnection();
        Statement stmt = null;
        try {
            stmt = con.createStatement();
            int i = stmt.executeUpdate("delete from t_user where id=5");
            System.out.println(i);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils2.close(stmt,con);
        }

    }

5、封装实体类

首先创建一个bean包,用来存放实体类

public class User {
    private String username;
    private String password;
    private int age;

    public User() {
    }

    public User(String username, String password, int age) {
        this.username = username;
        this.password = password;
        this.age = age;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                '}';
    }
}

测试类 

public class UserTest3 {
    @Test
    public void queryUser(){
        Connection conn = JDBCUtils2.getConnection();
        User user=null;
        Statement stmt=null;
        ResultSet rs=null;
        List<User> list=new ArrayList<>();
        try {
            stmt = conn.createStatement();
            rs = stmt.executeQuery("select * from t_user");
            while(rs.next()){
                user=new User();
                user.setUsername(rs.getString("username"));
                user.setPassword(rs.getString("password"));
                user.setAge(rs.getInt("age"));
                list.add(user);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils2.close(rs,stmt,conn);
        }
        //遍历list集合
        list.forEach(System.out::println);

    }
}

 

6、 解决SQL注入问题

先来看这一问题

public class UserTest3 {
    @Test
    public void queryUser(){
        Connection conn = JDBCUtils2.getConnection();
        User user=null;
        Statement stmt=null;
        ResultSet rs=null;
        List<User> list=new ArrayList<>();
        try {
            stmt = conn.createStatement();
            rs = stmt.executeQuery("select * from t_user where username=''or'1'='1'");
            while(rs.next()){
                user=new User();
                user.setUsername(rs.getString("username"));
                user.setPassword(rs.getString("password"));
                user.setAge(rs.getInt("age"));
                list.add(user);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils2.close(rs,stmt,conn);
        }
        //遍历list集合
        list.forEach(System.out::println);

    }
}

我在查询语句后面加了一个条件为username=''or'1'='1',我们现在运行程序

发现所有信息被查询出来了,这是怎么一回事呢,这就是SQL注入问题,是一个严重的安全隐患,那我们就要开始解决这个BUG,这也是字符串拼接带来的坏处,为了解决这个BUG,就要想办法不用字符串拼接,下面就讲述一下preparedStatment方法,其实现是通过占位符来完成的。

改造代码如下

public class UserTest3 {
    @Test
    public void queryUser() {
        Connection conn = JDBCUtils2.getConnection();
        User user = null;
        // Statement stmt=null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        List<User> list = new ArrayList<>();
        try {
            // stmt = conn.createStatement();
            // rs = stmt.executeQuery("select * from t_user where username=''or'1'='1'");
            //创建pstmt对象并赋值sql语句
            pstmt = conn.prepareStatement("select * from t_user where username= ?");
            //为占位符进行赋值,左边是占位符索引从1开始,右边为字符串内容
            pstmt.setString(1,"''or'1'='1'");
            rs = pstmt.executeQuery();
            while (rs.next()) {
                user = new User();
                user.setUsername(rs.getString("username"));
                user.setPassword(rs.getString("password"));
                user.setAge(rs.getInt("age"));
                list.add(user);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils2.close(rs, pstmt, conn);
        }
        //遍历list集合
        list.forEach(System.out::println);

    }
}

可见,这次再输入就查询不到了。 

猜你喜欢

转载自blog.csdn.net/select_myname/article/details/126650631