Chinaunix首页 | 论坛 | 博客
  • 博客访问: 731169
  • 博文数量: 178
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1507
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-27 23:20
文章分类

全部博文(178)

文章存档

2015年(58)

2014年(121)

我的朋友

分类: Java

2014-12-02 13:49:16

      
利用Java针对MySql封装的jdbc框架类 JdbcUtils 完整实现(包含增删改查、JavaBean反射原理,附源码)
        最近看老罗的视频,跟着完成了利用Java操作MySql数据库的一个框架类JdbcUtils.java,完成对数据库的增删改查。其中查询这块,包括普通的查询和利用反射完成的查询,主要包括以下几个函数接口:

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

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

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

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

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

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

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

下面附完整代码:

JdbcUtils.java

  1. "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, Listparams)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
  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 findSimpleResult(String sql, List params) throws SQLException{  
  86.         Map map = new HashMap();  
  87.         int index  = 1;  
  88.         pstmt = connection.prepareStatement(sql);  
  89.         if(params != null && !params.isEmpty()){  
  90.             for(int i=0; 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
  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> findModeResult(String sql, List params) throws SQLException{  
  117.         List> list = new ArrayList>();  
  118.         int index = 1;  
  119.         pstmt = connection.prepareStatement(sql);  
  120.         if(params != null && !params.isEmpty()){  
  121.             for(int i = 0; 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 map = new HashMap();  
  130.             for(int i=0; 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 findSimpleRefResult(String sql, List params,  
  152.             Class 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
  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
  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  List findMoreRefResult(String sql, List params,  
  190.             Class cls )throws Exception {  
  191.         List list = new ArrayList();  
  192.         int index = 1;  
  193.         pstmt = connection.prepareStatement(sql);  
  194.         if(params != null && !params.isEmpty()){  
  195.             for(int i = 0; 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
  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 params = new ArrayList(); 
  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 params = new ArrayList(); 
  263.         params.add("小明"); 
  264.         boolean flag = jdbcUtils.updateByPreparedStatement(sql, params);*/  
  265.   
  266.         /*******************改*********************/  
  267.         //将名字为李四的密码改了  
  268.         /*      String sql = "update userinfo set pswd = ? where username = ? "; 
  269.         List params = new ArrayList(); 
  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> list = jdbcUtils.findModeResult(sql2, null); 
  279.         System.out.println(list);*/  
  280.   
  281.         //利用反射查询 单条记录  
  282.         String sql = "select * from userinfo where username = ? ";  
  283.         List params = new ArrayList();  
  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.   

  299. 根据上面代码可以看到,数据库名字: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代码如下:

    1. "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.   

    补充说明:


    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传递出去,给查询者看。

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

    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

         文中代码下载链接:

    阅读(1577) | 评论(0) | 转发(0) |
    给主人留下些什么吧!~~