利用Java针对MySql封装的jdbc框架类 JdbcUtils 完整实现(包含增删改查、JavaBean反射原理,附源码)

最近看老罗的视频,跟着完成了利用Java操作MySql数据库的一个框架类JdbcUtils.java,完成对数据库的增删改查。其中查询这块,包括普通的查询和利用反射完成的查询,主要包括以下几个函数接口:

1、public Connection getConnection()   获得数据库的连接

2、public boolean updateByPreparedStatement(String sql, List<Object>params)throws SQLException  更新数据库,包括增加记录、删除记录、改动某个记录三个功能。

3、public Map<String, Object> findSimpleResult(String sql, List<Object> params) throws SQLException 查询单条记录,传进去的是一个List<Object>参数填充占位符,返回的是一个Map<String, Object>.一个Map对应一条完整的记录,String对应属性名,Object是属性值。

4、public List<Map<String, Object>> findModeResult(String sql, List<Object> params) throws SQLException 查询多条记录,放在List里。

上面四个函数已经包括了MySQl的所有操作,完全能够满足使用需要。视频里老罗还扩展了两个反射来查询的函数。

5、public <T> T findSimpleRefResult(String sql, List<Object> params,
Class<T> cls )throws Exception   利用反射查询单个记录。

6、 public <T> List<T> findMoreRefResult(String sql, List<Object> params,
Class<T> cls )throws Exception   利用反射查询多个记录。

下面附完整代码:

JdbcUtils.java

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">package com.jdbc.dbutils;  
  2.   
  3. import java.lang.reflect.Field;  
  4. import java.sql.Connection;  
  5. import java.sql.DriverManager;  
  6. import java.sql.PreparedStatement;  
  7. import java.sql.ResultSet;  
  8. import java.sql.ResultSetMetaData;  
  9. import java.sql.SQLException;  
  10. import java.util.ArrayList;  
  11. import java.util.HashMap;  
  12. import java.util.List;  
  13. import java.util.Map;  
  14.   
  15. import domain.UserInfo;  
  16.   
  17.   
  18. public class JdbcUtils {  
  19.     //数据库用户名  
  20.     private static final String USERNAME = "root";  
  21.     //数据库密码  
  22.     private static final String PASSWORD = "yanzi";  
  23.     //驱动信息   
  24.     private static final String DRIVER = "com.mysql.jdbc.Driver";  
  25.     //数据库地址  
  26.     private static final String URL = "jdbc:mysql://localhost:3306/mydb";  
  27.     private Connection connection;  
  28.     private PreparedStatement pstmt;  
  29.     private ResultSet resultSet;  
  30.     public JdbcUtils() {  
  31.         // TODO Auto-generated constructor stub  
  32.         try{  
  33.             Class.forName(DRIVER);  
  34.             System.out.println("数据库连接成功!");  
  35.   
  36.         }catch(Exception e){  
  37.   
  38.         }  
  39.     }  
  40.       
  41.     /** 
  42.      * 获得数据库的连接 
  43.      * @return 
  44.      */  
  45.     public Connection getConnection(){  
  46.         try {  
  47.             connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);  
  48.         } catch (SQLException e) {  
  49.             // TODO Auto-generated catch block  
  50.             e.printStackTrace();  
  51.         }  
  52.         return connection;  
  53.     }  
  54.   
  55.       
  56.     /** 
  57.      * 增加、删除、改 
  58.      * @param sql 
  59.      * @param params 
  60.      * @return 
  61.      * @throws SQLException 
  62.      */  
  63.     public boolean updateByPreparedStatement(String sql, List<Object>params)throws SQLException{  
  64.         boolean flag = false;  
  65.         int result = -1;  
  66.         pstmt = connection.prepareStatement(sql);  
  67.         int index = 1;  
  68.         if(params != null && !params.isEmpty()){  
  69.             for(int i=0; i<params.size(); i++){  
  70.                 pstmt.setObject(index++, params.get(i));  
  71.             }  
  72.         }  
  73.         result = pstmt.executeUpdate();  
  74.         flag = result > 0 ? true : false;  
  75.         return flag;  
  76.     }  
  77.   
  78.     /** 
  79.      * 查询单条记录 
  80.      * @param sql 
  81.      * @param params 
  82.      * @return 
  83.      * @throws SQLException 
  84.      */  
  85.     public Map<String, Object> findSimpleResult(String sql, List<Object> params) throws SQLException{  
  86.         Map<String, Object> map = new HashMap<String, Object>();  
  87.         int index  = 1;  
  88.         pstmt = connection.prepareStatement(sql);  
  89.         if(params != null && !params.isEmpty()){  
  90.             for(int i=0; i<params.size(); i++){  
  91.                 pstmt.setObject(index++, params.get(i));  
  92.             }  
  93.         }  
  94.         resultSet = pstmt.executeQuery();//返回查询结果  
  95.         ResultSetMetaData metaData = resultSet.getMetaData();  
  96.         int col_len = metaData.getColumnCount();  
  97.         while(resultSet.next()){  
  98.             for(int i=0; i<col_len; i++ ){  
  99.                 String cols_name = metaData.getColumnName(i+1);  
  100.                 Object cols_value = resultSet.getObject(cols_name);  
  101.                 if(cols_value == null){  
  102.                     cols_value = "";  
  103.                 }  
  104.                 map.put(cols_name, cols_value);  
  105.             }  
  106.         }  
  107.         return map;  
  108.     }  
  109.   
  110.     /**查询多条记录 
  111.      * @param sql 
  112.      * @param params 
  113.      * @return 
  114.      * @throws SQLException 
  115.      */  
  116.     public List<Map<String, Object>> findModeResult(String sql, List<Object> params) throws SQLException{  
  117.         List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();  
  118.         int index = 1;  
  119.         pstmt = connection.prepareStatement(sql);  
  120.         if(params != null && !params.isEmpty()){  
  121.             for(int i = 0; i<params.size(); i++){  
  122.                 pstmt.setObject(index++, params.get(i));  
  123.             }  
  124.         }  
  125.         resultSet = pstmt.executeQuery();  
  126.         ResultSetMetaData metaData = resultSet.getMetaData();  
  127.         int cols_len = metaData.getColumnCount();  
  128.         while(resultSet.next()){  
  129.             Map<String, Object> map = new HashMap<String, Object>();  
  130.             for(int i=0; i<cols_len; i++){  
  131.                 String cols_name = metaData.getColumnName(i+1);  
  132.                 Object cols_value = resultSet.getObject(cols_name);  
  133.                 if(cols_value == null){  
  134.                     cols_value = "";  
  135.                 }  
  136.                 map.put(cols_name, cols_value);  
  137.             }  
  138.             list.add(map);  
  139.         }  
  140.   
  141.         return list;  
  142.     }  
  143.   
  144.     /**通过反射机制查询单条记录 
  145.      * @param sql 
  146.      * @param params 
  147.      * @param cls 
  148.      * @return 
  149.      * @throws Exception 
  150.      */  
  151.     public <T> T findSimpleRefResult(String sql, List<Object> params,  
  152.             Class<T> cls )throws Exception{  
  153.         T resultObject = null;  
  154.         int index = 1;  
  155.         pstmt = connection.prepareStatement(sql);  
  156.         if(params != null && !params.isEmpty()){  
  157.             for(int i = 0; i<params.size(); i++){  
  158.                 pstmt.setObject(index++, params.get(i));  
  159.             }  
  160.         }  
  161.         resultSet = pstmt.executeQuery();  
  162.         ResultSetMetaData metaData  = resultSet.getMetaData();  
  163.         int cols_len = metaData.getColumnCount();  
  164.         while(resultSet.next()){  
  165.             //通过反射机制创建一个实例  
  166.             resultObject = cls.newInstance();  
  167.             for(int i = 0; i<cols_len; i++){  
  168.                 String cols_name = metaData.getColumnName(i+1);  
  169.                 Object cols_value = resultSet.getObject(cols_name);  
  170.                 if(cols_value == null){  
  171.                     cols_value = "";  
  172.                 }  
  173.                 Field field = cls.getDeclaredField(cols_name);  
  174.                 field.setAccessible(true); //打开javabean的访问权限  
  175.                 field.set(resultObject, cols_value);  
  176.             }  
  177.         }  
  178.         return resultObject;  
  179.   
  180.     }  
  181.   
  182.     /**通过反射机制查询多条记录 
  183.      * @param sql  
  184.      * @param params 
  185.      * @param cls 
  186.      * @return 
  187.      * @throws Exception 
  188.      */  
  189.     public <T> List<T> findMoreRefResult(String sql, List<Object> params,  
  190.             Class<T> cls )throws Exception {  
  191.         List<T> list = new ArrayList<T>();  
  192.         int index = 1;  
  193.         pstmt = connection.prepareStatement(sql);  
  194.         if(params != null && !params.isEmpty()){  
  195.             for(int i = 0; i<params.size(); i++){  
  196.                 pstmt.setObject(index++, params.get(i));  
  197.             }  
  198.         }  
  199.         resultSet = pstmt.executeQuery();  
  200.         ResultSetMetaData metaData  = resultSet.getMetaData();  
  201.         int cols_len = metaData.getColumnCount();  
  202.         while(resultSet.next()){  
  203.             //通过反射机制创建一个实例  
  204.             T resultObject = cls.newInstance();  
  205.             for(int i = 0; i<cols_len; i++){  
  206.                 String cols_name = metaData.getColumnName(i+1);  
  207.                 Object cols_value = resultSet.getObject(cols_name);  
  208.                 if(cols_value == null){  
  209.                     cols_value = "";  
  210.                 }  
  211.                 Field field = cls.getDeclaredField(cols_name);  
  212.                 field.setAccessible(true); //打开javabean的访问权限  
  213.                 field.set(resultObject, cols_value);  
  214.             }  
  215.             list.add(resultObject);  
  216.         }  
  217.         return list;  
  218.     }  
  219.   
  220.     /** 
  221.      * 释放数据库连接 
  222.      */  
  223.     public void releaseConn(){  
  224.         if(resultSet != null){  
  225.             try{  
  226.                 resultSet.close();  
  227.             }catch(SQLException e){  
  228.                 e.printStackTrace();  
  229.             }  
  230.         }  
  231.     }  
  232.   
  233.     /** 
  234.      * @param args 
  235.      */  
  236.     public static void main(String[] args) throws SQLException {  
  237.         // TODO Auto-generated method stub  
  238.         JdbcUtils jdbcUtils = new JdbcUtils();  
  239.         jdbcUtils.getConnection();  
  240.   
  241.         /*******************增*********************/  
  242.         /*      String sql = "insert into userinfo (username, pswd) values (?, ?), (?, ?), (?, ?)"; 
  243.         List<Object> params = new ArrayList<Object>(); 
  244.         params.add("小明"); 
  245.         params.add("123xiaoming"); 
  246.         params.add("张三"); 
  247.         params.add("zhangsan"); 
  248.         params.add("李四"); 
  249.         params.add("lisi000"); 
  250.         try { 
  251.             boolean flag = jdbcUtils.updateByPreparedStatement(sql, params); 
  252.             System.out.println(flag); 
  253.         } catch (SQLException e) { 
  254.             // TODO Auto-generated catch block 
  255.             e.printStackTrace(); 
  256.         }*/  
  257.   
  258.   
  259.         /*******************删*********************/  
  260.         //删除名字为张三的记录  
  261.         /*      String sql = "delete from userinfo where username = ?"; 
  262.         List<Object> params = new ArrayList<Object>(); 
  263.         params.add("小明"); 
  264.         boolean flag = jdbcUtils.updateByPreparedStatement(sql, params);*/  
  265.   
  266.         /*******************改*********************/  
  267.         //将名字为李四的密码改了  
  268.         /*      String sql = "update userinfo set pswd = ? where username = ? "; 
  269.         List<Object> params = new ArrayList<Object>(); 
  270.         params.add("lisi88888"); 
  271.         params.add("李四"); 
  272.         boolean flag = jdbcUtils.updateByPreparedStatement(sql, params); 
  273.         System.out.println(flag);*/  
  274.   
  275.         /*******************查*********************/  
  276.         //不利用反射查询多个记录  
  277.         /*      String sql2 = "select * from userinfo "; 
  278.         List<Map<String, Object>> list = jdbcUtils.findModeResult(sql2, null); 
  279.         System.out.println(list);*/  
  280.   
  281.         //利用反射查询 单条记录  
  282.         String sql = "select * from userinfo where username = ? ";  
  283.         List<Object> params = new ArrayList<Object>();  
  284.         params.add("李四");  
  285.         UserInfo userInfo;  
  286.         try {  
  287.             userInfo = jdbcUtils.findSimpleRefResult(sql, params, UserInfo.class);  
  288.             System.out.print(userInfo);  
  289.         } catch (Exception e) {  
  290.             // TODO Auto-generated catch block  
  291.             e.printStackTrace();  
  292.         }  
  293.   
  294.   
  295.     }  
  296.   
  297. }  
  298. </span>  


