2021年8月30日

0.补充知识点

咱们现在写代码,得有main主函数才能运行。

如果没有main主函数能运行代码吗?

能的

咱们使用的是一个注解的写法

@Test 下面修饰的是一个自定义的方法

需要导包 alt+enter Junit4这个jar包

package com.qfedu.a_test;

import org.junit.Test;

public class Test1 {
   //@Test 是一个注解的写法
   //@Override   是修饰一个方法的,这个方法是严格重写的方法
   @Test//alt + enter   add Junit4这个jar添加一些即可
   //这个注解是修饰一个方法的,让这个方法变成一个测试方法。可以直接运行的方法
   public void test1() {
       System.out.println("123");
  }
   @Test
   public void test2() {
       System.out.println("hello world");
  }

   //这个@Test只要修饰了方法以后,这个方法就会变成一个单元测试的方法,
   //可以直接使用运行按钮,直接执行的。
   @Test
   public void sb() {
       System.out.println("呵呵哒");
  }
}

1.重新封装JdbcUtil

1.在src下面新建一文件,这个文件叫db.properties,等一会儿,咱们这个文件需要在

JdbcUti这个类下面需要读取这个文件里面的内容

package com.qfedu.util;

import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

/**
* 1.完成驱动的自动加载
* 2.完成必要的数据处理 url user password
* 3.完成connection这个方法
* 4.完成统一的close方法
*/
public class JdbcUtil {
   private static String url = null;
   private static String user = null;
   private static String password = null;
   private static String driver = null;
   //使用静态代码块进行数据的加载和驱动的加载
   static {
       //需要去读取properties这个文件里面的内容

       //1.需要创建一个properties对象,这个对象的功能就是读取properties这文件的
       Properties properties = new Properties();
       //2.使用load方法,加载src下面的db.properties这个文件
       try {
           //已经将咱们的db.properties文件里面的额内容已经加载到了properties对象中了
           properties.load(new FileInputStream("./src/db.properties"));
           //3.从properties这个对象获取值 4个值
           url = properties.getProperty("url");
           user = properties.getProperty("user");
           password = properties.getProperty("password");
           driver = properties.getProperty("driver");
           Class.forName(driver);
      } catch (IOException e) {
           e.printStackTrace();
      } catch (ClassNotFoundException e) {
           e.printStackTrace();
      }

  }
   //简化getConnection方法的写法
   //简化getConnection方法的写法
//封装一个静态的方法,获取connetion对象
   public static Connection getConnection() {
       Connection connection = null;
       try {
           connection = DriverManager.getConnection(url, user, password);
      } catch (SQLException e) {
           e.printStackTrace();
      }
       return connection;
  }

   //现在封装的时候,我不知道需要关闭哪个资源
   //有的需要关闭一个,有的需要关闭两个,有的需要关闭三个
   //关闭一个资源 connection
   public static void close(Connection connection) {
       close(connection, null, null);
  }
   //关闭两个资源 connection statement
   public static void close(Connection connection, Statement statement) {
       close(connection, statement, null);
  }
   //关闭三个资源的 connection statement   resultSet
   public static void close(Connection connection, Statement statement, ResultSet resultSet) {
       if (connection != null) {
           try {
               connection.close();
          } catch (SQLException e) {
               e.printStackTrace();
          }
      }
       if (statement != null) {
           try {
               statement.close();
          } catch (SQLException e) {
               e.printStackTrace();
          }
      }
       if (resultSet != null) {
           try {
               resultSet.close();
          } catch (SQLException e) {
               e.printStackTrace();
          }
      }
  }

}

2.预处理搬运工对象处理sql

咱们之前学过搬运工对象,搬运工对象的功能就是把sql语句搬运到数据库进行执行,

而且写的sql语句叫静态的sql语句。现在再学一种处理sql的方法,写动态的sql语句

这个叫预处理的搬运工。这个是咱们以后开发中用的,搬运工不用了。

在写sql语句的时候,真实的sql语句使用到是?带替真实的值。

package com.qfedu.b_preparestatement;

import com.qfedu.util.JdbcUtil;
import org.junit.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

