• JDBC知识点总结


    一:JDBC 概述

        一、简介

           1. JDBC(Java DataBase Connection,Java 数据库连接)Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。

           2. JDBC 是一个标准 SQL(Structured Query Language,结构化查询语言)数据库访问接口,可以为多种关系数据库提供统一访问。也提供一种基准,据此可以构建更高级的工具和接口。

           3. JDK(Java Development Kit,Java 开发工具包)软件捆绑包括 JDBC 和 JDBC-ODBC(Open DataBase Connection,开放式数据库连接)桥。

              

        二、API

         

    二:JDBC 开发步骤

        一、配置依赖 jar 包

           1. 下载

               1. MySQL

                  

               2. Oracle

                  

           2. 配置

               1. 导入 jar 包

                  

               2. Maven 配置

     1 <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
     2 <dependency>
     3     <groupId>mysql</groupId>
     4     <artifactId>mysql-connector-java</artifactId>
     5     <version>8.0.20</version>
     6 </dependency>
     7 
     8 <!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc10 -->
     9 <dependency>
    10     <groupId>com.oracle.database.jdbc</groupId>
    11     <artifactId>ojdbc10</artifactId>
    12     <version>19.3.0.0</version>
    13 </dependency>

        二、注册驱动

     1 public class DriverTest {
     2     /**
     3      * 通过反射机制,加载数据库驱动,类初始化的时候执行静态代码块
     4      *   优点1:此方式由于参数为字符串,因此很容易修改,移植性强。
     5      *   优点2:不依赖特定的Driver库,很容易改造成从配置文件读取JDBC配置,从而可以在运行时动态更换数据库连接驱动。
     6      */
     7     static {
     8         try {
     9             /**
    10              * MySQL:8.0版本,5.0版本为:com.mysql.jdbc.Driver
    11              */
    12             Class.forName("com.mysql.cj.jdbc.Driver");
    13             
    14             /**
    15              * Oracle
    16              */
    17             Class.forName("oracle.jdbc.driver.OracleDriver");
    18         } catch (ClassNotFoundException e) {
    19             // TODO Auto-generated catch block
    20             e.printStackTrace();
    21         } // 8版本
    22     }
    23 }

        三、获取连接

     1 public class ConnectionTest {
     2     /**
     3      * MySQL
     4      */
     5     public Connection getMysqlConnection() {
     6         // 本地连接URL:jdbc:mysql:///student?useUnicode=true&characterEnocding=utf-8&useSSL=false&serverTimezone=UTC
     7         // 远程连接URL:jdbc:mysql://<host>:<port>/<database>?useUnicode=true&characterEnocding=utf-8&useSSL=false&serverTimezone=UTC
     8         final String url = "jdbc:mysql:///student?useUnicode=true&characterEnocding=utf-8&useSSL=false&serverTimezone=UTC";
     9         // 连接用户名
    10         final String user = "root";
    11         // 连接密码
    12         final String password = "000000";
    13         Connection conn = null;
    14         if (conn == null) {
    15             try {
    16                 conn = DriverManager.getConnection(url, user, password);
    17             } catch (SQLException e) {
    18                 // TODO Auto-generated catch block
    19                 System.err.println("Oracle数据库连接出错");
    20                 e.printStackTrace();
    21             }
    22         }
    23         return conn;
    24     }
    25 
    26     /**
    27      * Oracle
    28      */
    29     public Connection getOracleConnection() {
    30         /**
    31          * 1. 使用thin连接:jdbc:oracle:thin:@<host>:<port>:<database>
    32          *    优点:thin完全由Java代码编写,与平台无关,不需要Oracle客户端。
    33          *    缺点:thin性能一般,达不到如OCI方式的企业级的要求,一般适合一台主机连接。
    34          * 
    35          * 2. 使用oci连接:jdbc:oracle:oci:@<host>:<port>:<database>
    36          *    优点:用OCI连接数据库是企业级的做法,适应于单个数据库和集群数据库,性能优越,尤其是连接池功能大大提高了应用程序的性能和并发量。
    37          *    缺点:若想使用OCI必须要安装Oracle客户端。
    38          */
    39         final String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
    40         // 连接用户名
    41         final String user = "scott";
    42         // 连接密码
    43         final String password = "tiger";
    44         // 连接对象
    45         Connection conn = null;
    46         if (conn == null) {
    47             try {
    48                 conn = DriverManager.getConnection(url, user, password);
    49             } catch (SQLException e) {
    50                 // TODO Auto-generated catch block
    51                 System.err.println("Oracle数据库连接出错");
    52                 e.printStackTrace();
    53             }
    54         }
    55         return conn;
    56     }
    57 }

        四、创建Statement、PreparedStatement、CallableStatement接口,执行SQL语句

     1 package pers.mj.test;
     2 
     3 import java.sql.CallableStatement;
     4 import java.sql.Connection;
     5 import java.sql.PreparedStatement;
     6 import java.sql.ResultSet;
     7 import java.sql.SQLException;
     8 import java.sql.Statement;
     9 import java.sql.Types;
    10 
    11 public class MysqJDBClTest {
    12     /**
    13      * Statement 的作用:用于执行静态 SQL 语句并返回它所生成结果的对象,完成对数据库的增删改查。
    14      * Statement 的优点:语法简单,对于只执行一次的 SQL 语句,使用 Statement 比 PreparedStatement 对象的开销更小。
    15      * Statement 的缺点:每次执行时相似SQL都会进行编译  ,采用硬编码效率低,安全性较差,字符串拼接方式的 SQL 语句是非常繁琐的,中间有很多的单引号和双引号的混用,极易出错。
    16      * Statement 的适用场景:普通的不带参的查询SQL 
    17      */
    18     public void testStatement() {
    19         try {
    20             // 获取数据库连接
    21             Connection conn = DBUtil.getMysqlConnection();
    22             // 创建 Statement 对象
    23             Statement st = conn.createStatement();
    24             // 定义SQL语句
    25             String sql = "insert into student(stu_id, stu_name) values(20200626, " + " '张三')"; // 字符串拼接麻烦
    26             /**
    27              * 演示SQL注入问题:如果此时传递给字段的值为:or 1 = 1,那么不论如何条件都成立,导致结果都成功,这就是SQL注入
    28              */
    29             String SQL = "select * from student where stu_name="+"'张三' and stu_id= "+"'or 1 = 1' ";
    30             // 执行SQL语句
    31             if (st.execute(sql)) {
    32                 System.out.println("信息插入成功");
    33             }
    34         } catch (SQLException e) {
    35             System.err.println("插入语句执行失败");
    36             e.printStackTrace();
    37         }
    38     }
    39     
    40     /**
    41      * PreparedStatement 的作用:用于执行动态 SQL 语句并返回它所生成结果的对象,完成对数据库的增删改查。继承Statement
    42      * PreparedStatement 的优点:相似SQL只编译一次,减少编译次数,代码的可读性和可维护性更高,提高了安全性(阻止了SQL注入)。
    43      * PreparedStatement 的缺点:执行非相似SQL语句时,速度较慢。
    44      * PreparedStatement 的适用场景:支持可变参数的SQL 
    45      */
    46     public void testPreparedStatement() {
    47         try {
    48             // 获取数据库连接
    49             Connection conn = DBUtil.getMysqlConnection();
    50             // 定义SQL语句
    51             String sql = "insert into student(stu_id, stu_name) values(?, ?)"; 
    52             /**
    53              * 解决SQL注入问题:PreparedStatement不是将参数简单拼凑成sql,而是做了一些预处理,将参数转换为string,两端加单引号,将参数内的一些特殊字符(换行,单双引号,斜杠等)做转义处理,这样就很大限度的避免了sql注入。
    54              */
    55             String SQL = "select * from student where stu_name=? and stu_id= ? ";
    56             // 预编译SQL语句,防止SQL注入
    57             PreparedStatement ps = conn.prepareStatement(sql);
    58             // 给占位符(?)赋值:索引从1开始,数据类型需要相对应
    59             ps.setInt(1, 20180627);
    60             ps.setString(2, "李四");
    61             // 执行SQL语句
    62             if (ps.execute()) {
    63                 System.out.println("信息插入成功");
    64             }
    65         } catch (SQLException e) {
    66             System.err.println("插入语句执行失败");
    67             e.printStackTrace();
    68         }
    69     }
    70     
    71     /**
    72      * CallableStatement 的作用:实现了存储过程函数调用的方法以及对于输出的处理。继承PreparedStatement
    73      * CallableStatement 的使用场景:支持调用存储过程,提供了对输出和输入/输出参数(INOUT)的支持
    74      */
    75     public void testCallableStatement(){
    76         try {
    77             // 获取数据库连接
    78             Connection conn = DBUtil.getMysqlConnection();
    79             // 定义SQL语句
    80             String sql = "call p3(?,?)";
    81             // 预编译SQL
    82             CallableStatement cs = conn.prepareCall(sql);
    83             // 给站位符赋值
    84             cs.setString(1, "王五"); 
    85             cs.registerOutParameter(2, Types.INTEGER);  // 注册一个输入参数
    86             // 执行SQL
    87             cs.execute();
    88             // 获取结果集对象
    89             ResultSet resultSet = cs.getResultSet();
    90             while (resultSet.next()) {
    91                 System.out.println(resultSet.getString("name")+" ");                
    92             }
    93             // 获取输出参数
    94             System.out.println(cs.getInt(2));
    95         } catch (Exception e) {
    96             // TODO: handle exception
    97         }
    98     }
    99 }

        五、execute、executeQuery和executeUpdate详解

      1 public class ExecuteTest {
      2     // 数据库连接对象
      3     Connection conn = null;
      4     // 预处理对象
      5     PreparedStatement ps = null;
      6     // 结果集对象
      7     ResultSet rs = null;
      8     
      9     /**
     10      * executeQuery()
     11      *   作用:只能执行DQL(SELECT语句),是使用最多的查询语句。
     12      *   返回值:单个结果及对象(ResultSet)
     13      */
     14     public void testExecuteQuery() {
     15         try {
     16             // 获取数据库连接
     17             conn = DBUtil.getMysqlConnection();
     18             // 定义SQL语句
     19             String sql = "SELECT stu_id,stu_name FROM student WHERE stu_id=? ";
     20             // 预编译SQL
     21             ps = conn.prepareStatement(sql);
     22             // 给占位符赋值
     23             ps.setInt(1, 20200626);
     24             // 执行SQL语句
     25             rs = ps.executeQuery();
     26             while (rs.next()) {
     27                 System.out.println("学号:" + rs.getInt("stu_id") + " 姓名:" + rs.getString("stu_name"));
     28             }
     29         } catch (Exception e) {
     30             // TODO: handle exception
     31         }
     32     }
     33 
     34     /**
     35      * executeUpdate()
     36      *   作用:执行DML(除去SELECT语句)和DDL,修改表中零行或多行中的一列或多列。
     37      *   返回值:受影响的行数(整数)
     38      */
     39     @Test
     40     public void testExecuteUpdate() {
     41         try {
     42             // 获取数据库连接
     43             conn = DBUtil.getMysqlConnection();
     44             // 定义SQL语句
     45             String sql = "UPDATE student SET stu_name=? WHERE stu_id=?";
     46             // 预编译SQL
     47             ps = conn.prepareStatement(sql);
     48             // 给占位符赋值
     49             ps.setString(1, "王五");
     50             ps.setInt(2, 20200626);
     51             // 执行SQL语句
     52             if (ps.executeUpdate() != 0) {
     53                 System.out.println("信息修改成功");
     54             }
     55         } catch (Exception e) {
     56             // TODO: handle exception
     57         }
     58     }
     59 
     60     /**
     61      * execute()
     62      *   作用:用于执行返回多个结果集、多个更新计数或二者组合的语句。例如:执行某个已存储过程或动态执行未知 SQL 字符串。
     63      *   返回值:多个ResultSet对象、多个更新计数或ResultSet对象与更新计数。
     64      *   使用
     65      *    多个结果集
     66      *      1. 执行完execute()方法后,使用CallableStatement对象调用getResultSet()方法获取第一个结果集,调用适当的getXXX方法获取值
     67      *      2. 如果存在第二个结果集,则必须调用getMoreResults()方法,然后再调用getResultSet()方法来获取结果集,依次类推。
     68      *    多个更新计数
     69      *      1. 执行完execute()方法后,则首先调用方法 getUpdateCount,然后调用 getMoreResults,并再次调用 getUpdateCount,依次类推。
     70      *   
     71      */
     72     public void testExecute() {
     73         List<List<Map<String, Object>>> resultList = new ArrayList<>();
     74         try {
     75             // 获取数据库连接
     76             conn = DBUtil.getMysqlConnection();
     77             // 定义SQL语句
     78             String sql = "sp_help 'test.student'";
     79             // 预编译SQL
     80             CallableStatement cs = conn.prepareCall(sql);
     81              // 外循环获取结果集的个数
     82             boolean oprFlg  = cs.execute(sql);
     83             while (oprFlg) {
     84                 List<Map<String, Object>> result = new ArrayList<>();
     85                 // 获取第一个结果集
     86                 rs = cs.getResultSet();
     87                 // 内循环获取每个结果集的记录
     88                 while (rs.next()) {
     89                     ResultSetMetaData rsmd = rs.getMetaData();
     90                     int columnCount = rsmd.getColumnCount();
     91                     Map<String, Object> map = new HashMap<String, Object>();
     92                     for (int i = 0; i < columnCount; i++) {
     93                         map.put(rsmd.getColumnName(i + 1).toLowerCase(), rs.getObject(i + 1));
     94                     }
     95                     result.add(map);
     96                 }
     97                 resultList.add(result);
     98                 // 获取更多的结果集
     99                 oprFlg = cs.getMoreResults();
    100             }
    101         } catch (Exception e) {
    102             // TODO: handle exception
    103         }
    104     }

        六、处理结果集

          1. ResultSet:在线

     1 public class ResultSetTest {
     2     // 数据库连接对象
     3     Connection conn = null;
     4     // 预处理对象
     5     PreparedStatement ps = null;
     6     // 结果集对象
     7     ResultSet rs = null;
     8 
     9     /**
    10      * 可滚动,可更新
    11      *    ResultSet.TYPE_FORWARD_ONLY:该常量控制ResultSet记录指针只能向前移动(默认)。
    12      *    ResultSet.TYPE_SCROLL_INSENSITIVE:该常量控制ResultSet记录指针可以自由移动(可滚动结果集),但底层数据的改变不会受ResultSet的内容。
    13      *    ResultSet.TYPE_SCROLL_SENSITIVE:该常量控制ResultSet记录指针可以自由移动(可滚动结果集),并且底层数据的改变会影响ResultSet的内容。
    14      *    ResultSet.CONCUR_READ_ONLY:该常量指示ResultSet是只读的并发模式(默认)。
    15      *    ResultSet.CONCUR_UPDATABLE: 该常量指示ResultSet是可更新的并发默认。
    16      *   
    17      */
    18     public void testScrollAndUpdate() {
    19         try {
    20             // 获取数据库连接
    21             conn = DBUtil.getMysqlConnection();
    22             // 定义SQL语句
    23             String sql = "SELECT stu_id,stu_name FROM student";
    24             // 预编译SQL
    25             ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
    26             // 执行SQL语句
    27             rs = ps.executeQuery();
    28             // 处理结果集
    29             while (rs.next()) {
    30                 System.out.println("学号:" + rs.getInt("stu_id") + " 姓名:" + rs.getString("stu_name"));
    31             }
    32         } catch (Exception e) {
    33             // TODO: handle exception
    34         }
    35     }
    36     
    37     /**
    38      * ResultSetMetaData:分析结果集,当不清楚该ResultSet里包含哪些数据列,以及每个数据列的数据类型,那么可以通过ResultSetMetaData来获取关于ResultSet的描述信息。
    39      *   getMetaData():获取ResultSetMetaData对象。
    40      *   int getColumnCount():返回该ResultSet的列数量。
    41      *   String getColumnName(int columnIndex):返回对应列的名称。
    42      *   int getColumnType(int columnIdex):返回对应列的数据类型。
    43      */
    44     public void testResultSetMetaData() {
    45         try {
    46             // 获取数据库连接
    47             conn = DBUtil.getMysqlConnection();
    48             // 定义SQL语句
    49             String sql = "SELECT stu_id,stu_name FROM student";
    50             // 预编译SQL
    51             ps = conn.prepareStatement(sql);
    52             // 执行SQL语句
    53             rs = ps.executeQuery();
    54             // 处理结果集
    55             while (rs.next()) {
    56                 // 获取结果集元数据对象
    57                 ResultSetMetaData rsmd = rs.getMetaData();
    58                 // 获取结果集列数
    59                 int columnCount = rsmd.getColumnCount();
    60                 for (int i = 0; i < columnCount; i++) {
    61                     // 获取结果集对应列名称
    62                     System.out.println(rsmd.getColumnName(i + 1));
    63                     // 获取结果集对应数据类型
    64                     System.out.println(rsmd.getColumnType(i + 1));
    65                 }
    66             }
    67         } catch (Exception e) {
    68             // TODO: handle exception
    69         }
    70     }
    71 }

          2. RowSet:离线

      1 public class RowSetTest {
      2     // 数据库连接对象
      3     Connection conn = null;
      4     // 预处理对象
      5     PreparedStatement ps = null;
      6     // 结果集对象
      7     ResultSet rs = null;
      8 
      9     /**
     10      * RowSet:实现了ResultSet接口,并且有子接口CachedRowSet(离线查询)
     11      *   概念:离线查询:在本地搞一个结果集的副本,关闭结果集、数据库连接,使用本地的这个副本。
     12      *   作用:RowSet默认是可滚动,可更新,可序列化的结果集,并且作为对JavaBean使用,因此能方便地在网络上传输,用于同步两端的数据。
     13      *   优点:程序在创建RowSet时已把底层数据读取到了内存中,因此可以充分利用计算机的内存,从而减低数据库的负载,提高程序的性能。
     14      */
     15     @Test
     16     public void testRowSetOffline() {
     17         try {
     18             // 获取数据库连接
     19             conn = DBUtil.getMysqlConnection();
     20             // 定义SQL语句
     21             String sql = "SELECT stu_id,stu_name FROM student";
     22             // 预编译SQL
     23             ps = conn.prepareStatement(sql);
     24             // 执行SQL语句
     25             rs = ps.executeQuery();
     26             /**
     27              * 离线查询
     28              */
     29             // 通过RowSetProvider的静态方法创建RowSetFactory对象
     30             RowSetFactory rsf = RowSetProvider.newFactory();
     31             // 创建CachedRowSet对象
     32             CachedRowSet crs = rsf.createCachedRowSet(); 
     33             // 使用结果集填充CachedRowSet
     34             crs.populate(rs); //  使用给定的ResultSet装填RowSet,从ResultSet的第startRow条记录开始装填。
     35             /**
     36              * 关闭数据库资源
     37              */
     38             rs.close();
     39             ps.close();
     40             conn.close();
     41             // 离线处理结果集:CachedRowSet是ResultSet的孙接口,使用的方法都相同。
     42             while (crs.next()) {
     43                 System.out.println("学号:" + crs.getInt("stu_id") + " 姓名:" + crs.getString("stu_name"));
     44             }
     45         } catch (Exception e) {
     46             // TODO: handle exception
     47         }
     48     }
     49     
     50     /**
     51      * 分页:不推荐使用每个数据库特有的分页,追求跨数据库,代码可用性更高
     52      *   1. 使用游标实现
     53      *   2. 使用离线查询实现
     54      */
     55     public void pagination() {
     56         try {
     57             /**
     58              * 使用游标实现
     59              */
     60             // 获取数据库连接
     61             conn = DBUtil.getMysqlConnection();
     62             // 定义SQL语句
     63             String sql = "SELECT stu_id,stu_name FROM student";
     64             // 预编译SQL
     65             ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
     66             // 执行SQL语句
     67             rs = ps.executeQuery();
     68             // 定义分页
     69             int start = 0;  // 起始页
     70             int pageSize = 10;  // 分页大小
     71             // 定义游标
     72             rs.absolute(start);  // 游标指向起始位
     73             while (rs.next()) {
     74                 // ......
     75                 if (rs.getRow() == pageSize) { // getRow()是获取当前记录是结果集中的第几条记录,第一条就是1。也可以设置计数器来判断
     76                     break;
     77                 }
     78             }
     79             
     80             /**
     81              * 使用离线查询实现
     82              */
     83             // 创建RowSetFactory对象
     84             RowSetFactory rsf = RowSetProvider.newFactory();
     85             // 创建CachedRowSet对象
     86             CachedRowSet crs = rsf.createCachedRowSet(); 
     87             // 设置分页大小
     88             crs.setPageSize(10);
     89             // 使用结果集填充CachedRowSet
     90             crs.populate(rs);
     91             // 释放资源
     92             rs.close();
     93             ps.close();
     94             conn.close();
     95             while (crs.next()) {
     96                 // ......
     97             }
     98         } catch (Exception e) {
     99             // TODO: handle exception
    100         }
    101     }
    102 }

       

        七、释放资源

     1 public class CloseTest {
     2     // 数据库连接对象
     3     Connection conn = null;
     4     // 预处理对象
     5     PreparedStatement ps = null;
     6     // 结果集对象
     7     ResultSet rs = null;
     8 
     9     /**
    10      * 手动释放
    11      */
    12     public void handMovement() {
    13         try {
    14             // 获取数据库连接
    15             conn = DBUtil.getMysqlConnection();
    16             // 定义SQL语句
    17             String sql = "SELECT stu_id,stu_name FROM student ";
    18             // 预编译SQL
    19             ps = conn.prepareStatement(sql);
    20             // 执行SQL语句
    21             rs = ps.executeQuery();
    22             // 处理结果集
    23             while (rs.next()) {
    24                 System.out.println("学号:" + rs.getInt("stu_id") + " 姓名:" + rs.getString("stu_name"));
    25             }
    26         } catch (Exception e) {
    27             // TODO: handle exception
    28         } finally {
    29             if (rs != null) {
    30                 try {
    31                     rs.close();
    32                 } catch (SQLException e) {
    33                     // TODO Auto-generated catch block
    34                     e.printStackTrace();
    35                 }
    36             }
    37             if (ps != null) {
    38                 try {
    39                     ps.close();
    40                 } catch (SQLException e) {
    41                     // TODO Auto-generated catch block
    42                     e.printStackTrace();
    43                 }
    44             }
    45             if (conn != null) {
    46                 try {
    47                     conn.close();
    48                 } catch (SQLException e) {
    49                     // TODO Auto-generated catch block
    50                     e.printStackTrace();
    51                 }
    52             }
    53         }
    54     }
    55 
    56     /**
    57      * 自动释放
    58      */
    59     public void autoregula() {
    60         try(
    61             // 获取数据库连接
    62             conn = DBUtil.getMysqlConnection();
    63             // 定义SQL语句
    64             String sql = "SELECT stu_id,stu_name FROM student ";
    65             // 预编译SQL
    66             ps = conn.prepareStatement(sql);
    67             // 执行SQL语句
    68             rs = ps.executeQuery();
    69             // 处理结果集
    70             while (rs.next()) {
    71                 System.out.println("学号:" + rs.getInt("stu_id") + " 姓名:" + rs.getString("stu_name"));
    72             }    
    73           ){
    74         }catch (Exception e) {
    75             // TODO: handle exception
    76         }
    77     }
    78 }

    三:封装

        一、封装配置文件

     1 # MySQL
     2 mysql.jdbc.driver=com.mysql.cj.jdbc.Driver
     3 mysql.jdbc.url=jdbc:mysql://<host>:<port>/<database>?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&serverTimezone=UTC
     4 mysql.jdbc.username=<user>
     5 mysql.jdbc.password=<password>
     6 # Oracle
     7 oracle.jdbc.driver=oracle.jdbc.driver.OracleDriver
     8 oracle.jdbc.url=jdbc:oracle:thin:@<host>:<port>:<database>
     9 oracle.jdbc.username=<user>
    10 oracle.jdbc.password=<password>

        二、封装工具类

     1 public class DBUtil {
     2     /**
     3      * MySQL和Oracle连接属性
     4      */
     5     private static String mysqlDriver;
     6     private static String mysqlUrl;
     7     private static String mysqlUser;
     8     private static String mysqlPassword;
     9     private static String oracleDriver;
    10     private static String oracleUrl;
    11     private static String oracleUser;
    12     private static String oraclePassword;
    13 
    14     /**
    15      * 读取配置文件并加载驱动
    16      */
    17     private static Properties pros = new Properties();
    18     static {
    19         try {
    20             // 加载配置文件
    21             pros.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
    22             // 属性赋值
    23             mysqlDriver = pros.getProperty("mysql.jdbc.driver");
    24             mysqlUrl = pros.getProperty("mysql.jdbc.url");
    25             mysqlUser = pros.getProperty("mysql.jdbc.username");
    26             mysqlPassword = pros.getProperty("mysql.jdbc.password");
    27             oracleDriver = pros.getProperty("oracle.jdbc.driver");
    28             oracleUrl = pros.getProperty("oracle.jdbc.url");
    29             oracleUser = pros.getProperty("oracle.jdbc.username");
    30             oraclePassword = pros.getProperty("oracle.jdbc.password");
    31             // 注册驱动
    32             try {
    33                 Class.forName(mysqlDriver);
    34             } catch (ClassNotFoundException e) {
    35                 // TODO Auto-generated catch block
    36                 e.printStackTrace();
    37             }
    38         } catch (IOException e) {
    39             // TODO Auto-generated catch block
    40             e.printStackTrace();
    41         }
    42     }
    43 
    44     /**
    45      * 数据库连接
    46      */
    47     public static Connection getConnection(String dbManufacturer) {
    48         Connection conn = null;
    49         if (conn == null) {
    50             try {
    51                 if (dbManufacturer.startsWith("mysql")) {
    52                     conn = DriverManager.getConnection(mysqlUrl, mysqlUser, mysqlPassword);
    53                 } else {
    54                     conn = DriverManager.getConnection(oracleUrl, oracleUser, oraclePassword);
    55                 }
    56             } catch (Exception e) {
    57                 System.err.println("数据库连接出错,请检查");
    58             }
    59         }
    60         return conn;
    61     }
    62 
    63     /**
    64      * 释放资源
    65      */
    66     public static void release(Connection conn, PreparedStatement ps, ResultSet rs) {
    67         if (rs != null) {
    68             try {
    69                 rs.close();
    70             } catch (SQLException e) {
    71                 e.printStackTrace();
    72             }
    73         }
    74         if (ps != null) {
    75             try {
    76                 ps.close();
    77             } catch (SQLException e) {
    78                 e.printStackTrace();
    79             }
    80         }
    81         if (conn != null) {
    82             try {
    83                 conn.close();
    84             } catch (SQLException e) {
    85                 e.printStackTrace();
    86             }
    87         }
    88     }
    89 }

        三、封装查询和更新

      1 public class BaseDao<T> {
      2     /**
      3      * 封装增、删、改功能
      4      * 
      5      * @param sql  需要执行的sql语句
      6      * @param args 不定参数,是对sql语句中的占位符“?”传入的参数
      7      * @return 返回操作所影响的行数
      8      */
      9     public int executeUpdate(String sql, Object... args) {
     10         Connection conn = null;
     11         PreparedStatement ps = null;
     12         int rows = 0;
     13         try {
     14             conn = DBUtil.getConnection("mysql");
     15             ps = conn.prepareStatement(sql);
     16             for (int i = 0; i < args.length; i++) {
     17                 ps.setObject(i + 1, args[i]);
     18             }
     19             rows = ps.executeUpdate();
     20         } catch (SQLException e) {
     21             e.printStackTrace();
     22         } finally {
     23             DBUtil.release(conn, ps, null);
     24         }
     25         return rows;
     26     }
     27 
     28     /**
     29      * 查询一条记录
     30      * 
     31      * @param sql  需要执行的sql语句
     32      * @param cls  实体类对象类型,例如Student.class,如果类未知,则使用 Class<?>
     33      * @param args 不定参数,是对sql语句中的占位符“?”传入的参数
     34      * @return 返回操作所影响的行数
     35      */
     36     public T selectOne(String sql, Class<T> cls, Object... args) {
     37         List<T> list = this.selectMany(sql, cls, args);
     38         return list.isEmpty() ? null : list.get(0);
     39     }
     40 
     41     /**
     42      * 查询所有记录
     43      * 
     44      * @param sql  需要执行的sql语句
     45      * @param cls  实体类对象类型,例如Student.class,如果类未知,则使用 Class<?>
     46      * @param args 不定参数,是对sql语句中的占位符“?”传入的参数
     47      * @return 返回结果集
     48      */
     49     public List<T> selectMany(String sql, Class<T> cls, Object... args) {
     50         Connection conn = null;
     51         PreparedStatement ps = null;
     52         ResultSet rs = null;
     53         List<T> list = new ArrayList<T>();
     54         try {
     55             conn = DBUtil.getConnection("mysql");
     56             ps = conn.prepareStatement(sql);
     57             for (int i = 0; i < args.length; i++) {
     58                 ps.setObject(i + 1, args[i]);
     59                 rs = ps.executeQuery();
     60                 // 分析结果集对象
     61                 ResultSetMetaData metaData = rs.getMetaData();
     62                 while (rs.next()) {
     63                     T obj = cls.getDeclaredConstructor().newInstance();
     64                     // 获取结果集列数
     65                     for (int j = 1; j <= metaData.getColumnCount(); j++) {
     66                         // 获取结果集列名
     67                         String columnLabel = metaData.getColumnLabel(j);
     68                         // 动态拼接成该属性对应实体中的setter方法的方法名
     69                         String name = "set" + StringUtil.toUpper(columnLabel);
     70                         // 获取实体中所有声明的属性
     71                         Field field = cls.getDeclaredField(columnLabel);
     72                         // 获取实体中所有声明的方法,形参为field.getType()类型
     73                         Method method = cls.getDeclaredMethod(name, field.getType());
     74                         // 通过结果集获取字段值名
     75                         Object realParam = rs.getObject(columnLabel);
     76                         // 执行obj对象中的method方法,传入的实参为realParam
     77                         method.invoke(obj, realParam);
     78                     }
     79                     list.add(obj);
     80                 }
     81             }
     82         } catch (SQLException | InstantiationException | IllegalAccessException e) {
     83             e.printStackTrace();
     84         } catch (NoSuchMethodException e) {
     85             e.printStackTrace();
     86         } catch (SecurityException e) {
     87             e.printStackTrace();
     88         } catch (IllegalArgumentException e) {
     89             e.printStackTrace();
     90         } catch (InvocationTargetException e) {
     91             e.printStackTrace();
     92         } catch (NoSuchFieldException e) {
     93             e.printStackTrace();
     94         } finally {
     95             DBUtil.release(conn, ps, rs);
     96         }
     97         return list;
     98     }
     99 
    100     /**
    101      * 查询总记录数
    102      * 
    103      * @param sql  需要执行的sql语句
    104      * @param args 需要对sql语句中的占位符“?”传入的参数数组
    105      * @return 返回操作所影响的行数
    106      */
    107     public int selectCount(String sql, Object... args) {
    108         Connection conn = null;
    109         PreparedStatement ps = null;
    110         ResultSet rs = null;
    111         int count = 0;
    112         try {
    113             conn = DBUtil.getConnection("mysql");
    114             ps = conn.prepareStatement(sql);
    115             for (int i = 0; i < args.length; i++) {
    116                 ps.setObject(i + 1, args[i]);
    117                 rs = ps.executeQuery();
    118                 if (rs.next()) {
    119                     count = rs.getInt(1);
    120                 }
    121             }
    122         } catch (SecurityException e) {
    123             e.printStackTrace();
    124         } catch (IllegalArgumentException e) {
    125             e.printStackTrace();
    126         } catch (SQLException e) {
    127             e.printStackTrace();
    128         } finally {
    129             DBUtil.release(conn, ps, rs);
    130         }
    131         return count;
    132     }
    133 }
  • 相关阅读:
    <a>元素生成多个<a>的问题,元素标签结尾影响
    mysql不能插入中文数据
    java: Multiple encodings set for module chunk test "GBK" will be used by compiler
    过滤器第二篇【高级应用】
    过滤器第一篇【介绍、入门、简单应用】
    客户关系管理系统
    Mysql中文乱码
    用户登陆注册【JDBC版】
    Mysql的基本命令图
    购物车小案例【简单版】
  • 原文地址:https://www.cnblogs.com/mh20131118/p/13176479.html
Copyright © 2020-2023  润新知