JavaWeb—JDBC篇

概述

jdbc是javaWeb的技术框架

定义

JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,(java.sql,javax.sql)使用这些类库可以以一种标准的方法、方便地访问数据库资源。

作用

JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。 

图片示例: 

 

 系统结构

JDBC接口(API)包括两个层次:
面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)。
面向数据库的API:Java Driver API,供开发商开发数据库驱动程序用。 

JDBC是sun公司提供一套用于数据库操作的接口,java程序员只需要面向这套接口编程即可。
不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。 ————面向接口编程 

JDBC步骤

图示:

 

  1. 导入jar包 添加到当前类库中

  2. 加载注册驱动 Driver的实现类

  3. 获取数据库连接对象Connection

  4. 创建执行sql的对象

  5. 执行sql DML增删改 DQL查询

  6. 如果是增删改拿到影响行数的返回结果 ,如果是查询就获取ResultSet对象

  7. 关闭资源 ResultSet Connection

连接三要素

要素1 Driver驱动

Driver接口
java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现。在程序中不需要直接去访问实现了 Driver 接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实现。


加载与注册JDBC驱动
加载驱动:加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名
Class.forName(“com.mysql.cj.jdbc.Driver”);
注册驱动:DriverManager 类是驱动程序管理器类,负责管理驱动程序:
使用DriverManager.registerDriver(com.mysql.jdbc.Driver)来注册驱动
(通常不需要注册)

要素2 url

JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。
JDBC URL的标准由三部分组成,各部分间用冒号分隔。 http:// 
jdbc:子协议:子名称
协议:JDBC URL中的协议总是jdbc 
子协议:子协议用于标识一个数据库驱动程序
子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了定位数据库提供足够的信息。包含主机名(对应服务端的ip地址),端口号,数据库名


jdcb主协议
mysql子协议
localhost:3306 本机的mysql
java2312 要操作的数据库
jdbc:mysql://localhost:3306/java2312

要素三 用户名和密码

user,password可以用“属性名=属性值”方式告诉数据库
可以调用 DriverManager 类的 getConnection() 方法建立到数据库的连接

连接方式

连接方式1

public void conOne() throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {

        //连接方式1

//        driver全类名 要素1
        String driveClass = "com.mysql.cj.jdbc.Driver";
//        url 连接路径 要素2
        String url = "jdbc:mysql://localhost:3306/java2312";
//        用户名 密码 要素3
        String user= "root";
        String password = "121812";


//        实例化driver
        Class<?> aClass = Class.forName(driveClass);
        Driver driver = (Driver) aClass.newInstance();

//        注册驱动 可选
        DriverManager.registerDriver(driver);

//        获取连接
        Connection connection = DriverManager.getConnection(url, user, password);

        System.out.println(connection);
    }

连接方式2

 jdbc.properties

driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/java2312
username=root
password=111111

java代码

  /*
        将 三大要素 存放到 配置文件中
        文件名一般都叫jdbc.properties
          内容以key = value的形式编写
        再通过io的形式读取出来
         */

        // 如果test测试单元 根目录实在模块下 如果main方法是在项目下
        FileInputStream fileInputStream = new FileInputStream("jdbc.properties");
//        用来读取配置文件
        Properties properties = new Properties();
        properties.load(fileInputStream);

//       驱动
        String driverClass = properties.getProperty("driverClass");
        //url
        String url = properties.getProperty("url");
        //用户名
        String username = properties.getProperty("username");
        //密码
        String password = properties.getProperty("password");
//        加载驱动
        Class.forName(driverClass);

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

        System.out.println(connection);

执行DML语句

 

 Connection connection = null;
        try {
            //获取连接对象
            connection = ConnectionUtil.getConnection();
//        获取sql执行对象
            Statement statement = connection.createStatement();
            String sql ="delete from account where id in(1,2);";
            int i = statement.executeUpdate(sql);
            System.out.println(i);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            //关闭资源
            ConnectionUtil.close(connection);
        }

sql注入问题

SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令(如:SELECT user, password FROM user_table WHERE user='a' OR 1 = ' AND password = ' OR '1' = '1') ,从而利用系统的 SQL 引擎完成恶意行为的做法。

preparedStatement

可以通过调用 Connection 对象的 preparedStatement(String sql) 方法获取 PreparedStatement 对象
PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句
PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值

 @Test
    public void preparedStatementTest1() {
        Connection connection = null;
        ResultSet resultSet = null;
        try {
            connection = ConnectionUtil.getConnection();


            //查询sql ?是占位符
            String sql="select * from user_table where user_name=? and password =?;";

//        获取 对象 传入一个预编译sql
            PreparedStatement ps = connection.prepareStatement(sql);
//       设置占位符内容
//        第几个占位符从1开始,占位符内容
            ps.setString(1,"1'or");
            ps.setString(2,"=1 or '1'='1");

//        执行查询语法
            resultSet = ps.executeQuery();
            if (resultSet.next()){
                System.out.println("登录成功");
            }else {
                System.out.println("登录失败");
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {

            //关闭资源
            ConnectionUtil.close(connection,resultSet);
        }

    }

 

preparedStatement和Statement区别

statement不对sql语句做处理,直接交给数据库;而prepraedstatement是支持预编译的,会将编译好的sql语句放在数据库端,相当于缓存,对于多次重复执行的sql语句,使用prepraedstatement可以使得代码的执行效率更高。

java对应sql的数据类型表

封装公共的增加修改删除

 /**
     * 公用的增加 修改 删除的方法
     * @param sql 预编译sql
     * @param args 占位符的内容
     * @return
     */
    public static int publicUpdate(String sql,Object ... args) {
        Connection connection = null;
        int num = 0;

        try {
            //1获取连接对象
            connection = ConnectionUtil.getConnection();

            //2获取操作sql的对象
            PreparedStatement ps = connection.prepareStatement(sql);

            //3充填占位符
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i+1,args[i]);
            }

            //4执行sql
            num = ps.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            //5关闭资源
            ConnectionUtil.close(connection);
        }

        return num;


    }