public class Demo1 {
   //先写一个增加数据的写法,使用预处理的搬运工对象进行数据的增加
   @Test
   public void testAdd() throws SQLException {
       //1.获取connetion对象
       Connection connection = JdbcUtil.getConnection();
       //2.准备sql语句
       //sql 就是一个动态的sql语句,先使用?占着位置,然后通过预处理搬运工对象
       //对咱们这个sql进行预处理
       String sql = "insert into work (name, age, info) values(?,?,?)";
       //3.可以预编译并存储在PreparedStatement对象中。 然后可以使用该对象多次有效地执行此语句
       PreparedStatement preparedStatement = connection.prepareStatement(sql);
       //4.给定实际参数
       //parameterIndex - 第一个参数是1,第二个是2,...
       //将旺财 赋值给第一个?   将23赋值给第二个?   将噼里啪啦赋值给第3个?
       //这个顺序一定要排好。因为预处理搬运工已经将咱们的sql进行了预处理了。发现是?
       //等着你进行值的赋值
       preparedStatement.setObject(1, "旺财");
       preparedStatement.setObject(2, 23);
       preparedStatement.setObject(3, "噼里啪啦");
       //4.开始真正的执行sql语句,这个时候的sql语句是一个完整的sql语句了
       int i = preparedStatement.executeUpdate();
       System.out.println(i);
       //5.关闭资源
       JdbcUtil.close(connection, preparedStatement);
  }

   //使用预处理的搬运工对象进行删除数据的操作
   @Test
   public void testDelete() throws SQLException {
       //1.获取connetion对象
       Connection connection = JdbcUtil.getConnection();
       String sql = "delete from work where id = ?";//?只是一个占而已,缺一个,预处理的搬运工对象,需要给赋一个真实的值。
       PreparedStatement preparedStatement = connection.prepareStatement(sql);
       preparedStatement.setObject(1, 3);
       int i = preparedStatement.executeUpdate();
       System.out.println(i);
       JdbcUtil.close(connection, preparedStatement);


  }
   //使用预处理的搬运工对象修改数据
   @Test
   public void testUpdate() throws SQLException {
       Connection connection = JdbcUtil.getConnection();
       String sql = "update work set name=?,age=?,info=? where id=?";
       PreparedStatement preparedStatement = connection.prepareStatement(sql);
       preparedStatement.setObject(1, "小万");
       preparedStatement.setObject(2, 4);
       preparedStatement.setObject(3, "活泼可爱");
       preparedStatement.setObject(4, 4);
       int i = preparedStatement.executeUpdate();
       System.out.println(i);
       JdbcUtil.close(connection, preparedStatement);
  }
   //使用预处理的搬用工查询一条数据
   @Test
   public void testSelectOne() throws SQLException {
       Connection connection = JdbcUtil.getConnection();
       String sql = "select * from work where id = ?";
       PreparedStatement preparedStatement = connection.prepareStatement(sql);
       preparedStatement.setObject(1, 7);
       ResultSet resultSet = preparedStatement.executeQuery();//有几条数据?1条
       //1条数据的话,有必要使用循环吗?用if写法
       if (resultSet.next()) {
           int id = resultSet.getInt("id");
           String name = resultSet.getString("name");
           int age = resultSet.getInt("age");
           String info = resultSet.getString("info");
           //以上把数据取出来了,然后呢?能不能将取出来的数据赋值给一个对象?
           //Work这类有参构造,所以咱们直接new有参构造
           Work work = new Work(id, name, age, info);
           System.out.println(work);
      }
       JdbcUtil.close(connection, preparedStatement, resultSet);
  }
   //使用预处理的搬运工对象获取多条数据
   @Test
   public void testSelectAll() {
       Connection connection = JdbcUtil.getConnection();
       String sql = "select * from work";//没有占位符的
       PreparedStatement preparedStatement = null;
       ResultSet resultSet = null;
       ArrayList<Work> works = new ArrayList<>();//声明了一个集合,这个集合存放的是多个work对象

       try {
           preparedStatement = connection.prepareStatement(sql);
      } catch (SQLException e) {
           e.printStackTrace();
      }
       try {
           resultSet = preparedStatement.executeQuery();
           while (resultSet.next()) {
               int id = resultSet.getInt("id");
               String name = resultSet.getString("name");
               int age = resultSet.getInt("age");
               String info = resultSet.getString("info");
               //将数据库里面取出来的值赋值给work对象
               //一次循环数据赋值给一个对象,循环了多次 多个work对象
               works.add(new Work(id, name, age, info));

          }
      } catch (SQLException e) {
           e.printStackTrace();
      }

       for (Work work : works) {
           System.out.println(work);
      }
       JdbcUtil.close(connection, preparedStatement, resultSet);
  }
}

总结:

1.现在src文件夹下面创建一个lib文件夹,把mysql-connector-java-5.1.47.jar复制上去并导包
2.写一个db.properties这个文件到src这个下面
3.新建一个文件夹,下面写封装号的JdbcUtil这个类
4.直接写预处理搬运工就就可以了

3.使用预处理搬运工对象可以防止sql注入

sql注入就是一种不安全的情况,在删除数据或者查询数据的时候,sql语句的后面如果跟了or 1=1这个sql语句相当于操作了数据表所有数据

package com.qfedu.c_preparestatement;

import com.qfedu.util.JdbcUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

