JDBC高级

JDBC高级(连接池&自定义JDBC框架)

数据库连接池

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。这项技术能明显提高对数据库操作的性能.
作用:避免重复创建连接.

C3P0数据库连接池

  1. 导入 jar 包。

    c3p0-0.9.5.2.jar

    mchange-commons-java-0.2.12.jar

  2. 导入配置文件到 src 目录下。

  3. 创建 C3P0 连接池对象。

  4. 获取数据库连接进行使用。

注意:C3P0 的配置文件会自动加载,但是必须叫 c3p0-config.xml 或 c3p0-config.properties 。

C3P0配置文件
<c3p0-config>
  <!-- 使用默认的配置读取连接池对象 -->
  <default-config>
  	<!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/db14</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <!--初始化的连接数量-->
    <property name="initialPoolSize">5</property>
    <!--最大连接数量-->
    <property name="maxPoolSize">10</property>
    <!--超时等待时间-->
    <property name="checkoutTimeout">3000</property>
  </default-config>

  <named-config name="otherc3p0"> 
    <!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/db15</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">8</property>
    <property name="checkoutTimeout">1000</property>
  </named-config>
</c3p0-config>
C3P0小案例
public class Demo1C3p0 {

    public static void main(String[] args) throws SQLException {
        //1.创建连接池,使用默认配置。ComboPooledDataSource实现了DataSource接口
        ComboPooledDataSource ds = new ComboPooledDataSource();
        //2.使用连接池,从连接池中获取10个连接对象
        for (int i = 1; i <= 11; i++) {
            Connection connection = ds.getConnection();
            System.out.println("第" + i + "个连接对象:" + connection);
            //第5个释放
            if (i==5) {
                //放回到连接池中
                connection.close();
            }
        }
    }
}

Druid 数据库连接池

  1. 导入 jar 包。

    druid-1.0.9.jar

  2. 编写配置文件,放在 src 目录下。

  3. 通过 Properties 集合加载配置文件。

  4. 通过 Druid 连接池工厂类获取数据库连接池对象。

  5. 获取数据库连接进行使用。

注意:Druid 不会自动加载配置文件,需要我们手动加载,但是文件的名称可以自定义。

druid配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db3
username=root
password=root
# 初始化连接数量
initialSize=5
# 最大连接数量
maxActive=10
# 超时等待时间
maxWait=3000
druid小案例
public class Demo2Druid {

    public static void main(String[] args) throws Exception {
        //1.从类路径下加载配置文件,获取一个输入流。如果不指定路径,默认是读取同一个包下资源文件
        InputStream inputStream = Demo2Druid.class.getClassLoader().getResourceAsStream("druid.properties");
        //2.使用Properties对象的方法将配置文件中属性加载到Properties对象中
        Properties properties = new Properties();
        //加载了配置文件中所有的属性
        properties.load(inputStream);
        //3.通过druid的工厂类创建连接池
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

        //获取10个连接对象
        for (int i = 1; i <= 11; i++) {
            Connection connection = dataSource.getConnection();
            System.out.println("第" + i + "个连接对象:" + connection);
            //第3个连接关闭
            if (i==3) {
                connection.close();
            }
        }
    }
}

JDBC工具类简单版

/**
 * 访问数据库的工具类
 */
public class JdbcUtils {

    //声明一个连接池对象,使用druid连接池
    private static DataSource dataSource;

