jdbc层层推进之体验

1.什么是jdbc

我们在web开发中,不可避免的地要使用数据库来存储和管理数据。为了在java语言中提供数据库访问的支持,Sun公司于1996年提供了一套访问数据的标准Java类库,即JDBC。JDBC的全称是Java数据库连接(Java Database connect),它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系数据库,并使用SQL语句来完成对数据库中数据的查询、更新和删除等操作。

2.jdbc常用API

class java.sql.DriverManager 	
	Java JDBC 驱动管理类,主要负责驱动注册和数据库连接对象获取
	常用方法:
		public static void registerDriver(java.sql.Driver driver);	
			注册符合 JDBC 规范要求的 Driver 对象,增强当前 Java 程序,可以操作数据库
		public static java.sql.Connection getConnection(String jdbcUrl, String username, 
				String password)
			根据提供的 JdbcUrl JDBC 数据库连接规范 URL,对应的数据库用户名和密码获取到数据库 
			java.sql.Connection 连接对象

interface java.sql.Connection 
	Java JDBC 数据库连接对象接口,主要用于获取数据库连接相关的信息,获取数据库 SQL 搬运工对象
	常用方法:
		public java.sql.Statement createStatement();
			通过该数据库连接对象,获取对应当前数据库的 SQL 语句搬运工对象
		public java.sql.PreparedStatement prepareStatement(String sql);
			通过该数据库连接对象,根据参数 SQL 语句,获取对应当前数据库的 SQL 语句预处理搬运工对象。

interface java.sql.Statment
	Java JDBC 规范 数据库搬运工对象,在项目中主要处理的 SQL 语句可以分为两大部分,一部分为更新(insert, 
	update, delete),一部分为查询(select)
	常用方法:
		public int executeUpdate(String sql);
			执行 SQL 语句更新操作,主要可以执行的 SQL 语句类型为 insert,update,delete 操作,返回值是 
			int 类型,返回值是当前 SQL 语句执行,对应数据表受到影响的行数。
				Query OK, 1 row affected(5ms)
		public java.sql.Resultset executeQuery(String sql);
			执行 SQL 语句查询操作,主要可以执行的 SQL 语句类型为 select 操作,返回值为 
			java.sql.ResultSet 数据库查询结果集对象。

interface java.sql.PreparedStatment extends java.sql.Statment
	Java JDBC 规范 数据库【预处理】搬运工对象,在项目中主要处理的 SQL 语句可以分为两大部分,一部分为更新
	(insert, update, delete),一部分为查询(select),PreparedStatment 可以引入 SQL 语句参数操作。SQL
	参数为 ? 占位符
	常用方法:
		public void setXXX(int index, XXX value);
			可以给予 SQL 语句参数赋值操作,第一个参数是 SQL 语句参数下标位置(从 1 开始),给予当前 SQL 语句
			的实际参数。类型支持任意类型(int, double, float, long, Object, String ...)
		public int executeUpdate();
			执行 SQL 语句更新操作,主要可以执行的 SQL 语句类型为 insert,update,delete 操作,返回值是 
			int 类型,返回值是当前 SQL 语句执行,对应数据表受到影响的行数。
				Query OK, 1 row affected(5ms)
		public java.sql.Resultset executeQuery();
			执行 SQL 语句查询操作,主要可以执行的 SQL 语句类型为 select 操作,返回值为 
			java.sql.ResultSet 数据库查询结果集对象。

interface java.sql.ResultSet
	Java JDBC 规范,数据库查询结果集对象。可以认为是 select 查询 SQL 语句最终结果表格对应的 Java 类型。
	常用方法:
		XXX getXXX(String columnName);
			根据列名/字段名,获取数据库当前数据行对应的数据信息,类型可以是任意类型,但是要求和数据库存储类型
			一致。支持(int, String, Long...)
		XXX getXXX(int columnIndex);	
        	根据列下标,获取数据库当前数据行对应的数据信息,类型可以是任意类型,但是要求和数据库存储类型一致。
        	支持(int, String, Long...)
        	【注意】列下标从 1 开始
        boolean next();
        	1. 判断当前数据库查询结果集对象是否还有数据行可以解析,如果可以返回 true,否则返回 false
        	2. 提取当前数据行进行解析操作,同时指向下一行数据