public class Demo1 {
   public static void main(String[] args) throws SQLException {
       prepareTest();
  }
   //使用搬用工对象处理sql语句,有可能出现问题!!!!
   public static  void statementTest() throws SQLException {
       Connection connection = JdbcUtil.getConnection();
       String id = "1 or 1=1";//这个是你的同事也就是竞争对手,用你的电脑,然后
       //修改了id这个字符串,就会将数据表中的数据全部删除掉了
       //delete from user1 where id = 1 or 1=1
       String sql = "delete from user1 where id = " + id;
       Statement statement = connection.createStatement();
       int i = statement.executeUpdate(sql);
       System.out.println(i);
       JdbcUtil.close(connection, statement);
  }

   //预处理的搬运工,可以防止sql注入
   public static void prepareTest() throws SQLException {
       Connection connection = JdbcUtil.getConnection();
       String sql = "delete from user1 where id = ?";
       PreparedStatement preparedStatement = connection.prepareStatement(sql);
       //preparedStatement.setObject(1, "5 or 1=1");
       preparedStatement.setObject(1, "5");
       int i = preparedStatement.executeUpdate();
       System.out.println(i);
       JdbcUtil.close(connection, preparedStatement);
  }
   /*
   * 为什么preparestatement可以防止sql注入?
   * 因为他的sql预。而且里面使用了占位符。规定了sql的结构!!!
   * 用户可以设置?的值,但是sql的结构不能再更改。如果想要在sql的后面加上
   * or 1=1就直接报错了
   *
   * */
}

4.JavaBean规范和BeanUtils工具类的使用【重点】

4.1JavaBean规范

JavaBean就是你写的一个实体类,

JavaBean规范:就是对类的一种规范写法。

1.私有化成员变量

2.一定要提供一个无参构造

3.一定要提供对应的setter和getter方法

4.每一个类作为一个单独的文件,并且使用public修饰

以后开发中可以利用JavaBean规范的额普适性完成一些操作!!!

一个表对应着一个类?为什么?而且表的字段和实体类属性对应好!!为什么要这样做!!!

咱们从数据库里面取出来数据,可以使用一个实体类进行接收赋值,刚好接到。

4.2BeanUtils类

Beanutils是基于反射,完成符合javabean规范的实体类的操作

查看官方的API,查不到?是因为Jdk压根就没有这个类,所以判定这个类第三方的类

所以需要导包才能使用这个类。

需要导包:common-beanutils-1.9.3.jar 导这一个包行吗?不行!!!

还需要依赖另外一个包 common-logging-1.1.3.jar

package com.qfedu.d_beanutils;

import org.apache.commons.beanutils.BeanUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

public class Demo1 {
   public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException {
       //BeanUtils 基于反射 操作咱们的实体类的,对实体类对象进行赋值取值的
       Person person = new Person();
       System.out.println(person);//Person{id=0, name='null', age=0}
       //使用Beanutils这个类去设置实体类的属性
       //person.setId(1) 换成下面这种写法了
       //使用beanutils这个类去设置person对象中的 id属性为 1
       BeanUtils.setProperty(person, "id", 1);
       BeanUtils.setProperty(person, "name", "狗蛋");
       BeanUtils.setProperty(person, "age", 23);
       System.out.println(person);
       //获取字段的写法
       System.out.println(BeanUtils.getProperty(person, "name"));//狗蛋

       //复制数据到一个新的对象中
       Person person1 = new Person();
       System.out.println(person1);//空的数据
       //将person对象中属性复制给person1对象
       BeanUtils.copyProperties(person1, person);
       System.out.println(person1);

       //克隆
       Person o = (Person)BeanUtils.cloneBean(person);
       System.out.println(o);

       //描述当前实体类的
       Map<String, String> describe = BeanUtils.describe(person);
       System.out.println(describe);
       Set<String> strings = describe.keySet();//获取的键
       Collection<String> values = describe.values();//获取的值
  }
}

5.元数据【重要的点】

metaData

数据库元数据【不重要】:DatabaseMetaData

获取数据库连接对象信息

元数据包括有关数据库表,其支持的SQL语法,其存储过程,此连接的功能等的信息。

参数元数据【重要】:

结果集元数据【重要】:

5.1数据库元数据【DatabaseMetaData】

package com.qfedu.e_metadata;

import com.qfedu.util.JdbcUtil;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;

/**
* 数据库元数据
*/
public class Demo1 {
   public static void main(String[] args) throws SQLException {
       //1.先连接上数据库
       Connection connection = JdbcUtil.getConnection();
       //元数据包括有关数据库表,其支持的SQL语法,其存储过程,此连接的功能等的信息。
       DatabaseMetaData metaData = connection.getMetaData();
       System.out.println(metaData);
       //获取数据库产品的名字
       String databaseProductName = metaData.getDatabaseProductName();
       System.out.println(databaseProductName);
       //获取驱动端额名字
       String driverName = metaData.getDriverName();
       System.out.println(driverName);
       //获取驱动的版本
       String driverVersion = metaData.getDriverVersion();
       System.out.println(driverVersion);
       //获取连接数据库的url
       String url = metaData.getURL();
       System.out.println(url);
       //root@localhost
       String userName = metaData.getUserName();
       System.out.println(userName);
       //能不能获取连接数据库的密码?不能,要疯啊!!!


  }
}