根据上面代码可以看到,数据库名字:mydb,表名:userinfo,结构如下:

 

+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| id       | int(11)     | NO   | PRI | NULL    | auto_increment |
| username | varchar(64) | YES  |     | NULL    |                |
| pswd     | varchar(64) | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+

是用Nvicat提前创建好的:

因为有两个接口用到了反射,因此对应的JavaBean UserInfo.java代码如下:

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">package domain;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class UserInfo implements Serializable{  
  6.   
  7.     /** 
  8.      *  
  9.      */  
  10.     private static final long serialVersionUID = 1L;  
  11.   
  12.     private int id;  
  13.     private String username;  
  14.     private String pswd;  
  15.       
  16.     public UserInfo() {  
  17.         // TODO Auto-generated constructor stub  
  18.     }  
  19.   
  20.     public int getId() {  
  21.         return id;  
  22.     }  
  23.   
  24.     public void setId(int id) {  
  25.         this.id = id;  
  26.     }  
  27.   
  28.     public String getUsername() {  
  29.         return username;  
  30.     }  
  31.   
  32.     public void setUsername(String username) {  
  33.         this.username = username;  
  34.     }  
  35.   
  36.     public String getPswd() {  
  37.         return pswd;  
  38.     }  
  39.   
  40.     public void setPswd(String pswd) {  
  41.         this.pswd = pswd;  
  42.     }  
  43.   
  44.     @Override  
  45.     public String toString() {  
  46.         return "UserInfo [id=" + id + ", username=" + username + ", pswd="  
  47.                 + pswd + "]";  
  48.     }  
  49.   
  50.   
  51.   
  52.   
  53.   
  54. }  
  55. </span>  


