首页 > 代码库 > JDBC-自定义数据库工具类(DBService)
JDBC-自定义数据库工具类(DBService)
写在前面的话:
(1)使用JDBC,必须要使用对应的jar包,该笔记中使用jar包:mysql-connector-java-5.1 .6-bin.jar
(2)使用连接池,一定要导入对象的数据库连接池包,该笔记中使用jar包:c3p0-0.9.1.2.jar
常用连接池:dbcp连接池、c3p0连接池、druid连接池
第一版:不用数据库连接池:
1 package cn; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.PreparedStatement; 6 import java.sql.ResultSet; 7 import java.sql.ResultSetMetaData; 8 import java.sql.SQLException; 9 import java.util.ArrayList; 10 import java.util.HashMap; 11 import java.util.List; 12 import java.util.Map; 13 14 public class SqlService { 15 16 // 四大金刚 17 String driver = "com.mysql.jdbc.Driver" ;// 驱动名称 18 String url = "jdbc:mysql:///mao" ;// 连接字符串 19 String username = "root" ;// 用户名 20 String password = "123456" ;// 密码 21 22 // 三剑客 23 Connection con = null ;// 连接对象 24 PreparedStatement pstmt = null ;// 语句对象 25 ResultSet rs = null ;// 结果集对象 26 27 /** 28 * 获得连接对象 29 * 30 * @return 连接对象 31 * @throws ClassNotFoundException 32 * @throws SQLException 33 */ 34 public Connection getConnection() throws ClassNotFoundException, 35 SQLException { 36 Class. forName( driver); 37 con = DriverManager.getConnection( url , username , password ); 38 return con ; 39 } 40 41 /** 42 * 关闭三剑客 43 * 44 * @throws SQLException 45 */ 46 public void close(ResultSet rs, PreparedStatement pstmt, Connection con) { 47 48 try { 49 if (rs != null) 50 rs.close(); 51 if (pstmt != null) 52 pstmt.close(); 53 if (con != null) 54 con.close(); 55 } catch (SQLException e) { 56 // TODO: handle exception 57 e.printStackTrace(); 58 } 59 } 60 61 /** 62 * 执行更新 63 * 64 * @param sql 65 * 传入的预设的 sql语句 66 * @param params 67 * 问号参数列表 68 * @return 影响行数 69 */ 70 public int execUpdate(String sql, Object[] params) { 71 try { 72 this .getConnection();// 获得连接对象 73 this .pstmt = this. con .prepareStatement(sql);// 获得预设语句对象 74 75 if (params != null) { 76 // 设置参数列表 77 for (int i = 0; i < params. length; i++) { 78 // 因为问号参数的索引是从1开始,所以是i+1,将所有值都转为字符串形式,好让setObject成功运行 79 this .pstmt .setObject(i + 1, params[i] + "" ); 80 } 81 } 82 83 return this .pstmt .executeUpdate(); // 执行更新,并返回影响行数 84 85 } catch (ClassNotFoundException | SQLException e) { 86 // TODO Auto-generated catch block 87 e.printStackTrace(); 88 } finally { 89 this .close( this. rs, this. pstmt , this .con ); 90 } 91 return 0; 92 } 93 94 /** 95 * 执行查询 96 * 97 * @param sql 98 * 传入的预设的 sql语句 99 * @param params100 * 问号参数列表101 * @return 查询后的结果102 */103 public List<Map<String, Object>> execQuery(String sql, Object[] params) {104 105 try {106 this .getConnection();// 获得连接对象107 this .pstmt = this. con .prepareStatement(sql);// 获得预设语句对象108 109 if (params != null) {110 // 设置参数列表111 for (int i = 0; i < params. length; i++) {112 // 因为问号参数的索引是从1开始,所以是i+1,将所有值都转为字符串形式,好让setObject成功运行113 this .pstmt .setObject(i + 1, params[i] + "" );114 }115 }116 117 // 执行查询118 ResultSet rs = pstmt .executeQuery();119 120 List<Map<String, Object>> al = new ArrayList<Map<String, Object>>();121 122 // 获得结果集元数据(元数据就是描述数据的数据,比如把表的列类型列名等作为数据)123 ResultSetMetaData rsmd = rs.getMetaData();124 125 // 获得列的总数126 int columnCount = rsmd.getColumnCount();127 128 // 遍历结果集129 while (rs.next()) {130 Map<String, Object> hm = new HashMap<String, Object>();131 for (int i = 0; i < columnCount; i++) {132 // 根据列索引取得每一列的列名,索引从1开始133 String columnName = rsmd.getColumnName(i + 1);134 // 根据列名获得列值135 Object columnValue =http://www.mamicode.com/ rs.getObject(columnName);136 // 将列名作为key,列值作为值,放入 hm中,每个 hm相当于一条记录137 hm.put(columnName, columnValue);138 }139 // 将每个 hm添加到al中, al相当于是整个表,每个 hm是里面的一条记录140 al.add(hm);141 }142 143 return al;144 145 } catch (ClassNotFoundException | SQLException e) {146 // TODO Auto-generated catch block147 e.printStackTrace();148 } finally {149 this .close( this. rs, this. pstmt , this .con );150 }151 return null ;152 }153 }
代码解释:
一:为什么直接使用 “Class. forName( driver); ”注册驱动
①原始注册驱动写法:
1 // 注册驱动:告诉 java 去连接哪种数据库2 //DriverManager :驱动管理类,负责管理驱动,创建连接对象3 DriverManager. registerDriver( new com.mysql.jdbc.Driver());
static void | registerDriver ( Driver driver) 向 DriverManager 注册给定驱动程序。 |
参数:Driver=====来哦子欲你要连接的数据库(如果连接orcale,来自于oracle,如果连接mysql,来自于mysql)
备注:查询 Drive源码
1 public class Driver extends NonRegisteringDriver implements java.sql.Driver { 2 // ~ Static fields/initializers 3 // --------------------------------------------- 4 5 // 6 // Register ourselves with the DriverManager 7 // 8 static { 9 try {10 java.sql.DriverManager. registerDriver( new Driver());11 } catch (SQLException E) {12 throw new RuntimeException( "Can‘t register driver!" );13 }14 }
可以看到: java.sql.DriverManager. registerDriver( new Driver());是写在静态代码块中,只要调用Driver这个方法,就会自动运行这段代码,这样会造成“注册两次驱动”
因此,我们可以改成如下版本:
②改进版
1 // 注册驱动:告诉 java去连接哪种数据库2 //DriverManager.registerDriver(new com.mysql.jdbc.Driver());3 new com.mysql.jdbc.Driver();
但是这样写:
1、静态初始化已经new了一个Driver对象,注册到DriverManager中去,在此再创建一个Driver对象则是完全没有必要的,浪费空间;
2、不够灵活,如果需要换数据库的话,需要改动代码,此时最好把要变得内容改成字符串的形式,可以由变量读取外部配置文件进行传入(由此可以解释,为什么源代码中要直接写成静态代码块)
③最终版
1 // 注册驱动:告诉 java 去连接哪种数据库2 //DriverManager.registerDriver(new com.mysql.jdbc.Driver());3 //new com.mysql.jdbc.Driver();4 Class. forName( "com.mysql.jdbc.Driver");
最终版的好处:
1、Class.forName()的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段。
2、既然在静态初始化器中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX)就可以了
二:获得连接对象
con = DriverManager.getConnection( url , username , password );
url:连接到某一个具体的数据库
user:数据库的用户名
password:数据库用户名对应的密码
url = "jdbc:mysql://localhost:3306/mao"
jdbc: jdbc协议
mysql: jdbc子协议(表示mysql协议)
备注:
url其他写法一:
url = jdbc:mysql://localhost:3306/mao?userUnicode=true&characterEncoding=utf8//?userUnicode=true&characterEncoding=utf8//加上这个可以解决数据库的乱码问题
/*
*1、存数据时:
*数据库在存放项目数据的时候会先用UTF-8格式将数据解码成字节码,然后再将解码后的字节码重新使用GBK编码存*放到数据库中。
*
*2.取数据时:
* 在从数据库中取数据的时候,数据库会先将数据库中的数据按GBK格式解码成字节码,然后再将解码后的字节*码重新按UTF-8格式编码数据,最后再将数据返回给客户端。
**/
url其他写法二:
//如果连接的mysql是在本机,并且mysql的端口是3306,比如:url:"jdbc:mysql://localhost:3306/mao"//那么url可以简写为:url:"jdbc:mysql:///mao"
三、语句对象
1 // 创建语句对象Statement2 Statement stmt = con.createStatement();3 4 //创建预设语句对象PreparedStatement5 String sql = "update class set classDesc = ? where id = ?";6 PreparedStatement pstmt = con.prepareStatement(sql);
接下来是重点:
1:Statement的缺陷:
①容易被sql注入
sql注入:在页面表单中输入sql的片段。达到串改程序中sql语句。
正常情况:
select * from user where username=‘zhangsan‘ and password = ‘123456‘;
当sql被注入之后的语句:
select * from user where username=‘zhangsan‘ and password = ‘‘ or ‘1‘=‘1‘
②效率不高
Statement每执行一次,sql进行一次编译。即使每次的sql语句格式都一样
2:PreparedStatement的优势
①防止sql注入
PreparedStatement会对特殊字符进行转译,并通过参数形式设置到语句中,而不再是变量拼凑成sql语句
②预编译功能
相同格式的sql语句只被编译一次,后一条格式相同的sql语句运行时,只需改变参数的值即可
第二版:使用数据库连接池
代码前备注:
本工具类代码使用c3p0连接池
c3p0-config.xml
1 <? xml version ="1.0" encoding= "UTF-8" ?> 2 < c3p0-config> 3 <!-- 默认配置,c3p0框架默认加载这段默认配置 --> 4 < default-config> 5 <!-- 配置JDBC 四个基本属性 --> 6 < property name ="driverClass" > com.mysql.jdbc.Driver</ property > 7 < property name ="jdbcUrl" > jdbc:mysql:///数据库名</ property > 8 < property name ="user" > 数据库用户名</ property > 9 < property name ="password" > 数据库密码</ property >10 </ default-config> <!-- This app is massive! -->11 </ c3p0-config>
1 package cn.service; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.sql.ResultSetMetaData; 7 import java.sql.SQLException; 8 import java.util.ArrayList; 9 import java.util.HashMap; 10 import java.util.List; 11 import java.util.Map; 12 13 import org.junit.Test; 14 15 import com.mchange.v2.c3p0.ComboPooledDataSource; 16 import com.mchange.v2.c3p0.util.TestUtils; 17 18 public class DBService { 19 20 // 三剑客 21 Connection con = null;// 连接对象 22 PreparedStatement pstmt = null;// 语句对象 23 ResultSet rs = null;// 结果集对象 24 25 /** 26 * 获得连接对象 27 * 28 * @return 连接对象 29 * @throws ClassNotFoundException 30 * @throws SQLException 31 */ 32 public Connection getConnection() throws ClassNotFoundException, 33 SQLException { 34 35 // 创建c3p0连接池 36 ComboPooledDataSource ds = new ComboPooledDataSource("itcast"); 37 // 通过连接池对象创建连接 38 con = ds.getConnection(); 39 return con; 40 } 41 42 /** 43 * 关闭三剑客 44 * 45 * @throws SQLException 46 */ 47 public void close(ResultSet rs, PreparedStatement pstmt, Connection con) { 48 49 try { 50 if (rs != null) 51 rs.close(); 52 if (pstmt != null) 53 pstmt.close(); 54 if (con != null) 55 con.close(); 56 } catch (SQLException e) { 57 // TODO: handle exception 58 e.printStackTrace(); 59 } 60 } 61 62 /** 63 * 执行更新 64 * 65 * @param sql 66 * 传入的预设的sql语句 67 * @param params 68 * 问号参数列表 69 * @return 影响行数 70 */ 71 public int execUpdate(String sql, Object[] params) { 72 try { 73 this.getConnection();// 获得连接对象 74 this.pstmt = this.con.prepareStatement(sql);// 获得预设语句对象 75 76 if (params != null) { 77 // 设置参数列表 78 for (int i = 0; i < params.length; i++) { 79 // 因为问号参数的索引是从1开始,所以是i+1,将所有值都转为字符串形式,好让setObject成功运行 80 this.pstmt.setObject(i + 1, params[i] + ""); 81 } 82 } 83 84 return this.pstmt.executeUpdate();// 执行更新,并返回影响行数 85 86 } catch (ClassNotFoundException | SQLException e) { 87 // TODO Auto-generated catch block 88 e.printStackTrace(); 89 } finally { 90 this.close(this.rs, this.pstmt, this.con); 91 } 92 return 0; 93 } 94 95 /** 96 * 执行查询 97 * 98 * @param sql 99 * 传入的预设的sql语句100 * @param params101 * 问号参数列表102 * @return 查询后的结果103 */104 public List<Map<String, Object>> execQuery(String sql, Object[] params) {105 106 try {107 this.getConnection();// 获得连接对象108 this.pstmt = this.con.prepareStatement(sql);// 获得预设语句对象109 110 if (params != null) {111 // 设置参数列表112 for (int i = 0; i < params.length; i++) {113 // 因为问号参数的索引是从1开始,所以是i+1,将所有值都转为字符串形式,好让setObject成功运行114 this.pstmt.setObject(i + 1, params[i] + "");115 }116 }117 118 // 执行查询119 ResultSet rs = pstmt.executeQuery();120 121 List<Map<String, Object>> al = new ArrayList<Map<String, Object>>();122 123 // 获得结果集元数据(元数据就是描述数据的数据,比如把表的列类型列名等作为数据)124 ResultSetMetaData rsmd = rs.getMetaData();125 126 // 获得列的总数127 int columnCount = rsmd.getColumnCount();128 129 // 遍历结果集130 while (rs.next()) {131 Map<String, Object> hm = new HashMap<String, Object>();132 for (int i = 0; i < columnCount; i++) {133 // 根据列索引取得每一列的列名,索引从1开始134 String columnName = rsmd.getColumnName(i + 1);135 // 根据列名获得列值136 Object columnValue =http://www.mamicode.com/ rs.getObject(columnName);137 // 将列名作为key,列值作为值,放入hm中,每个hm相当于一条记录138 hm.put(columnName, columnValue);139 }140 // 将每个hm添加到al中,al相当于是整个表,每个hm是里面的一条记录141 al.add(hm);142 }143 144 return al;145 146 } catch (ClassNotFoundException | SQLException e) {147 // TODO Auto-generated catch block148 e.printStackTrace();149 } finally {150 this.close(this.rs, this.pstmt, this.con);151 }152 153 return null;154 }155 156 }157
JDBC-自定义数据库工具类(DBService)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。