zoukankan      html  css  js  c++  java
  • Java JDBC

    一、介绍

      JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用java语言编写的类和接口组成。
      有了JDBC,向各种关系数据发送SQL语句就是一件很容易的事。换言之,有了JDBC API,就不必为访问Sybase数据库专门写一个程序,为访问Oracle数据库又专门写一个程序,或为访问Informix数据库又编写另一个程序等等,程序员只需用JDBC API写一个程序就够了,它可向相应数据库发送SQL调用。

    二、JDBC 的开发步骤

    1)注册驱动:主要告诉 JVM 我们的程序将要使用哪一种数据库
    2)获取连接:使用 JDBC 中的类,获得数据库的连接对象 Connection
    3)获得语句执行平台:通过 Connection 可以获取执行者对象,Statement、PreparedStatement.
    4)执行 SQL 语句:使用执行者对象,向数据库中执行 SQL 语句,然后可以得到对应的接口,有单个结果,也可能有结果集 ResultSet。
    5)处理结果
    6)释放对象:关闭顺序:rs -> stmt 、ptmt -> conn

    演示代码:

     1 public static void main(String[] args) {
     2         // 提示用户输入用户名和密码
     3         Scanner sc = new Scanner(System.in);
     4 
     5         System.out.println("请输入用户名:");
     6         String name = sc.nextLine();
     7 
     8         System.out.println("请输入密码:");
     9         String pwd = sc.nextLine();
    10 
    11         Connection conn = null;
    12         PreparedStatement pstmt = null;
    13         ResultSet rs = null;
    14         try {
    15 
    16             // 1. 加载驱动
    17             Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
    18 
    19             // 2. 获取连接
    20             conn = DriverManager.getConnection("jdbc:sqlserver://localhost:1433;databaseName=testdb", "sa", "123456");
    21 
    22             // 3. 利用conn,创建一个可以执行SQL语句的对象
    23             String sql = "select * from userinfo where uname=? and upwd=?";
    24             pstmt = conn.prepareStatement(sql);
    25 
    26             // 执行Sql语句之前,先给“?”号赋值。
    27             pstmt.setString(1, name);
    28             pstmt.setString(2, pwd);
    29 
    30             // 执行查询,不需要再给SQL语句
    31             rs = pstmt.executeQuery();
    32 
    33             if (rs.next()) {// 有了
    34                 System.out.println("登陆成功!");
    35             } else {
    36                 System.out.println("登陆失败!");
    37             }
    38             while(rs.next()){//指针下移
    39                 int uid = rs.getInt("uid");
    40                 String uname = rs.getString("uname");
    41                 String upwd = rs.getString("upwd");
    42                 float umoney = rs.getFloat("umoney");
    43                 
    44                 System.out.println(uid+"	"+uname+"	"+upwd+"	"+umoney);
    45             }
    46 
    47         } catch (Exception e) {
    48             e.printStackTrace();
    49         } finally {
    50             try {
    51                 rs.close();
    52                 pstmt.close();
    53                 conn.close();
    54             } catch (Exception e2) {
    55                 e2.printStackTrace();
    56             }
    57         }
    58     }

    四、抽取 JDBC 工具类

       在实际开发中,我们经常会碰到一些重复的代码,比如在获取某些资源的时候,解析某些数据的时候,都是需要重复去做一些相似的动作,这个时候很有必要抽取这些重复的代码成一个工具类,方面后面的使用。

      很明显,我们每次操作数据库的,都需要连接数据库和关闭数据库,所有我们可以把数据库的连接和关闭都给抽取出来,作为公共部分。
    新建一个 JDBCUtil.java 类。

     1 public class JDBCUtils {
     2     // 重构:一旦发现代码用起来不是很爽的时候,一直有重复动作,必须想把饭抽取出来一个新的
     3     public JDBCUtils() {
     4     }
     5  
     6     public static Connection conn;
     7  
     8     // 静态块:在类初始化之后,会加载一次
     9     // 一般情况,我们会将一些常用的数据,放在静态块中进行加载
    10     // 加载完成之后,后面如果想要用的话,直接就可以用
    11     // 优点是,只会创建一次,不会重复创建良妃性能
    12     static {
    13         try {
    14             // 1.注册驱动
    15             Class.forName("com.mysql.jdbc.Driver");
    16             // 2.获取连接:数据库地址、用户名、密码 Connection
    17             String url = "jdbc:mysql://localhost:3306/test";
    18             String user = "root";
    19             String password = "root";
    20             conn = DriverManager.getConnection(url, user, password);
    21         } catch (Exception e) {
    22             e.printStackTrace();
    23         }
    24     }
    25  
    26     /**
    27      * 获取 Connection 对象
    28      */
    29     public static Connection getConnection() {
    30         return conn;
    31     }
    32  
    33     /**
    34      * 释放资源
    35      */
    36     public static void close(Statement stmt, Connection conn) {
    37         // 思路:在关闭资源之前,先要判断,到底有没有用到这个资源
    38         if (stmt != null) {
    39             try {
    40                 stmt.close();
    41             } catch (SQLException e) {
    42                 e.printStackTrace();
    43             }
    44         }
    45         if (conn != null) {
    46             try {
    47                 conn.close();
    48             } catch (SQLException e) {
    49                 e.printStackTrace();
    50             }
    51         }
    52     }
    53  
    54     public static void close(ResultSet rs, Statement stmt, Connection conn) {
    55         if (rs != null) {
    56             try {
    57                 rs.close();
    58             } catch (SQLException e) {
    59                 e.printStackTrace();
    60             }
    61         }
    62         if (stmt != null) {
    63             try {
    64                 stmt.close();
    65             } catch (SQLException e) {
    66                 e.printStackTrace();
    67             }
    68         }
    69         if (conn != null) {
    70             try {
    71                 conn.close();
    72             } catch (SQLException e) {
    73                 e.printStackTrace();
    74             }
    75         }
    76     }
    77  
    78 }

    改写上面的类:(可以发现抽出公共部分之后,以后每次写的代码都会大大减少)

    @Test
    public void fun2() throws Exception {
        // 1.获取数据库连接
        Connection conn = JDBCUtils.getConnection();
     
        // 2.准备 SQL 语句
        String sql = "select * from product";
        
        // 3.获取执行者对象
        Statement stmt = conn.createStatement();
     
        // 4.执行 SQL 语句
        ResultSet rs = stmt.executeQuery(sql);
     
        // 5.处理结果
        while (rs.next()) {
            int idStr = rs.getInt("id");
            String nameStr = rs.getString("name");
            double priceStr = rs.getDouble("price");
            String markStr = rs.getString("mark");
            System.out.println(idStr + "--" + nameStr + "--" + markStr);
        }
     
        // 6.关闭资源
        JDBCUtils.close(rs, stmt, conn);
    }

    五、SQL 的注入

    SELECT * FROM product WHERE NAME = '伊利牛奶' AND price= 3.5
    使用 PreparedStatement 对象,可以预防SQL 注入和提高 SQL 的预编译。

     1 @Test
     2 public void fun3() throws Exception {
     3     // 1.获取数据库连接
     4     Connection conn = JDBCUtils.getConnection();
     5  
     6     // 2. 获取执行者对象
     7     // 如果使用 Statement 的话,则有可能会被 SQL 注入破坏
     8     // Statement stmt = conn.createStatement();
     9     // 推荐使用 PreparedStatement,它是 Statement 的子类,
    10     // 可以预防 SQL 注入,而且还可以把我们的 SQL 语句进行预初始化
    11  
    12     // 3. 准备 SQL 语句
    13     String sql = "select * from product where NAME = ? and price = ?";
    14     PreparedStatement ptmt = conn.prepareStatement(sql);
    15     // 这里的 1和2 表示的 where 后面的第n个属性
    16     ptmt.setString(1, "伊利牛奶");
    17     ptmt.setDouble(2, 3.5);
    18  
    19     // 4. 执行 SQL 语句
    20     ResultSet rs = ptmt.executeQuery();
    21  
    22     // 5. 处理结果
    23     while (rs.next()) {
    24         int idStr = rs.getInt("id");
    25         String nameStr = rs.getString("NAME");
    26         String passStr = rs.getString("price");
    27         System.out.println(idStr + "--" + nameStr + "--" + passStr);
    28     }
    29  
    30     // 6. 关闭资源
    31     JDBCUtils.close(rs, ptmt, conn);
    32 }

    六、PreparedStatement 的简单使用

    主要演示了“修改”功能,至于其他的功能,有时间再自己实践下。

     1 @Test
     2 public void fun4() throws Exception {
     3  
     4     // 1.获取数据库连接
     5     Connection conn = JDBCUtils.getConnection();
     6  
     7     // 2. 准备 SQL 语句
     8     String sql = "update product set name = ?, price = ? where id = ?";
     9  
    10     PreparedStatement ptmt = conn.prepareStatement(sql);
    11  
    12     ptmt.setString(1, "奥特曼");
    13     ptmt.setString(2, "49.8");
    14     ptmt.setInt(3, 1);
    15  
    16     // 3. 执行 SQL 语句
    17     // 此处的返回值是 int 类型,如果有一条数据发生改变的话,则返回 1
    18     int i = ptmt.executeUpdate();
    19  
    20     // 4. 处理结果
    21     if (i == 1) {
    22         System.out.println("恭喜你,修改成功了...");
    23     }
    24  
    25     // 6. 关闭资源
    26     JDBCUtils.close(ptmt, conn);
    27 }

     七、封装数据

    如果要封装数据的话,则需要新建一个对应的 JavaBean 类
    如果要提供一个 JavaBean 的话,需要满足三个条件:、
    1)实现序列化接口
    2)提供字段
    3)提供字段对应的 get 和 set 方法
    注意: JavaBean 的命名,最好和对应的数据表一致。主要为了更好体现类与表的映射关系。

     1 public class Product {
     2     private int id;
     3     private String NAME;
     4     private double price;
     5     private String mark;
     6     
     7     public Product(int id, String nAME, double price, String mark) {
     8         super();
     9         this.id = id;
    10         NAME = nAME;
    11         this.price = price;
    12         this.mark = mark;
    13     }
    14     public int getId() {
    15         return id;
    16     }
    17     public void setId(int id) {
    18         this.id = id;
    19     }
    20     public String getNAME() {
    21         return NAME;
    22     }
    23     public void setNAME(String nAME) {
    24         NAME = nAME;
    25     }
    26     public double getPrice() {
    27         return price;
    28     }
    29     public void setPrice(double price) {
    30         this.price = price;
    31     }
    32     public String getMark() {
    33         return mark;
    34     }
    35     public void setMark(String mark) {
    36         this.mark = mark;
    37     }
    38 }

    查询所有数据:

     1 /**
     2  * 封装数据
     3  * @throws Exception
     4  */
     5 @Test
     6 public void fun5() throws Exception {
     7     
     8     // 1. 获取数据库连接
     9     Connection conn = JDBCUtils.getConnection();
    10     
    11     // 2. 准备 SQL 语句
    12     String sql = "select * from product";
    13     
    14     PreparedStatement ptmt = conn.prepareStatement(sql);
    15     
    16     // 3. 执行 SQL 语句
    17     ResultSet rs = ptmt.executeQuery();
    18     
    19     // 4. 创建一个集合,用来保存查询出来的对象实例
    20     // 菱形语法,在泛型中,用来指定集合中存储的内容类型
    21     List<Product> proList = new ArrayList<Product>();
    22     
    23     // 5. 处理结果
    24     while (rs.next()){
    25         // 5.1 获取目标对象的实例,可以通过有参构造器
    26         int id = rs.getInt("id");
    27         String name = rs.getString("name");
    28         double price = rs.getDouble("price");
    29         String mark = rs.getString("mark");
    30         Product pro = new Product(id, name, price, mark);
    31         proList.add(pro);
    32     }
    33     
    34     // 5.2 查看保存数据的集合
    35     for (Product pro : proList) {
    36         System.out.println("商品的名字是:" + pro.getNAME());
    37     }
    38     
    39     // 6. 关闭资源
    40     JDBCUtils.close(rs, ptmt, conn);
    41 }

    八、Properties 配置文件

      在实际开发中,我们一般情况下,会把配置相关的信息,放在 xx.properties 中保存,并且使用。因为,以后代码有可能写的非常复杂,像一些不经常改动的东西,都建议抽取出来保存到配置文件中。当我们要用的时候,直接从配置文件中获取使用。当我们需要修改的时候,显示找到文件,然后就可以直接修改即可。很方便的。
      一般情况下,都是写死的内容,不会经常改动的。

    8.1 编写 jdbc.properties 文件

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

    8.2 重写 JDBCUtils.java

      1 public class JDBCUtils2 {
      2     public JDBCUtils2() {
      3     }
      4  
      5     public static Connection conn;
      6  
      7     private static String driver;
      8     private static String url;
      9     private static String user;
     10     private static String password;
     11  
     12     static {
     13         try {
     14             // 0.加载配置文件,获取对应的信息
     15             readConfig();
     16             // 1.注册驱动
     17             Class.forName(driver);
     18             // 2.获取连接:数据库地址、用户名、密码 Connection
     19             conn = DriverManager.getConnection(url, user, password);
     20         } catch (Exception e) {
     21             e.printStackTrace();
     22         }
     23     }
     24  
     25     /**
     26      * 用来加载配置文件
     27      * 
     28      * source folder 在部署之后,他的路径就是 bin 路径,也就是 classes 类资源路径
     29      * 
     30      * @throws IOException
     31      */
     32     public static void readConfig() throws IOException {
     33         // 1.找到文件,并且加载文件
     34         InputStream is = JDBCUtils2.class.getClassLoader().getResourceAsStream("jdbc.properties");
     35         System.out.println("is 的值:" + is);
     36  
     37         // 2.从文件中获取数据
     38         Properties pro = new Properties();
     39  
     40         // 3.通过输入流加载数据
     41         pro.load(is);
     42  
     43         // 4.当获取到数据之后,应该把数据赋值给上面的变量
     44         driver = pro.getProperty("driver");
     45         url = pro.getProperty("url");
     46         user = pro.getProperty("user");
     47         password = pro.getProperty("password");
     48     }
     49  
     50     /**
     51      * 获取 Connection 对象
     52      */
     53     public static Connection getConnection() {
     54         return conn;
     55     }
     56  
     57     /**
     58      * 释放资源
     59      */
     60     public static void close(Statement stmt, Connection conn) {
     61         // 思路:在关闭资源之前,先要判断,到底有没有用到这个资源
     62         if (stmt != null) {
     63             try {
     64                 stmt.close();
     65             } catch (SQLException e) {
     66                 e.printStackTrace();
     67             }
     68         }
     69         if (conn != null) {
     70             try {
     71                 conn.close();
     72             } catch (SQLException e) {
     73                 e.printStackTrace();
     74             }
     75         }
     76     }
     77  
     78     public static void close(ResultSet rs, Statement stmt, Connection conn) {
     79         if (rs != null) {
     80             try {
     81                 rs.close();
     82             } catch (SQLException e) {
     83                 e.printStackTrace();
     84             }
     85         }
     86         if (stmt != null) {
     87             try {
     88                 stmt.close();
     89             } catch (SQLException e) {
     90                 e.printStackTrace();
     91             }
     92         }
     93         if (conn != null) {
     94             try {
     95                 conn.close();
     96             } catch (SQLException e) {
     97                 e.printStackTrace();
     98             }
     99         }
    100     }
    101 }

    九、整篇博客用到的 Java 代码打包地址:

    https://github.com/yyzheng1729/JDBC

  • 相关阅读:
    ElementUI 组件不支持@keyup 的解决办法
    ElementUI 实现头部组件和左侧组件效果
    ElementUI 整体页面布局
    vue路由登录拦截
    vue中使用localStorage存储信息
    ElementUI Checkbox 多选框
    vue拦截器qs
    (未完)经典Web漏洞实战演练靶场笔记
    文件包含漏洞实战靶场笔记
    文件解析漏洞总结
  • 原文地址:https://www.cnblogs.com/BalmyLee/p/10716079.html
Copyright © 2011-2022 走看看