    //在类加载的时候就创建连接池
    static {
        //1.从类路径下加载配置文件,获取一个输入流。如果不指定路径,默认是读取同一个包下资源文件
        try (InputStream inputStream = JdbcUtils.class.getResourceAsStream("/druid.properties")) {
            //2.使用Properties对象的方法将配置文件中属性加载到Properties对象中
            Properties properties = new Properties();
            //加载了配置文件中所有的属性
            properties.load(inputStream);
            //3.通过druid的工厂类创建连接池
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接池对象
     * @return
     */
    public static DataSource getDataSource() {
        return dataSource;
    }

    /**
     * 得到数据库的连接
     */
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    /**
     * 关闭连接
     * 查询调用这个方法
     */
    public static void close(Connection connection, Statement statement, ResultSet resultSet) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (statement != null) {
                statement.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    /**
     * 关闭连接
     * 增删改没有结果集
     */
    public static void close(Connection connection, Statement statement) {
        //直接调用上面的方法
        close(connection, statement, null);
    }


    /**
     * 通用的增删改的方法
     * @param sql 要执行的SQL语句
     * @param params 替换占位符的真实地址,在方法内部是一个数组(从0开始)
     * @return 影响的行数
     */
    public static int update(String sql, Object... params) {
        Connection connection = null;
        PreparedStatement ps = null;

        int row = 0;  //影响的行数
        try {
            //1.创建连接对象
            connection = getConnection();
            //2.创建预编译的语句对象
            ps = connection.prepareStatement(sql);
            //2.5 得到参数元数据
            ParameterMetaData metaData = ps.getParameterMetaData();
            int count = metaData.getParameterCount();  //获取有几个参数
            //3.替换占位符为真实的值
            for (int i = 0; i < count; i++) {
                ps.setObject(i + 1, params[i]);  //一定是个对象类型
            }
            //4.执行SQL语句
            row = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(connection, ps);  //调用自己的方法
        }
        return row;
    }

    /**
     * 通用的查询方法
     * @param sql 要执行的SQL语句
     * @param clazz 要实例化的类型,如:Student.class, Employee.class
     * @param params 替换占位符的真实值
     * @return 封装好的集合对象
     */
    public static <T> List<T> query(String sql, Class<T> clazz, Object... params) {
        Connection connection = null;
        PreparedStatement ps = null;
        ResultSet resultSet = null;

        List<T> list = new ArrayList<>();
        try {
            //1.创建连接对象
            connection = getConnection();
            //2. 创建预编译的语句对象
            ps = connection.prepareStatement(sql);
            //2.5 得到参数元数据(源信息)
            ParameterMetaData metaData = ps.getParameterMetaData();
            int count = metaData.getParameterCount();  //获取有几个参数
            //3.替换占位符为真实的值
            for (int i = 0; i < count; i++) {
                ps.setObject(i + 1, params[i]);  //一定是个对象类型
            }
            //4.执行查询操作
            resultSet = ps.executeQuery();
            //5.遍历整个结果集,封装到集合中,每个元素是一个对象
            while (resultSet.next()) {
                //每条记录封装成一个对象,创建一个对象
                T obj = clazz.getConstructor().newInstance();
                //先得到实体类中有哪些属性
                Field[] fields = clazz.getDeclaredFields();  //得到所有成员变量,包含私有的
                //遍历每个成员变量,进行赋值
                for (Field field : fields) {
                    //私有的要暴力
                    field.setAccessible(true);
                    //列名=属性名
                    String name = field.getName();
                    //要赋值的对象,值
                    field.set(obj, resultSet.getObject(name));   //从结果集中获取数据
                }
                //6.添加到集合中
                list.add(obj);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            close(connection, ps, resultSet);
        }
        return list;
    }
}
使用工具类
/**
 * 使用工具类
 */
public class Demo3UseUtils {

    public static void main(String[] args) {
        //使用工具类添加1条记录
        int row = JdbcUtils.update("insert into student values(null,?,?,?)", "嫦娥", 0, "1997-07-07");
        System.out.println("添加了" + row + "条");

        //使用工具类查询所有的数据
        List<Student> students = JdbcUtils.query("select * from student", Student.class);
        //打印
        students.forEach(System.out::println);
    }
}

JDBC工具类加强版(自定义JDBC框架)

DataSourceUtils.java
/*
    数据库连接池的工具类
 */
public class DataSourceUtils {
    //1.私有构造方法
    private DataSourceUtils(){}

    //2.声明数据源变量
    private static DataSource dataSource;

    //3.提供静态代码块,完成配置文件的加载和获取数据库连接池对象
    static{
        try{
            //完成配置文件的加载
            InputStream is = DataSourceUtils.class.getClassLoader().getResourceAsStream("druid.properties");

            Properties prop = new Properties();
            prop.load(is);

            //获取数据库连接池对象
            dataSource = DruidDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //4.提供一个获取数据库连接的方法
    public static Connection getConnection() {
        Connection con = null;
        try {
            con = dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return con;
    }

    //5.提供一个获取数据库连接池对象的方法
    public static DataSource getDataSource() {
        return dataSource;
    }

    //6.释放资源
    public static void close(Connection con, Statement stat, ResultSet rs) {
        if(con != null) {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(stat != null) {
            try {
                stat.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static void close(Connection con, Statement stat) {
        if(con != null) {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(stat != null) {
            try {
                stat.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
Student.java(实体类)
/*
    学生的实体类
 */
public class Student {
    private Integer sid;
    private String name;
    private Integer age;
    private Date birthday;

    public Student() {
    }

    public Student(Integer sid, String name, Integer age, Date birthday) {
        this.sid = sid;
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public Integer getSid() {
        return sid;
    }

    public void setSid(Integer sid) {
        this.sid = sid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Student{" +
                "sid=" + sid +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                '}';
    }
}
ResultSetHandler.java
/*
    用于处理结果集方式的接口
 */
public interface ResultSetHandler<T> {
    <T> T handler(ResultSet rs);
}
BeanHandler.java
/*
    实现类1:用于将查询到的一条记录,封装为Student对象并返回
 */
//1.定义一个类,实现ResultSetHandler接口
public class BeanHandler<T> implements ResultSetHandler<T>{
    //2.定义Class对象类型变量
    private Class<T> beanClass;

    //3.通过有参构造为变量赋值
    public BeanHandler(Class<T> beanClass) {
        this.beanClass = beanClass;
    }

    //4.重写handler方法。用于将一条记录封装到自定义对象中
    @Override
    public T handler(ResultSet rs) {
        //5.声明自定义对象类型
        T bean = null;
        try {
            //6.创建传递参数的对象,为自定义对象赋值
            bean = beanClass.newInstance();

            //7.判断结果集中是否有数据
            if(rs.next()) {
                //8.通过结果集对象获取结果集源信息的对象
                ResultSetMetaData metaData = rs.getMetaData();
                //9.通过结果集源信息对象获取列数
                int count = metaData.getColumnCount();

                //10.通过循环遍历列数
                for(int i = 1; i <= count; i++) {
                    //11.通过结果集源信息对象获取列名
                    String columnName = metaData.getColumnName(i);

                    //12.通过列名获取该列的数据
                    Object value = rs.getObject(columnName);

                    //13.创建属性描述器对象,将获取到的值通过该对象的set方法进行赋值
                    PropertyDescriptor pd = new PropertyDescriptor(columnName.toLowerCase(),beanClass);
                    //获取set方法
                    Method writeMethod = pd.getWriteMethod();
                    //执行set方法,给成员变量赋值
                    writeMethod.invoke(bean,value);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //14.返回封装好的对象
        return bean;
    }
}
BeanListHandler.java
/*
    实现类2:用于将查询到的多条记录,封装为Student对象并添加到集合返回
 */
//1.定义一个类,实现ResultSetHandler接口
public class BeanListHandler<T> implements ResultSetHandler<T>{
    //2.定义Class对象类型变量
    private Class<T> beanClass;

    //3.通过有参构造为变量赋值
    public BeanListHandler(Class<T> beanClass) {
        this.beanClass = beanClass;
    }

    //4.重写handler方法。用于将多条记录封装到自定义对象中并添加到集合返回
    @Override
    public List<T> handler(ResultSet rs) {
        //5.声明集合对象类型
        List<T> list = new ArrayList<>();
        try {
            //6.判断结果集中是否有数据
            while(rs.next()) {
                //7.创建传递参数的对象,为自定义对象赋值
                T bean = beanClass.newInstance();

                //8.通过结果集对象获取结果集源信息的对象
                ResultSetMetaData metaData = rs.getMetaData();
                //9.通过结果集源信息对象获取列数
                int count = metaData.getColumnCount();

                //10.通过循环遍历列数
                for(int i = 1; i <= count; i++) {
                    //11.通过结果集源信息对象获取列名
                    String columnName = metaData.getColumnName(i);

                    //12.通过列名获取该列的数据
                    Object value = rs.getObject(columnName);

                    //13.创建属性描述器对象,将获取到的值通过该对象的set方法进行赋值
                    PropertyDescriptor pd = new PropertyDescriptor(columnName.toLowerCase(),beanClass);
                    //获取set方法
                    Method writeMethod = pd.getWriteMethod();
                    //执行set方法,给成员变量赋值
                    writeMethod.invoke(bean,value);
                }
                //将对象保存到集合中
                list.add(bean);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //14.返回封装好的对象
        return list;
    }
}
ScalarHandler.java
/*
    1.定义一个类,实现ResultSetHandler接口
    2.重写handler方法
    3.定义一个Long类型变量
    4.判断结果集对象中是否还有数据
    5.获取结果集源信息的对象
    6.获取第一列的列名
    7.根据列名获取该列的值
    8.返回结果
 */
//1.定义一个类,实现ResultSetHandler接口
public class ScalarHandler<T> implements ResultSetHandler<T> {

    //2.重写handler方法
    @Override
    public Long handler(ResultSet rs) {
        //3.定义一个Long类型变量
        Long value = null;
        try{
            //4.判断结果集对象中是否还有数据
            if(rs.next()) {
                //5.获取结果集源信息的对象
                ResultSetMetaData metaData = rs.getMetaData();
                //6.获取第一列的列名
                String columnName = metaData.getColumnName(1);
                //7.根据列名获取该列的值
               value = rs.getLong(columnName);
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        //8.返回结果
        return value;
    }
}
JDBCTemplate.java(框架)
/*
    JDBC框架类
 */
public class JDBCTemplate {
    //1.定义参数变量(数据源、连接对象、执行者对象、结果集对象)
    private DataSource dataSource;
    private Connection con;
    private PreparedStatement pst;
    private ResultSet rs;

    //2.通过有参构造为数据源赋值
    public JDBCTemplate(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    /*
        查询方法:用于将聚合函数的查询结果进行返回
     */
    public Long queryForScalar(String sql, ResultSetHandler<Long> rsh, Object...objs){
        Long value = null;

        try{
            //通过数据源获取一个数据库连接
            con = dataSource.getConnection();

            //通过数据库连接对象获取执行者对象,并对sql语句进行预编译
            pst = con.prepareStatement(sql);

            //通过执行者对象获取参数的源信息对象
            ParameterMetaData parameterMetaData = pst.getParameterMetaData();
            //通过参数源信息对象获取参数的个数
            int count = parameterMetaData.getParameterCount();

            //判断参数数量是否一致
            if(count != objs.length) {
                throw new RuntimeException("参数个数不匹配");
            }

            //为sql语句占位符赋值
            for(int i = 0; i < objs.length; i++) {
                pst.setObject(i+1,objs[i]);
            }

            //执行sql语句并接收结果
            rs = pst.executeQuery();

            //通过ScalarHandler方式对结果进行处理
            value = rsh.handler(rs);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            DataSourceUtils.close(con,pst,rs);
        }

        //返回结果
        return value;
    }

    /*
        查询方法:用于将多条记录封装成自定义对象并添加到集合返回
     */
    public <T> List<T> queryForList(String sql, ResultSetHandler<T> rsh, Object...objs){
        List<T> list = new ArrayList<>();

        try{
            //通过数据源获取一个数据库连接
            con = dataSource.getConnection();

            //通过数据库连接对象获取执行者对象,并对sql语句进行预编译
            pst = con.prepareStatement(sql);

            //通过执行者对象获取参数的源信息对象
            ParameterMetaData parameterMetaData = pst.getParameterMetaData();
            //通过参数源信息对象获取参数的个数
            int count = parameterMetaData.getParameterCount();

            //判断参数数量是否一致
            if(count != objs.length) {
                throw new RuntimeException("参数个数不匹配");
            }

            //为sql语句占位符赋值
            for(int i = 0; i < objs.length; i++) {
                pst.setObject(i+1,objs[i]);
            }

            //执行sql语句并接收结果
            rs = pst.executeQuery();

            //通过BeanListHandler方式对结果进行处理
            list = rsh.handler(rs);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            DataSourceUtils.close(con,pst,rs);
        }

        //返回结果
        return list;
    }

    /*
        查询方法:用于将一条记录封装成自定义对象并返回
     */
    public <T> T queryForObject(String sql, ResultSetHandler<T> rsh,Object...objs){
        T obj = null;

        try{
            //通过数据源获取一个数据库连接
            con = dataSource.getConnection();

            //通过数据库连接对象获取执行者对象,并对sql语句进行预编译
            pst = con.prepareStatement(sql);

            //通过执行者对象获取参数的源信息对象
            ParameterMetaData parameterMetaData = pst.getParameterMetaData();
            //通过参数源信息对象获取参数的个数
            int count = parameterMetaData.getParameterCount();

            //判断参数数量是否一致
            if(count != objs.length) {
                throw new RuntimeException("参数个数不匹配");
            }

            //为sql语句占位符赋值
            for(int i = 0; i < objs.length; i++) {
                pst.setObject(i+1,objs[i]);
            }

            //执行sql语句并接收结果
            rs = pst.executeQuery();

            //通过BeanHandler方式对结果进行处理
            obj = rsh.handler(rs);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            DataSourceUtils.close(con,pst,rs);
        }

        //返回结果
        return obj;
    }

    /*
        用于执行增删改功能的方法
     */
    //3.定义update方法。参数:sql语句、sql语句中的参数
    public int update(String sql,Object...objs) {
        //4.定义int类型变量,用于接收增删改后影响的行数
        int result = 0;

        try{
            //5.通过数据源获取一个数据库连接
            con = dataSource.getConnection();

            //6.通过数据库连接对象获取执行者对象,并对sql语句进行预编译
            pst = con.prepareStatement(sql);

            //7.通过执行者对象获取参数的源信息对象
            ParameterMetaData parameterMetaData = pst.getParameterMetaData();
            //8.通过参数源信息对象获取参数的个数
            int count = parameterMetaData.getParameterCount();

            //9.判断参数数量是否一致
            if(count != objs.length) {
                throw new RuntimeException("参数个数不匹配");
            }

            //10.为sql语句占位符赋值
            for(int i = 0; i < objs.length; i++) {
                pst.setObject(i+1,objs[i]);
            }

            //11.执行sql语句并接收结果
            result = pst.executeUpdate();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //12.释放资源
            DataSourceUtils.close(con,pst);
        }

        //13.返回结果
        return result;
    }
}
JDBCTemplateTest.java(测试)
/*
    模拟dao层
 */
public class JDBCTemplateTest {

    private JDBCTemplate template = new JDBCTemplate(DataSourceUtils.getDataSource());

    @Test
    public void queryForScalar() {
        //查询聚合函数的测试
        String sql = "SELECT COUNT(*) FROM student";
        Long value = template.queryForScalar(sql,new ScalarHandler<Long>());
        System.out.println(value);
    }

    @Test
    public void queryForList() {
        //查询所有学生信息的测试
        String sql = "SELECT * FROM student";
        List<Student> list = template.queryForList(sql, new BeanListHandler<>(Student.class));
        for(Student stu : list) {
            System.out.println(stu);
        }
    }

    @Test
    public void queryForObject() {
        //查询一条记录并封装自定义对象的测试
        String sql = "SELECT * FROM student WHERE sid=?";
        Student stu = template.queryForObject(sql,new BeanHandler<>(Student.class),1);
        System.out.println(stu);
    }

    @Test
    public void delete() {
        //删除数据的测试
        String sql = "DELETE FROM student WHERE name=?";
        int result = template.update(sql, "周七");
        System.out.println(result);
    }

    @Test
    public void update() {
        //修改数据的测试
        String sql = "UPDATE student SET age=? WHERE name=?";
        Object[] params = {37,"周七"};
        int result = template.update(sql, params);
        System.out.println(result);
    }

    @Test
    public void insert() {
        //新增数据的测试
        String sql = "INSERT INTO student VALUES (?,?,?,?)";
        Object[] params = {5,"周七",27,"1997-07-07"};
        int result = template.update(sql, params);
        if(result != 0) {
            System.out.println("添加成功");
        }else {
            System.out.println("添加失败");
        }
    }
}
策略设计模式
  • 执行者
  • 策略
    • 策略的实现
  • ​ 调用者
    • 创建策略传递给执行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值