厚积薄发系列之JDBC详解

创建一个以JDBC链接数据库的程序,包含七个步骤

1.加载JDBC驱动

    • 加载要连接的数据库的驱动到JVM
    • 如何加载?forName(数据库驱动)
    • MySQL:Class.forName("com.mysql.jdbc.Driver");
    • Oracle10g:Class.forName("oracle.jdbc.driver.OracleDriver");
    • SQLServer2005:Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
    • 1         //1.加载驱动程序 mysql为例子
      2         try {
      3             Class.forName("com.mysql.jdbc.Driver");
      4         } catch (ClassNotFoundException e) {
      5             // TODO Auto-generated catch block
      6             e.printStackTrace();
      7             System.out.println("加载驱动失败");
      8         }

2.提供JDBC连接的URL

    • 连接URL定义了连接数据库时的协议,子协议,数据源标识
    • 根据不同的数据库产品不同连接的URL不同
      • Oracle10g:jdbc:oracle:thin:@主机名:端口:数据库SID
      • MySQL5:jdbc:mysql://主机名:端口/数据库名
      • SQLServer2005:jdbc:sqlserver://主机名:端口:DatabaseName=库名
    • 1     /**
      2      * 访问数据库的地址
      3      */
      4     private final String URL = "jdbc:mysql://localhost:3306/test";

3.创建数据库的链接

    • 连接数据库就要向java.sqlDriverManager请求过的Connection对象,一个Connection就代表一个数据库连接
    • 在连接的时候需要传入数据库的账户和密码
    • 1 Connection connection =
      DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");

4.创建一个Statement

    • 获得数据库连接后,要想执行sql语句,必须获得java.sql.Statement实例,Statement实例分为三种
      • 执行静态的sql语句.通过Statement实例实现
      • 执行动态的sql语句.通过PreparedStatement实例实现
      • 执行数据库存储过程.通常通过CallableStatement实例实现
    • 1             //执行静态的sql
      2             Statement statement = connection.createStatement();
      3             ResultSet resultSet = statement.executeQuery("select * from sys_user");
      4             System.out.println(resultSet.toString());
      5             
      6             //执行动态的sql  采用预加载的方式 可防止sql注入
      7             PreparedStatement prepareStatement = connection.prepareStatement("select * from sys_user");

5.执行sql语句

  • Statement提供了三种执行查询
    • ResultSet executeQuery(String sql);   执行查询数据库的sql语句,返回一个结果集(ResultSet)对象
    • int executeUpdate(String sql);  执行INSERT,UPDATE或者DELETE语句以及SQL DDL语句,返回受影响行数
    • execute(String sql); 用于返回多个结果集,多个更新计数或者二者组合的语句
    • 1             //执行查询
      2             ResultSet resultSet = statement.executeQuery("select * from sys_user");
      3             //执行insert update delete 
      4             statement.executeUpdate("INSERT INTO sys_user VALUES(5,'lisi','123','李四');");

6.处理结果

  • 处理结果有两种情况
    • 返回本次操作的记录数 在执行executeUpdate();方法的时候会返回受影响的行数
    • 返回ResultSet对象  在执行executeQuery();方法的时候会返回对象 
  • ResultSet对象中包含SQL查询中出的所有行,通过get方法可以获取每行的数据
  • 1             //执行查询
    2             ResultSet resultSet = statement.executeQuery("select * from sys_user");
    3             while(resultSet.next()) {
    4                 System.out.println(resultSet.getInt("uid"));
    5                 System.out.println(resultSet.getString("username"));
    6                 System.out.println(resultSet.getString("password"));
    7                 System.out.println(resultSet.getString("nickname"));
    8             }

7.关闭JDBC对象

  • 在使用完毕后需要关闭三个对象,关闭结果集(resultSet),关闭声明(Statement),关闭数据库连接(Connection)
  • 1             if (resultSet != null) { // 关闭记录集
    2                 resultSet.close();
    3             }
    4             if (statement != null) { // 关闭声明
    5                 statement.close();
    6             }
    7             if (connection != null) { // 关闭连接对象
    8                 connection.close();
    9             }