5.2参数元数据【重点】

ParameterMetaData

不是Connection对象获取出来的!!!

和数据库里面的sql语句有关 insert into person(name, age, info) values(?,?,?)

sql语句和预处理的搬运工有关系!!!

所以说咱们参数元数据对象是预处理的搬运工对象获取的

package com.qfedu.e_metadata;

import com.qfedu.util.JdbcUtil;

import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
* 参数元数据对象
*/
public class Demo2 {
   public static void main(String[] args) throws SQLException {
       Connection connection = JdbcUtil.getConnection();
       String sql  = "insert into work(name, age, info) values(?,?,?)";
       PreparedStatement preparedStatement = connection.prepareStatement(sql);
       //今天的东西必须去理解,因为明天要封装增删改查需要用到今天讲的BeanUtils
       //参数元数据和结果集元数据
       //获取preparedStatement对象中sql语句参数的数量,属性等
       ParameterMetaData parameterMetaData = preparedStatement.getParameterMetaData();
       //获取sql里面参数的个数,这个明天我要用!!!
       int parameterCount = parameterMetaData.getParameterCount();
       System.out.println(parameterCount);
//       for (int i = 1; i <= parameterCount; i++) {
//           preparedStatement.setObject(i, 数组参数[i-1]);
//       }
  }
}

5.3结果集元数据【重点】

ResultSetMetaData

只和查询出来结果有关

数据库元数据和Connection有关。

参数元数据和预处理的搬运工对象有关

结果集元数据和结果集有关

明天我讲的时候需要用到这个!!!

package com.qfedu.e_metadata;

import com.qfedu.util.JdbcUtil;

import java.sql.*;

/**
 * 结果集元数据
 */
public class Demo3 {
    public static void main(String[] args) throws SQLException {
        //结果集元数据只和查询有关
        Connection connection = JdbcUtil.getConnection();
        String sql = "select * from work";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        ResultSet resultSet = preparedStatement.executeQuery();//获取的是结果集对象
        //获取数据表中的字段的属性,个数,名字等
        ResultSetMetaData metaData = resultSet.getMetaData();
        //获取字段的个数  4
        int columnCount = metaData.getColumnCount();
        System.out.println(columnCount);
    /*
    *
    * mysql> select * from work;
+----+-----------+------+--------------+
| id | name      | age  | info         |
+----+-----------+------+--------------+
|  2 | 小邢      |    3 | 刚断奶       |
|  5 | 帅栋      |   34 | xjnnm        |
|  6 | 二狗子    |   32 | nxsnmxn      |
|  7 | 旺财      |   23 | 噼里啪啦     |
+----+-----------+------+--------------+
    * */
    while (resultSet.next()) {
        for (int i = 1; i <= columnCount; i++) {
            //第一次循环
            /*getColumnName  获取字段名字的!!!
            要字段名字干嘛?  可以通过字段的名字获取数据库里面的值!!!
            * i = 1 1<= 4 true    metaData.getColumnName(1) i++  id
            * i = 2  2<=4 true    metaData.getColumnName(2) i++  name
            * i=3  3 <= 4 true  metaData.getColumnName(3) i++  age
            * i=4 4<=4 true metaData.getColumnName(4) i++  info
            * 里层for循环结束
            *
            * 第二次while循环
            * * i = 1 1<= 4 true    metaData.getColumnName(1) i++  id
             * i = 2  2<=4 true    metaData.getColumnName(2) i++  name
             * i=3  3 <= 4 true  metaData.getColumnName(3) i++  age
             * i=4 4<=4 true metaData.getColumnName(4) i++  info
             * * 里层for循环结束
             *
             * 。。。
             *
             * 经历四次才结束
             * */
            //System.out.println(metaData.getColumnName(i));//通过列的索引获取列的名字
//            resultSet.getObject("id");
//            resultSet.getObject("name");
//            resultSet.getObject("age");
//            resultSet.getObject("info");

            //这行代码得看懂!!!metaData.getColumnName(i)  字段的名字是通过for循环获取出来的
            System.out.println(resultSet.getObject(metaData.getColumnName(i)));
            System.out.println("=========");

        }
    }
    }
}

明天封装增删改查!!!!

posted @ 2021-08-30 19:22  张三疯321  阅读(22)  评论(0)    收藏  举报