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 }
posted @ 2020-06-23 15:53  萌萌哥的春天  阅读(1114)  评论(0编辑  收藏  举报