我们可以把经常使用的方法封装成一个工具类,我们一般成为jdbcUtils,下面代码时从CSDNhttp://blog.csdn.net/harryweasley/article/details/45689023获取,大家可以自己借鉴修改,我就不再重复打出来了

  1 package com.jdbc.dbutils;  
  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 JdbcUtils {  
 15     /** 
 16      * 数据库的用户名 
 17      */  
 18     private final String USER = "root";  
 19     /** 
 20      * 数据库的密码 
 21      */  
 22     private final String PASSWORD = "123456";  
 23     /** 
 24      * 数据库的驱动信息 
 25      */  
 26     private final String DRIVER = "com.mysql.jdbc.Driver";  
 27     /** 
 28      * 访问数据库的地址 
 29      */  
 30     private final String URL = "jdbc:mysql://localhost:3306/test";  
 31     /** 
 32      * 数据库的连接 
 33      */  
 34     Connection connection;  
 35     /** 
 36      * sql语句的执行对象 
 37      */  
 38     PreparedStatement preparedStatement;  
 39     /** 
 40      * 查询返回的结果集合 
 41      */  
 42     ResultSet resultSet;  
 43   
 44     public JdbcUtils() {  
 45         try {  
 46             Class.forName(DRIVER);  
 47             System.out.println("注册驱动成功");  
 48         } catch (ClassNotFoundException e) {  
 49             e.printStackTrace();  
 50         }  
 51     }  
 52   
 53     /** 
 54      * 连接数据库 
 55      *  
 56      * @return 数据库的连接对象 
 57      */  
 58     public Connection getConnection() {  
 59         try {  
 60             connection = DriverManager.getConnection(URL, USER, PASSWORD);  
 61         } catch (SQLException e) {  
 62             e.printStackTrace();  
 63         }  
 64         return connection;  
 65     }  
 66   
 67     /** 
 68      * 完成对数据库的表的添加删除和修改的操作 
 69      *  
 70      * @param sql 
 71      * @param params 
 72      * @return 
 73      * @throws SQLException 
 74      */  
 75     public boolean updateByPrepareStatement(String sql, List<Object> params)  
 76             throws SQLException {  
 77         boolean flag = false;  
 78         int result = -1;// 表示当用户执行添加删除和修改的时候所影响数据库的行数  
 79         // 创建一个 PreparedStatement 对象来将参数化的 sql 语句发送到数据库。  
 80         preparedStatement = connection.prepareStatement(sql);  
 81         int index = 1;  
 82         if (params != null && !params.isEmpty()) {  
 83             for (Object object : params) {  
 84                 // 使用给定对象设置指定参数的值。index从1开始  
 85                 preparedStatement.setObject(index++, object);  
 86             }  
 87         }  
 88         // 在此 PreparedStatement 对象中执行 SQL 语句,该语句必须是一个 SQL 数据操作语言语句,比如  
 89         // INSERT、UPDATE 或 DELETE 语句  
 90         result = preparedStatement.executeUpdate();  
 91         flag = result > 0 ? true : false;  
 92         return flag;  
 93   
 94     }  
 95   
 96     /** 
 97      * 查询返回单条记录 
 98      *  
 99      * @param sql 
100      * @param params 
101      * @return 
102      * @throws SQLException 
103      */  
104     public Map<String, Object> findSimpleResult(String sql, List<Object> params)  
105             throws SQLException {  
106         Map<String, Object> map = new HashMap<String, Object>();  
107         int index = 1;  
108         // 创建一个 PreparedStatement 对象来将参数化的 sql 语句发送到数据库。  
109         preparedStatement = connection.prepareStatement(sql);  
110         if (params != null && !params.isEmpty()) {  
111             for (Object object : params) {  
112                 // 使用给定对象设置指定参数的值。index从1开始  
113                 preparedStatement.setObject(index++, object);  
114             }  
115         }  
116         // 在此 PreparedStatement 对象中执行 SQL 查询,并返回该查询生成的 ResultSet 对象。  
117         resultSet = preparedStatement.executeQuery();  
118         // 获取此 ResultSet 对象的列的编号、类型和属性。  
119         ResultSetMetaData metaData = resultSet.getMetaData();  
120         int col_len = metaData.getColumnCount();  
121         while (resultSet.next()) {  
122             for (int i = 0; i < col_len; i++) {  
123                 // sql数据库列的下标是从1开始的  
124                 String col_name = metaData.getColumnName(i + 1);  
125                 Object col_value = resultSet.getObject(col_name);  
126                 if (col_value == null) {  
127                     col_value = "";  
128                 }  
129                 map.put(col_name, col_value);  
130             }  
131         }  
132   
133         return map;  
134     }  
135   
136     public List<Map<String, Object>> findMoreResult(String sql,  
137             List<Object> params) throws SQLException {  
138         List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();  
139         int index = 1;  
140         // 创建一个 PreparedStatement 对象来将参数化的 sql 语句发送到数据库。  
141         preparedStatement = connection.prepareStatement(sql);  
142         if (params != null && !params.isEmpty()) {  
143             for (Object object : params) {  
144                 // 使用给定对象设置指定参数的值。index从1开始  
145                 preparedStatement.setObject(index++, object);  
146             }  
147         }  
148         // 在此 PreparedStatement 对象中执行 SQL 查询,并返回该查询生成的 ResultSet 对象。  
149         resultSet = preparedStatement.executeQuery();  
150         // 获取此 ResultSet 对象的列的编号、类型和属性。  
151         ResultSetMetaData metaData = resultSet.getMetaData();  
152         int col_len = metaData.getColumnCount();  
153         while (resultSet.next()) {  
154             Map<String, Object> map = new HashMap<String, Object>();  
155             for (int i = 0; i < col_len; i++) {  
156                 // sql数据库列的下标是从1开始的  
157                 String col_name = metaData.getColumnName(i + 1);  
158                 Object col_value = resultSet.getObject(col_name);  
159                 if (col_value == null) {  
160                     col_value = "";  
161                 }  
162                 map.put(col_name, col_value);  
163             }  
164             list.add(map);  
165         }  
166         return list;  
167     }  
168   
169     /** 
170      * 关闭数据库 
171      *  
172      * @throws SQLException 
173      */  
174     public void releaseConn() throws SQLException {  
175         if (resultSet != null) {  
176             resultSet.close();  
177         }  
178   
179         if (preparedStatement != null) {  
180             preparedStatement.close();  
181         }  
182         if (connection != null) {  
183             connection.close();  
184         }  
185     }  
186   
187     static JdbcUtils jdbcUtils;  
188   
189     public static void main(String[] args) throws SQLException {  
190         jdbcUtils = new JdbcUtils();  
191         jdbcUtils.getConnection();  
192         // insert();  
193         // update();  
194         // query();  
195         Morequery();  
196     }  
197   
198     private static void query() throws SQLException {  
199         String sql = "select * from userinfo where pwd = ? ";  
200         List<Object> params = new ArrayList<Object>();  
201         params.add("123");  
202         Map<String, Object> map = jdbcUtils.findSimpleResult(sql, params);  
203         System.out.println(map);  
204     }  
205   
206     private static void Morequery() throws SQLException {  
207         String sql = "select * from userinfo  ";  
208         List<Map<String, Object>> map = jdbcUtils.findMoreResult(sql, null);  
209         System.out.println(map);  
210     }  
211   
212     /** 
213      * 更新数据库内容 
214      *  
215      * @throws SQLException 
216      */  
217     private static void update() throws SQLException {  
218         String sql = "update userinfo set username =? where id=2";  
219         List<Object> params = new ArrayList<Object>();  
220         params.add("liumr");  
221         jdbcUtils.updateByPrepareStatement(sql, params);  
222     }  
223   
224     /** 
225      * 增加数据 
226      *  
227      * @throws SQLException 
228      */  
229     private static void insert() throws SQLException {  
230         String sql = "insert userinfo (username,pwd) values (?,?)";  
231         List<Object> params = new ArrayList<Object>();  
232         params.add("liugx");  
233         params.add("456");  
234         jdbcUtils.updateByPrepareStatement(sql, params);  
235   
236     }  
237   
238 }  
View Code

