JavaWeb使用c3p0,dbutils以及泛型反射抽取Dao

1. 泛型概念,泛型类,泛型方法,泛型接口以及用法

泛型只在编译时期有效,编译后的字节码文件中不存在泛型信息,这一点对于我们判断泛型使用规范很有帮助。例如

通常情况下,方法中接受的参数列表如果被写为

public void save(List<? extends Number> list){
    System.out.println(list.get(0));
}

就代表,传入的List集合中元素,必须是数字包装类,例如Integer,Double,Float等—Number类型规定了List结合中类型的上限。因此,如果我们调用该方法时使用

//1#
List<String> list = new ArrayList<String>();
list.add("BJTShang")
save(list); 

或者

//2#
List<String> list = new ArrayList();
list.add("BJTShang")
save(list); 

则必然报错。

但是,如果我们的调用代码是这样的:

//3#
List list = new ArrayList<String>();
list.add("BJTShang");
save(list);

或者是这样的:

//4##
List list = new ArrayList();
list.add("BJTShang");
save(list);

就只会提示类型警告,而不会报错,也可以正常打印出BJTShang。

原因就是泛型擦除:
泛型只在编译时期有效,编译后的字节码文件中不存在泛型信息。

3#和4#代码能够正常运行并得出结果的原因就在于,在编译时期,只检查引用类型list,因此编译通过。虽然实际上传入的类型是不符合的,但是在编译后的字节码文件中是没有泛型信息的,因此此时已经没有泛型约束。相当于普通的List集合类。

2. 泛型的反射

在案例中设置通用方法,会用到反射泛型!

案例分析,涉及的API,演示优化

案例分析、实现

修改数据库字段名字或者类型:

ALTER TABLE account CHANGE COLUMN id newid VARCHAR(20);

注意,有外键关联的字段,不能修改!

Type接口是所有Java类型的默认接口:

包括:引用类型;原始类型(基本数据类型);参数化类型,ParameterizedType,也就是JDK1.5之后引入的泛型,例如:”ArrayList”

通过泛型的反射,可以获得参数化类型

泛型反射的典型应用:

MVC模式中,模型层的Dao,通常需要处理多种数据,例如,通过继承泛型父类BaseDao,在实现时,指定泛型T的类型(AdminBaseDao extends BaseDao)。但是,由于数据操作通常是类似的,希望把处理数据的通用方法(例如T findById(int id))抽取到父类BaseDao中处理,那么就需要在BaseDao类中知道子类封装的对象类型,因此需要通过参数化类型的反射获取。

使用D3P0连接池技术连接数据库

  1. 需要导入两个jar包:数据库连接包(mysql-connector.jar)和D3P0工具包(c3p0.jar);
    • 而使用DBCP连接池,需要导入三个包(包括一个commons-pool.jar);
  2. 配置c3p0-config.xml文件;
  3. 使用ComboPooledDataSource获取数据库的数据源,相当于在数据库中完成了连接登录,已经使用了”USE DATABASE databasename”脚本;

案例:使用泛型反射抽取Dao层

为了方便获取结果集,引入Dbutils技术:导入commons-dbutils.jar包,如果是Java项目,在项目根目录下新建一个lib文件夹放入后build path;如果是JavaWeb项目,将jar包放入WEB-INF文件夹下的lib文件夹中再build path。

1. 结合C3P0和DBUtils,操作数据库
  1. 导jar包(3个);
  2. 在src目录下配置c3p0-config.xml文件:

    <c3p0-config>
      <default-config>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/day27</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="user">root</property>
        <property name="password">root</property>
        <property name="initialPoolSize">10</property>
        <property name="maxPoolSize">25</property>
        <property name="maxIdleTime">3000</property>
      </default-config>
    </c3p0-config>
    
  3. 编写JdbcUtils类:

    package com.cityu.utils;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.Statement;
    import java.sql.SQLException;
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    import org.apache.commons.dbutils.QueryRunner;
    /**
     * Jdbc工具类,需要使用c3p0和dbutils技术
     * @author shangxu2-c
     *
     */
    public class JdbcUtils {
    
        private static ComboPooledDataSource ds = null;
    
        static{
            //使用类时初始化,根据c3p0-config.xml配置文件
    
            //1. 加载数据库驱动
            //2. 根据通信协议获得数据库Url
            //3. 根据用户名密码登陆数据库并取得连接池配置
            //4. 拿到数据源,其中包含了所有的数据库连接池配置信息
            ds = new ComboPooledDataSource();
        }
    
        public static Connection getConnection() throws Exception {
            return ds.getConnection();
        }
    
        //dbutils工具方法,封装数据库操作方法
        public static QueryRunner getQueryRunner(){
            return new QueryRunner(ds);
        }
    
        /*public static void release(Connection conn,Statement st,ResultSet rs){
            if (rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            if (st!=null) {
                try {
                    st.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            if (conn!=null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }*/
    }
    
2. 抽取DAO层到BaseDao中完成对不同实体类的CRUD

首先,实体类名必须和数据库表名一致,这样,通过泛型中的参数化类型才可以可以获得数据库表名,用于sql语句;

package com.cityu.basedao;
//实体类名必须对应数据库中表名(数据库中不区分大小写)
public class Admin {
    private int id;
    private String username;
    private String pwd;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    @Override
    public String toString() {
        return "Admin [id=" + id + ", username=" + username + ", pwd=" + pwd
                + "]";
    }
}

接下来,实体类的Dao类直接继承泛型基类BaseDao,通过泛型向上抽取统一方法。这样,对于不同的实体类,均可以通过BaseDao具体实现操作数据库。

public class AdminDao extends BaseDao<Admin> {
}

最后是编写BaseDao泛型类

package com.cityu.basedao;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import com.cityu.utils.JdbcUtils;

//实体类型通过T传入
public class BaseDao<T> {
    private Class clazz;
    private String tableName;

    public BaseDao(){
        //获取参数类型
        ParameterizedType type 
            = (ParameterizedType) this.getClass().getGenericSuperclass();
        Type[] types = type.getActualTypeArguments();
        clazz = (Class) types[0];
        //获取数据库表名
        tableName = clazz.getSimpleName();//getName()方法获取类全名
    }

    public T findById(int id){
        String sql;
        try {
            sql = "SELECT * FROM "+tableName+" WHERE id = ?";
            return JdbcUtils.getQueryRunner().query(sql, new BeanHandler<T>(clazz), id);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
3. 泛型反射

在测试类或者service层中,直接调用BaseDao中的方法,即可完成对多个实体类的操作
package com.cityu.utils;

import org.junit.Test;
import com.cityu.basedao.Admin;
import com.cityu.basedao.AdminDao;

public class TestApp {
    @Test
    public void test() throws Exception {
        //在service层中,通常使用工厂方法创建实体Dao
        AdminDao adminDao = new AdminDao();
        Admin admin = adminDao.findById(2);
        System.out.println(admin);
    }
}

你可能感兴趣的:(java,Web,泛型,c3p0,C语言)