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 params
100        *            问号参数列表
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 = 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 block
147                   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   // 创建语句对象Statement
2      Statement stmt = con.createStatement();
3
4      //创建预设语句对象PreparedStatement
5      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 params
101      *            问号参数列表
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 = 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 block
148             e.printStackTrace();
149         } finally {
150             this.close(this.rs, this.pstmt, this.con);
151         }
152
153         return null;
154     }
155
156 }
157  
时间: 2024-10-11 01:53:43

JDBC-自定义数据库工具类(DBService)的相关文章

JAVA学习笔记(五十一)- DBUtil 封装数据库工具类

数据库工具类 import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /* * 数据库工具类 */ public class DBUtil { // 获取数据库连接 public static Connection getConnection() { String dr

自己编写的数据库工具类

/** * 数据库工具类 * 1.连接数据库 * 2.执行增删改查功能功能并报错 * 3.没有参数传递是则使用默认信息连接 */ class mysql {    private $link = null;       //记录连接资源    private $host;    private $port;    private $user;    private $pass;    private $charset;    private $dbname;            //设定6个私

自定义圆形工具类

1.自定义圆形工具类 CircleImageViewUtil.java 关键点:可以自持缩放 package com.example.circleimageviewdemo; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.graphics.Col

开发自己的框架——(二)数据库工具类的封装

为了让框架的内容与数据分离,我们把常用的类封装到一个工具类中,当用到这些方法时,就调用这个封装好的类,能够使代码的复用性得到很大的提高.首先,封装数据库相关操作,为了使封装规范化,我们创建一个接口让数据库实现接口中的方法,数据库使用PDO扩展访问数据.数据库接口类 I_DAO.interface.php 1 <?php 2 interface I_DAO 3 { 4 //查询所有数据的功能 5 public function getAll($sql=''); 6 // //查询一条数据 7 pu

关于jdbc的数据库驱动类DriverManager.getConnection()参数

关于jdbc的数据库驱动类DriverManager.getConnection()参数 1.Oracle8/8i/9i数据库(thin模式) Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); String url="jdbc:oracle:thin:@localhost:1521:orcl"; //orcl为数据库的SID String user="test"; St

单利模式的数据库工具类

package com.hanqi.dao; import java.sql.Connection; import java.sql.SQLException; //单利模式的数据库工具类 //返回数据连接 import com.mchange.v2.c3p0.ComboPooledDataSource; public class DBHelper { //1.隐藏默认的构造方法 private DBHelper() { } //2.静态的实例 private static DBHelper d

安卓开发技巧二:自定义日志工具类XLog的实现

我们在开发过程中,打印日志是必不可少的一个调试环节,然而,直接使用系统自带的Log日志类,并不能满足我们实际项目的需求:假如我们现在在开发一款比较大的项目,用到打印日志的地方肯定特别多,等到真正上线的时候,我们是不希望日志依旧能够打印出的,原因很简单,不仅多少有些影响效率,更有可能导致信息的泄露,所以我们就需要把所有的日志打印语句全部取消掉,难道我们真的一个一个的去删除这些打印日志的语句吗?项目那么大,就是想删除,也得耗费大量的时间和精力!大家不用怕,笔者这就给大家带来一款控制线上版本和线下版本

MySQL数据库工具类之——DataTable批量加入MySQL数据库(Net版)

MySQL数据库工具类之——DataTable批量加入数据库(Net版),MySqlDbHelper通用类希望能对大家有用,代码如下: using MySql.Data.MySqlClient; using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Linq; using System.Web; using System.Text; p

java学习--基础知识进阶第十三天--反射机制的概述和字节码对象的获取方式、反射操作构造方法、成员方法、成员属性、JavaBean的概述&amp;BeanUtils的使用、自定义BeanUtils工具类

今日内容介绍 u 反射机制的概述和字节码对象的获取方式 u 反射操作构造方法.成员方法.成员属性 u JavaBean的概述&BeanUtils的使用 u 自定义BeanUtils工具类 第1章 反射机制概述.字节码对象的获取方式.反射操作构造方法.成员方法.成员属性 1.1 反射机制的概述和字节码对象的获取方式 1.1.1 反射介绍 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法        这种动态获取的以及动