补充说明:

 

1. 在安装完mysql-connector-java-gpl-5.1.26.exe后会发现找不到jar包,其实jar文件在C:\Program Files\MySQL\MySQL Connector J目录下,有两个jar包:

用哪一个都ok。在Java工程里新建一个文件夹libs,然后将mysql-connector-java-5.1.26-bin.jar拷贝过去,右键单击 add to build path就ok了。

2.抛开这个框架类JdbcUtils.java来说,操作数据库的一般性步骤如下:

    (1)连接数据库,加载驱动: Class.forName(DRIVER); DRIVER = "com.mysql.jdbc.Driver";这本身就是反射!!

      (2) 利用用户名和密码及数据库的名字连接,这一步才是真正的连接:

connection = DriverManager.getConnection(URL, USERNAME, PASSWORD); 

其中:String URL = "jdbc:mysql://localhost:3306/mydb";

     (3)编写一个sql语句,其中的参数用?来代替,然后将参数写到List里。

执行:pstmt = connection.prepareStatement(sql); 然后将参数从list里取出来填充到pstmt里。

     (4)如果是增、删、改执行:result = pstmt.executeUpdate(); 其中的result是执行完影响的数据库里的行数,也即几条记录。如果是查询执行:resultSet = pstmt.executeQuery(); 返回的类型是ResultSet类型。之后就是把resultSet 弄成Map或List<Map>传递出去,给查询者看。

3.关于查询操作,在得到resultSet后利用getMetaData得到表的结构信息,如getColumnCount()得到有多少个列。String cols_name = metaData.getColumnName(i+1); 得到每个列的属性名称,如是id、username还是pswd.然后从Object cols_value = resultSet.getObject(cols_name);取出来,放到Map或List<Map>里。