3jdbc1.0版本

jdbc的执行流程如下

1 注册驱动
2 获取数据库连接对象
3 获取数据库执行者对象
4 执行sql语句
5 获得结果集对象
6关闭资源

现在咱们开始对jdbc的执行流程一步步的执行实现,然后我们一步步的简化代码,提高封装力度,大家做好了,咱准备发车了

3.1执行jdbc1.0版本的添加功能

 @Test
    public void testInsert() {   
// 1. 准备数据库连接必要的参数
        String jdbcUrl = "jdbc:mysql://localhost:3306/acxng?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC";
        String username = "root";
        String password = "root";

        Connection connection = null;
        PreparedStatement statement = null;

        try {
            // 2. 加载驱动
            Class.forName("com.mysql.jdbc.Driver");

            // 3. 获取数据库连接对象
            connection = DriverManager.getConnection(jdbcUrl, username, password);

            // 4. 获取 SQL 语句搬运工对象
            String sql = "insert into user(username, password) values (?,?)";
            statement = connection.prepareStatement(sql);
            statement.setObject(1, "梅花十三");
            statement.setObject(2,"123456");
            // 6. 执行 SQL 语句
            int affectedRows = statement.executeUpdate();
            System.out.println("返回的受影响行数是:" + affectedRows);

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                // 7. 关闭数据库连接资源
                if (statement != null) {
                    statement.close();
                }

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

3.2执行jdbc1.0版本的修改功能

 @Test
    public void testUpdate() {
        // 1. 准备数据库连接必要的参数
        String jdbcUrl = "jdbc:mysql://localhost:3306/acxng?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC";
        String username = "root";
        String password = "root";

        Connection connection = null;
        PreparedStatement statement = null;

        try {
            // 2. 加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 3. 获取数据库连接对象
            connection = DriverManager.getConnection(jdbcUrl, username, password);
            String sql = "update user set username = ? where id = ?";
            statement = connection.prepareStatement(sql);
            statement.setObject(1,"李志");
            statement.setObject(2,2);
            int i = statement.executeUpdate();
            if (i > 0) {
                System.out.println("添加成功哦!");
            }


        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                // 7. 关闭数据库连接资源
                if (statement != null) {
                    statement.close();
                }

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

3.3执行jdbc1.0版本的删除功能

@Test
    public void testDelete() {
        // 1. 准备数据库连接必要的参数
        String jdbcUrl = "jdbc:mysql://localhost:3306/acxng?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC";
        String username = "root";
        String password = "root";

        Connection connection = null;
        PreparedStatement statement = null;

        try {
            // 2. 加载驱动
            Class.forName("com.mysql.jdbc.Driver");

            // 3. 获取数据库连接对象
            connection = DriverManager.getConnection(jdbcUrl, username, password);
            String sql = "delete from user where id = ?";
            statement = connection.prepareStatement(sql);
            statement.setObject(1,9);
            int i = statement.executeUpdate();
            if (i > 0) {
                System.out.println("删除成功!");
            }

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                // 7. 关闭数据库连接资源
                if (statement != null) {
                    statement.close();
                }

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

3.4执行jdbc1.0版本的查询功能

 @Test
    public void testSelect() {
        // 1. 准备数据库连接必要的参数
        String jdbcUrl = "jdbc:mysql://localhost:3306/acxng?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC";
        String username = "root";
        String password = "root";

        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;

        try {
            // 2. 加载驱动
            Class.forName("com.mysql.jdbc.Driver");

            // 3. 获取数据库连接对象
            connection = DriverManager.getConnection(jdbcUrl, username, password);

            // 4. 获取 SQL 语句搬运工对象
            String sql = "select * from student where id = ?";
            statement = connection.prepareStatement(sql);
            statement.setObject(1,2);
            resultSet = statement.executeQuery();

            // 7. 【核心步骤】结果集数据解析操作
            if (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");
                boolean gender = resultSet.getBoolean("gender");

                System.out.println("ID:" + id);
                System.out.println("Name:" + name);
                System.out.println("Age:" + age);
                System.out.println("Gender:" + gender);
            }
        } catch (ClassNotFoundException | SQLException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (resultSet != null) {
                    resultSet.close();
                }

                if (statement != null) {
                    statement.close();
                }

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

3.5jdbc1.0版本的存在问题

代码利用率低,每执行一次增删改查都得执行大量重复的代码,例如获取连接,释放资源等等
代码冗余

4.jdbc2.0版本

4.1和jdbc1.0的差别

//使用工具类JdbcUtils和配置文件db.properties连接数据库,简化代码 //JdbcUtils中有两个方法,一是关闭资源close,方法,二是获取数据库连接方法getConnection

db.properties配置文件代码如下

Driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/acxng?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
user=root
password=123456

JdbcUtils工具类代码如下

public class JdbcUtils {
    /**
    连接数据库的Url地址
     */
    private static String url = null;
    /**
    用户名
     */
    private static String user = null;
    /**
    密码
     */
    private static String password = null;


    // 利用static修饰的静态代码块完成文件字段自动读取和驱动自动加载过分
    static {

        InputStream input = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
        try {
            // Properties实现类,里面的数据保存形式都是键值对形式
            Properties properties = new Properties();

            properties.load(input);
            // 从Properties读取对应的数据
            String driverClass = properties.getProperty("Driver");
            url = properties.getProperty("url");
            user = properties.getProperty("user");
            password = properties.getProperty("password");

            // 完整驱动加载
            Class.forName(driverClass);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                if (input!=null) {
                    input.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 返回数据库连接对象,连接失败返回null
     *
     * @return java.sql.Connection 数据库连接对象
     */
    public static Connection getConnection() {
        Connection connection = null;

        try {
            // 通过DriverManager驱动管理类,使用必要参数获取数据库连接
            connection = DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return connection;
    }

    /**
     * 关闭资源方法
     *
     * @param connection java.sql.Connection 数据库连接对象资源
     * @param statement  java.sql.Statement 数据库 SQL 语句搬运工资源
     */
    public static void close(Connection connection, Statement statement) {
        close(statement, connection);
    }

    /**
     * 关闭资源方法
     *
     * @param connection java.sql.Connection 数据库连接对象资源
     * @param statement  java.sql.Statement 数据库 SQL 语句搬运工资源
     * @param resultSet  java.sql.ResultSet 数据库查询结果集对象
     */
    public static void close(Connection connection, Statement statement, ResultSet resultSet) {
        close(resultSet, statement, connection);
    }

    /**
     * 内部私有化方法,统一处理数据库相关资源
     *
     * @param resources AutoCloseable 不定长参数,统一关闭对应资源
     */
    public static void close(AutoCloseable... resources) {
        if (resources != null && resources.length > 0) {
            Arrays.stream(resources).forEach(source -> {
                try {
                    if (source != null) {
                        source.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    }
}

4.2jdbc2.0执行增删改查的代码

public class Jdbc2Test {
    @Test
    public void testInsert() {

        Connection connection = null;
        PreparedStatement statement = null;

        try {
            // 3. 获取数据库连接对象
            connection = JdbcUtils.getConnection();
            // 4. 获取 SQL 语句搬运工对象
            String sql = "insert into user(username, password) values (?,?)";
            statement = connection.prepareStatement(sql);
            statement.setObject(1, "梅花十三");
            statement.setObject(2,"123456");
            // 6. 执行 SQL 语句
            int affectedRows = statement.executeUpdate();
            System.out.println("返回的受影响行数是:" + affectedRows);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
           JdbcUtils.close(connection,statement);
        }
    }

    @Test
    public void testUpdate() {
        Connection connection = null;
        PreparedStatement statement = null;

        try {
            // 3. 获取数据库连接对象
            connection = JdbcUtils.getConnection();
            String sql = "update user set username = ? where id = ?";
            statement = connection.prepareStatement(sql);
            statement.setObject(1,"李志");
            statement.setObject(2,2);
            int i = statement.executeUpdate();
            if (i > 0) {
                System.out.println("修改成功!!");
            }

        } catch ( SQLException e) {
            e.printStackTrace();
        } finally {
          JdbcUtils.close(connection,statement);
        }
    }

    @Test
    public void testDelete() {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            // 3. 获取数据库连接对象
            connection = JdbcUtils.getConnection();
            String sql = "delete from user where id = ?";
            statement = connection.prepareStatement(sql);
            statement.setObject(1,14);
            int i = statement.executeUpdate();
            if (i > 0) {
                System.out.println("删除成功!");
            }

        } catch ( SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(connection,statement);
        }
    }

    @Test
    public void testSelect() {

        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {

            // 3. 获取数据库连接对象
            connection = JdbcUtils.getConnection();
            // 4. 获取 SQL 语句搬运工对象
            String sql = "select * from user where id = ?";
            statement = connection.prepareStatement(sql);
            statement.setObject(1,2);
            resultSet = statement.executeQuery();

            // 7. 【核心步骤】结果集数据解析操作
            if (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("username");
                String password = resultSet.getString("password");
                System.out.println("ID:" + id);
                System.out.println("username:" + name);
                System.out.println("password:" + password);
            }
        } catch ( SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JdbcUtils.close(connection,statement,resultSet);
        }

    }

    /**
     1. 数据库数据表数据转换为 Student 实例化对象阿尼古
     2. 数据存储到 List 集合中
     */
    @Test
    public void testSelectAll() {
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            // 3. 获取数据库连接对象
            connection = JdbcUtils.getConnection();
            // 4. 获取 SQL 语句搬运工对象
            String sql = "select * from user";
            statement = connection.prepareStatement(sql);
            // 6. 执行 SQL 语句,得到 ResultSet 结果集对象【重点】
            resultSet = statement.executeQuery();
            // 7. 创建一个List集合
            ArrayList<User> list = new ArrayList<>();
            // 8. 【核心步骤】结果集数据解析操作
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String username1 = resultSet.getString("username");
                String password1 = resultSet.getString("password");
                list.add(new User(id, username1, password1));
            }
            list.forEach(System.out::println);
        } catch ( SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JdbcUtils.close(connection,statement,resultSet);
        }

    }
}

4.3jdbc2.0版本的存在问题

没有通用的更新方法和查询方法,每次查询或者更新都得重新写一个方法,这大大降低了代码的简介性

5.jdbc3.0版本

5.1和jdbc2.0的差别

增加了BaseDaoi类,执行通用的增删改查处理

BaseDao类

/**
     * 自定义通过增删改方法
     *
     * @param sql        sql语句
     * @param parameters 参数数组
     * @return 返回受影响行数
     */
    public int update(String sql, Object... parameters) {
        //1 准备必要的变量
        int affectRows = 0;
        Connection connection = null;
        PreparedStatement statement = null;
        //2 获取数据库连接对象
        connection = JdbcUtils.getConnection();
        try {
            //3 获取数据库执行者对象
            statement = connection.prepareStatement(sql);
            //4 通过元数据获取数据库中sql语句中的参数个数
            int parameterConut = statement.getParameterMetaData().getParameterCount();
            //5 判断参数个数不等于零或者参数值不为空,要求参数个数二者相等
            if (parameterConut != 0 && parameters != null && parameters.length == parameterConut) {
                for (int i = 0; i < parameterConut; i++) {
                    statement.setObject(i + 1, parameters[i]);
                }
            }
            affectRows = statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(connection, statement);
        }
        return affectRows;
    }

    public <T> T queryBean(String sql, Class<T> cls, Object... paramters) throws SQLException
    {

        T t = null;
        Connection connection = null;
        ResultSet resultSet = null;
        PreparedStatement statement = null;

        try {


            connection = JdbcUtils.getConnection();
            statement = handlerPreparedStatement(sql, connection, paramters);
            resultSet = statement.executeQuery();

            ResultSetMetaData metaData = resultSet.getMetaData();
            int columnCount = metaData.getColumnCount();

            while (resultSet.next()) {
                t = cls.getConstructor().newInstance();
                for (int i = 1; i <= columnCount; i++) {
                    String fieldName = metaData.getColumnName(i);
                    //获取实际对象中的值
                    Object value = resultSet.getObject(fieldName);

                    BeanUtils.setProperty(t,fieldName,value);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(connection, statement, resultSet);
        }
        return t;
    }

5.2 jdbc3.0执行代码

    @Test
    public void testInsert() {
            // 4. 获取 SQL 语句搬运工对象
        String sql = "insert into user(username, password) values (?,?)";

        int affectedRows = super.update(sql, "赤牙", "5879");
        System.out.println("SQL 语句执行对于数据表影响行数:" + affectedRows);

    }

    @Test
    public void testUpdate() {

        String sql = "update user set username = ? where id = ?";

        int affectRows = super.update(sql, "梅花大侠", 10);
        System.out.println("SQL 语句执行对于数据表影响行数:" + affectRows);

    }

    @Test
    public void testDelete() {

        String sql = "delete from user where id = ?";

        int affectRows = super.update(sql, 13);
        System.out.println("SQL 语句执行对于数据表影响行数:" + affectRows);
    }

    @Test
    public void testSelect() throws SQLException {
        String sql = "select * from user where id = ?";
        User users = super.queryBean(sql,User.class,2);
        System.out.println(users);
    }

    /**
     1. 数据库数据表数据转换为 Student 实例化对象阿尼古
     2. 数据存储到 List 集合中
     */
    @Test
    public void testSelectAll() {

        String sql = "select * from user where id >= ?";
        List<User> list = super.queryBeanList(sql, User.class, 1);
        System.out.println(list);
    }

5.3jdbc3.0存在的问题

我们可以看到,对于增删改方法返回的是受影响的行数,我们可以用一个通过的方法解决,但是对于查询,我们的返回值可能多种多样,这时候就要考虑数据类型的多样性,这时候我们就可以用到泛型了。

5.4元数据

分为数据库元数据,执行者元数据,结果集元数据
    @Test
    public void testMetaData() throws SQLException {

        Connection connection = JdbcUtils.getConnection();
        //数据库元数据 connection.getMetaData
        DatabaseMetaData metaData = connection.getMetaData();
        System.out.println("URL:"+metaData.getURL());
        System.out.println("DriverVersion:"+metaData.getDriverMajorVersion());
        System.out.println("UserName:"+metaData.getUserName());
        System.out.println();
        String sql = "select * from user where id = ?";
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setObject(1,1);


        //可以通过PreparedStatement 执行者对象获取参数元数据对象
        ParameterMetaData parameterMetaData = statement.getParameterMetaData();
        int parameterCount = parameterMetaData.getParameterCount();
        System.out.println("SQL语句对应的参数:"+parameterCount);
        System.out.println();
        ResultSet resultSet = statement.executeQuery();

        //【VIK】 结果集元数据,需要从结果集中获取【字段名称,字段个数】
        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
        int countmnCount = resultSetMetaData.getColumnCount();
        System.out.println("结果集字段个数:"+countmnCount);
        for (int i = 1; i <= countmnCount; i++) {
            System.out.println("字段名/列名:"+resultSetMetaData.getColumnName(i));
        }
        connection.close();
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值