ResultSet

   @Test
    public void test1() throws SQLException {
        Connection connection = ConnectionUtil.getConnection();


        String sql = "select * from account";
        PreparedStatement ps = connection.prepareStatement(sql);


        ResultSet resultSet = ps.executeQuery();

//        next 查看是否有下一条记录
//        System.out.println(resultSet.next());
//        System.out.println(resultSet.next());
//        System.out.println(resultSet.next());

//        getXxx :getObject getString
        /*
        通过列数或者字段名别名来拿到当前单元格中的信息
         */

        while (resultSet.next()){
            int id = resultSet.getInt("id");
            String userName = resultSet.getString("user_name");
            double money = resultSet.getDouble("money");
            //将查询出来的数据 转换为javaBean对象
            AccountBean accountBean = new AccountBean(id, userName, money);
            System.out.println(accountBean);


        }


    }

MetaData

通过metaData获取内容 :

 while (resultSet.next()){

            ResultSetMetaData metaData = resultSet.getMetaData();

//        返回当前查询结果中的列的个数
            int columnCount = metaData.getColumnCount();
            //根据列数进行循环
            for (int i = 0; i < columnCount; i++) {
                //获取当前列的别名 如果没有起别名 那么默认获取的就是列名
                String key = metaData.getColumnLabel(i+1);

                //通过resultSet 根据别名获取值
                Object value = resultSet.getObject(key);
                System.out.println(key+":"+value);

            }

//        获取当前列的列名
//        String columnName = metaData.getColumnName(1);

封装查询

 

  /**
     * 查询 单个对象
     * @param clazz 对象的类型
     * @param sql 预编译sql
     * @param args 占位符内容
     * @return  对应的对象
     * @param <T>
     * @throws Exception
     */
    public static <T> T querySingle(Class<T> clazz, String sql, Object... args)  {
        Connection connection = null;
        ResultSet resultSet = null;
        T o = null;
        try {
            connection = ConnectionUtil.getConnection();

            PreparedStatement ps = connection.prepareStatement(sql);

            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }

            resultSet = ps.executeQuery();
            o = null;
            if (resultSet.next()) {
                o= clazz.newInstance();
                ResultSetMetaData metaData = resultSet.getMetaData();

    //        返回当前查询结果中的列的个数
                int columnCount = metaData.getColumnCount();
                //根据列数进行循环
                for (int i = 0; i < columnCount; i++) {

                    //获取当前列的别名 如果没有起别名 那么默认获取的就是列名
                    String key = metaData.getColumnLabel(i + 1);

                    //通过resultSet 根据别名获取值
                    Object value = resultSet.getObject(key);

    //                获取类的属性对象
                    Field declaredField = clazz.getDeclaredField(key);
    //                  暴力破解 能够操作private修饰的属性
                    declaredField.setAccessible(true);

                    declaredField.set(o,value);

                }


            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } finally {
            //关流
            ConnectionUtil.close(connection,resultSet);
        }

        return o;
    }


    /**
     * 查询多列数据
     * @param clazz
     * @param sql
     * @param args
     * @return
     * @param <T>
     */
    public static <T> List<T> queryList(Class<T> clazz, String sql, Object... args)  {
        Connection connection = null;
        ResultSet resultSet = null;
        T o = null;
        ArrayList<T> list = new ArrayList<>();

        try {
            connection = ConnectionUtil.getConnection();

            PreparedStatement ps = connection.prepareStatement(sql);

            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }

            resultSet = ps.executeQuery();
            o = null;
            while (resultSet.next()) {
                o= clazz.newInstance();
                ResultSetMetaData metaData = resultSet.getMetaData();

                //        返回当前查询结果中的列的个数
                int columnCount = metaData.getColumnCount();
                //根据列数进行循环
                for (int i = 0; i < columnCount; i++) {

                    //获取当前列的别名 如果没有起别名 那么默认获取的就是列名
                    String key = metaData.getColumnLabel(i + 1);

                    //通过resultSet 根据别名获取值
                    Object value = resultSet.getObject(key);

                    //    获取类的属性对象
                    Field declaredField = clazz.getDeclaredField(key);
                    //   暴力破解 能够操作private修饰的属性
                    declaredField.setAccessible(true);
                    declaredField.set(o,value);
                }
                //将对象放入list集合中
                list.add(o);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } finally {
            //关流
            ConnectionUtil.close(connection,resultSet);
        }


        return list;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值