一: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 }