4.关于查询里利用的反射操作,步骤如下:

     (1) T resultObject = cls.newInstance(); 利用class文件的newInstance()方法创建一个实例。

     (2)在通过getColumnCount()得到有多少个列之后,进入循环,

                 String cols_name = metaData.getColumnName(i+1);
                 Object cols_value = resultSet.getObject(cols_name);

    读取每一列的属性名字和放的值。通过属性的名字cols_name进行反射:Field field = cls.getDeclaredField(cols_name);这样就得到了Field 等于类里的成员变量,field.setAccessible(true); //打开javabean的访问权限 在利用set方法将从数据库中查出来的cols_value通过JavaBean 也即定义的UserInfo这个类的 set方法赋进去。field.set(resultObject, cols_value);

5.一般意义上,要利用Java的反射需要以下步骤

     (1)加载Class对象,这个一般有两种方式:Class cls1 = UserInfo.class  或

Class cls2 = Class.forName("domain.UserInfo") 后者是利用包名+类名的方法。

   (2)反射出来Class之后干啥事呢?一个类不外乎构造函数成员变量成员函数。所以得到Class之后就可以干这三件事。

     A、关于构造函数,获得Constructor 有四种方法: 

  Constructor getConstructor(Class[] params) 

Constructor[] getConstructors() 

Constructor getDeclaredConstructor(Class[] params) 

  Constructor[] getDeclaredConstructors()  

这四个函数,如果不传参数则是获得所有的构造函数,得到的是一个集合。如果传特定的参数,则是寻找这个特定的构造函数,不带Declared是获得公共的public,带了Declared是可以获得私有构造函数。 得到构造函数后就可以利用反射创建实例了:

 Constructor con1[] = cls1.getDeclaredConstructors();
         con1[1].setAccessible(true);
     Object obj1 = con1[1].newInstance(new Object[]{"tom"}); 如果直接调用clcs.newInstance()则是用默认的构造函数创建实例。

      B、关于成员变量,同样有四种方法:

public Field getDeclaredField(String name)  获取任意指定名字的成员
public Field[] getDeclaredFields()          获取所有的成员变量
public Field getField(String name)          获取任意public成员变量
public Field[] getFields()                  获取所有的public成员变量

本文封装的JdbcUtils类就是利用这种方式操作类里的私有成员变量,记得要setAccessible打开开关。如下:

Field field = cls.getDeclaredField(cols_name);
field.setAccessible(true); //打开javabean的访问权限
field.set(resultObject, cols_value);

    C、关于成员函数,也有四种方法:

public Method[] getMethods()    获取所有的共有方法的集合
public Method getMethod(String name,Class<?>... parameterTypes) 获取指定公有方法 ,

参数1:方法名 参数2:参数类型集合  
public Method[] getDeclaredMethods()  获取所有的方法
public Method getDeclaredMethod(String name,Class<?>... parameterTypes) 获取任意指定方法

下面是利用文中的UserInfo这个类写的一个完成的反射例子,拿到setUsername(String username)方法,然后反射。再拿到getUsername()方法再反射,然后打印出结果:

Class clcs = UserInfo.class;
try {
Object obj = clcs.newInstance();
Method f = clcs.getDeclaredMethod("setUsername", String.class);
f.invoke(obj, "yan123");
Method f2 = clcs.getDeclaredMethod("getUsername", null);
Object name = f2.invoke(obj, null);
System.out.println("反射得到的名字 = "  +  name);


} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

在反射方法的时候,Method f = clcs.getDeclaredMethod("setUsername", String.class); 原函数里的输入参数是什么类型,就写什么类型.class. 如原来的setXXX需要输入参数String,反射的时候就写String.class.

6. JavaBean是反射的一种,反射对构造函数之类的没任何要求,JavaBean要求这个类必须继承Serializable即可串行化,另外构造函数必须为public. 另外,就是JavaBean在得到某个field后可以直接调用set和get,而不必再反射得到method后再执行。

    最后,反射是在程序运行的时候而非编译时!!!

参考:链接1 链接2  链接3

     文中代码下载链接:http://download.csdn.net/detail/yanzi1225627/7398533

posted @ 2016-04-25 10:50  疯子110  阅读(398)  评论(0编辑  收藏  举报