数据库连接池技术

  • 由于我们要对数据库频繁地进行操作,每进行一次连接操作就要获取一个conntection连接,每次使用完毕后要全部关闭资源,这样的话我们可以使用数据库连接池技术
  • 优点:
    • 资源重用:避免重复创建,释放连接,大量节约性能开销
    • 更快的响应:在连接池初始化的过程中,往往已经创建了若干数据库连接置于连接池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间。
    • 新的资源分配手段: 对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置,实现某一应用最大可用数据库连接数的限制,避免某一应用独占所有的数据库资源
    • 统一的连接管理,避免数据库连接泄露:  在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露。
  • 创建的数据库连接池
    • DBCP:由于性能问题,已经很少使用了
    • C3P0:目前在很多项目中都在使用
    • Druid(阿里巴巴):阿里巴巴开源的一个数据库连接池
  •  下面我们示范常用的C3p0的使用
    • 导入jar包c3p0-0.9.1.2.jar
    • 在项目src目录下新建c3p0.properties
      • 文件内容(当然还有很多其他配置,下面最简单配置)
      • c3p0.driverClass=com.mysql.jdbc.Driver
        c3p0.jdbcUrl=jdbc:mysql://localhost:3306/test
        c3p0.user=root
        c3p0.password=root
    • 在与数据库交互时
    • 1 //创建一个数据库连接池ComboPooledDataSource ds = new ComboPooledDataSource();
      2 //创建QueryRunner接口
      3 QueryRunner qr = new QueryRunner(DataSourceUtils.getDataSource());
      4 //通过接口可以执行查询或者更新,修改操作
      5   qr.update(sql); //返回受影响的行数
      6   qr.query(sql, null); //返回各种类型
    •  关于QueryRunner的query方法其实功能是很强大的,可以根据查询的内容自动封装各种类型
      • 封装入一个javaBean中
      • 1 public Category getById(String cid) throws Exception {
        2         QueryRunner qr = new QueryRunner(DataSourceUtils.getDataSource());
        3         String sql = "select * from category where cid = ?";
        4         return qr.query(sql, new BeanHandler<>(Category.class), cid);
        5     }
      • 封装成一个可以指定类型的list集合
      • 1 public List<Category> findAll() throws Exception {
        2         QueryRunner qr = new QueryRunner(DataSourceUtils.getDataSource());
        3         String sql = "select * from category";
        4         List<Category> list = qr.query(sql, new BeanListHandler<>(Category.class));
        5         return list;
        6     }
      • 返回单条数据
      •  1     /**
         2      * 查询数据总条数
         3      */
         4     @Override
         5     public Integer getTotalSize() throws Exception {
         6         // 创建查询接口
         7         QueryRunner qr = new QueryRunner(DataSourceUtils.getDataSource());
         8         String sql = "select count(*) from links";
         9         return ((Long) qr.query(sql, new ScalarHandler())).intValue();
        10     }
    • C3p0是在项目中是很详细的,详细的学习该请大家参考正式的文档
杂家不如专家,精益求精
原文地址:https://www.cnblogs.com/jimisun/p/7812756.html