javaweb-day06-jdbc连接池

JDBC连接池&JDBCTemplate

  • jdbc连接池
    • 程序和数据库之间的连接是底层技术,每一次连接都比较耗时,而用完后又得关闭连接释放资源,这样反复连接和释放其实是很浪费时间的,因此引出一个连接池技术,来管理这些连接对象。连接对象被使用完后,会归还给连接池,等待分配给下一次使用,而不是销毁。
  • jdbcTemplate
    • jdbc操作中,很多的代码大量重复出现,其实我们写熟练以后,发现只需要关注sql怎么写就可以,所以对重复出现的代码进行封装来简化jdbc的操作。

一.数据库连接池

1. 概述

  • 打个比方,过独木桥。

    没有连接池时,一人一个独木桥,过河就拆,所以每来一个人过河就要搭建一个新的独木桥。

    有了连接池后,就相当于建了一座大桥,可以同时让多个人通过,不需要一直建,一直拆。

  • 画图理解。

在这里插入图片描述

2. 代码实现介绍

  • java.sql.DataSuorce 接口,就是表示连接池

    • getConnection()方法 可以获取连接对象
  • 数据源接口的实现由连接池厂商实现

    • c3p0 古老的,常被hibernate框架使用
    • druid 阿里的产品,效率很高
  • 如果连接对象是由连接池得到的,那么它的Connection.close方法将不再表示关闭连接,而是归还连接对象到连接池。

3. c3p0连接池

3.1 基本使用

  • 导jar包 – 两个连接池 一个数据库驱动 共3个
  • 配置文件简介
<?xml version="1.0" encoding="utf-8" ?>
<c3p0-config>
  <!-- 使用默认的配置读取连接池对象 -->
  <default-config>
  	<!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/db1</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="myc3p0"> 
    <!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/db2</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">20</property>
    <property name="checkoutTimeout">5000</property>
  </named-config>


</c3p0-config>
  • 注意事项:

    1. c3p0-config.xml 文件名必须这么命名
    2. c3p0-config.xml 文件必须放在src目录下,不能放在子目录
  • 可能会出错的地方

    • 配置文件中书写错误
      • 文件名或路径错误
      • 数据库连接四大参数书写错误,或多加空格
    • 忘记导入驱动jar包
    public static void main(String[] args) throws SQLException {
        //创建连接池数据源对象
            ComboPooledDataSource ds = new ComboPooledDataSource();
        //获得连接对象
            Connection con = ds.getConnection();
        //输出连接对象的地址值表示连接正常
            System.out.println(con);
        }
    

3.2 熟悉配置文件

  • 测试最大连接数

    //不给参数,默认使用default-config配置的数据源
    ComboPooledDataSource ds = new ComboPooledDataSource();
    //循环创建11个连接对象
    for (int i=1;i<=11;i++){
            Connection con = ds.getConnection();
            System.out.println(i+":"+con);
             if(i==6){
                  con.close();//归还第6个对象给连接池
              }
      }
    
  • 测试超时时间

  • 测试命名的数据源

    ComboPooledDataSource ds = new ComboPooledDataSource("otherc3p0"); 
    

4. druid连接池

4.1 基本使用

  • 导入jar包-- 1个

  • 定义配置文件 druid.properties

  • 代码演示

    //1.导入jar包,定义配置文件
    //2.加载配置文件
    Properties pro = new Properties();
    InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties"); 		       pro.load(is);
    //3.获取连接池对象
    DataSource ds = DruidDataSourceFactory.createDataSource(pro);
    //4.获取连接对象
    Connection con = ds.getConnection();
    System.out.println(con);
    

4.2 工具类

  • 代码演示

    public class JDBCUtil {
        //1.定义一个数据源成员属性
        private static DataSource ds;
        //2.在静态代码块中加载配置文件
        static {
            try {
                Properties pro = new Properties();
                InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("druid.properties");
                pro.load(is);
            //3.创建连接池对象
                ds = DruidDataSourceFactory.createDataSource(pro);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //获取连接对象的方法
        public static Connection getConnection() throws SQLException {
            return  ds.getConnection();
        }
        //获取连接池对象的方法
        public static DataSource getDataSource(){
            return ds;
        }
        
    //释放资源的方法
        public void close(Statement stmt, Connection con, ResultSet rs){
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(con!=null){
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    

4.3 工具类测试

  • 代码演示–向account表中添加一条数据

    public static void main(String[] args) {
            Connection con=null;
            PreparedStatement pstmt=null;
            try {
                //1.获取连接对象
                con = JDBCUtil.getConnection();
                //2.定义sql
                String sql="insert into account values (null,?,?)";
                //3.创建pstmt对象
                pstmt = con.prepareStatement(sql);
                //4.给?赋值
                pstmt.setString(1,"曹操");
                pstmt.setDouble(2,3000);
                //5.执行sql
                int count = pstmt.executeUpdate();
                System.out.println(count);
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                //6.释放资源
                JDBCUtil.close(pstmt,con);
            }
        }
    

总结:

1.什么是连接池

1.就是一个容器
2.容器中装的是connection连接对象
3.这些连接对象创建后可以反复被使用,并不会销毁
4.它们是共享的

2.连接对象和连接池对象

connection 连接
DataSource 连接池 -- 数据源

获取;
DataSource ds=new DruidDataSource();
ds.getConnection();
-- 通过数据源获取数据,其实就是通过连接池获取连接

3.常用的连接池

c3p0   hibernate 传统的orm框架 
druid  国产的 阿里

4.连接池的好处

1.节约资源 提高效率

二.jdbcTemplate

1. 简介

  • Spring框架对jdbc的简单封装,提供了一个JdbcTemplate对象
  • jdbcTemplate的若干方法
    • update 执行 dml增删改
    • queryForMap() 查询结果,将结果集封装为map集合
    • queryForList() 查询结果,将结果集封装为list集合
    • queryForObject() 查询结果集,将结果集封装成某个数据类型
    • query() 查询结果集,将结果集封装为Javabean对象

2. 快速入门

  • 代码演示–修改曹操的金额为5000

    public static void main(String[] args) {
            //1.导入jar包
            //2.创建jdbcTemplate对象
            JdbcTemplate template = new JdbcTemplate(JDBCUtil.getDataSource());
            //3.定义sql语句
            String sql="update account set balance=5000 where id=?";
            // 4.调用update方法,并给?赋值
            int count = template.update(sql, 3);
            System.out.println(count);
        }
    

3. jdbcTemplate综合练习

  1. 修改id为1的数据
  2. 添加一条数据
  3. 删除一条数据
  4. 查询id为1的一条记录,封装成map
  5. 查询id为1的一条记录,封装成Account
  6. 查询所有记录,封装成list
  7. 查询所有记录,封装成泛型为Account的List
  8. 查询总记录数
public class DruidDemo3 {

    private JdbcTemplate template= new JdbcTemplate(JDBCUtil.getDataSource());
    @Test//修改
    public void test1(){
        int count = template.update("update account set balance=? where id=?",888,1);
        System.out.println(count);
    }
    @Test//新增
    public void test2(){
        int count = template.update("insert account values (null,?,?)","哪吒",666);
        System.out.println(count);
    }
    @Test//删除
    public void test3(){
        int count = template.update("delete from account where id=?",3);
        System.out.println(count);
    }
    @Test//查询一条 封装map
    public void test4(){
        Map<String, Object> map = template.queryForMap("select * from account where id=?", 1);
        System.out.println(map);
    }
    @Test//查询一条 封装javaBean
    public void test5(){
        Account account = template.queryForObject("select * from account where id=?", new BeanPropertyRowMapper<Account>(Account.class),2);
        System.out.println(account);
    }
    @Test//查询所有,封装成List中泛型为Map
    public void test6(){
        List<Map<String, Object>> list = template.queryForList("select * from account ");
        System.out.println(list);
    }
    @Test//查询所有,封装成List中泛型为JavaBean
    public void test7(){
        List<Account> list = template.query("select * from account ", new BeanPropertyRowMapper<Account>(Account.class));
        System.out.println(list);
    }
    @Test//查询总记录数
    public void test8(){
        Integer a = template.queryForObject("select count(*) from account ", Integer.class);
        System.out.println(a);
    }
}

补充

1.部门表和员工表的查询并关联封装

 @Test//每一个员工和他对应得部门信息
    public void test2(){
        List<Emp> emps = template.query("select * from emp ", new BeanPropertyRowMapper<Emp>(Emp.class));
        //关联每个部门下 的多个员工信息
        for (Emp emp : emps) {
            emp.setDept(template.queryForObject("select * from dept where id=?",new BeanPropertyRowMapper<Dept>(Dept.class),emp.getDept_id()));
        }
        //输出
        System.out.println(emps);
    }

    @Test//查询所有的部门下所有的员工
    public void test1(){
        List<Dept> depts = template.query("select * from dept ", new BeanPropertyRowMapper<Dept>(Dept.class));
        //关联每个部门下 的多个员工信息
        for (Dept dept : depts) {
            dept.setEmps(template.query("select * from emp where dept_id=?",new BeanPropertyRowMapper<Emp>(Emp.class),dept.getId()));
        }
        //输出
        System.out.println(depts);
    }

2.三层架构

controller  控制层
service  业务层  --包含接口和实现类
dao   执行层   --包含接口和实现类

controller层 --调用--> service层 --调用--> dao层
注意:
	接口和实现类的正确命名

3.template结合BeanPropertyRowMapper封装的模拟实现

@Test
    public void testQuery1(){
        List<Emp> emps = myQuery("SELECT * FROM EMP WHERE ID> ?", Emp.class, 3);
        System.out.println(emps);
    }

    // 结合反射和原始的jdbc模拟查询和封装的实现
    public <T> List<T> myQuery(String sql, Class<T> c,Object ...args){
        try {
            Class.forName("com.mysql.jdbc.Driver");
            Connection con = DriverManager.getConnection("jdbc:mysql:///db3","root","root");
            //3.获取执行sql的对象
            PreparedStatement pstm = con.prepareStatement(sql);
            //4.给占位符赋值
            for (int i = 0; i < args.length; i++) {
                pstm.setObject(i+1,args[i]);
            }
            //5.执行sql
            ResultSet rs = pstm.executeQuery();
            //6.处理结果集--拆开rs
            //元数据--可以获取结果集中的列数,列名,列类型
            ResultSetMetaData md = rs.getMetaData();
            //获取总列数
            int columnCount = md.getColumnCount();
            ArrayList<T> ts = new ArrayList<>();
            while (rs.next()){//外层循环遍历每一行
                T t = c.newInstance();
                for (int i = 1; i <= columnCount; i++) {//外层循环遍历每一行的每一个单元格
                    Object value = rs.getObject(i);
                    String columnName = md.getColumnName(i).toLowerCase();//获取每一个列的列名--和T中的属性名一致的
                    String columnName1 = md.getColumnLabel(i);//获取每一个列的列名--和T中的属性名一致的
                    String columnName2 = md.getColumnClassName(i);//获取每一个列的列名--和T中的属性名一致的
                    System.out.println(columnName+"--"+columnName1+"--"+columnName2);
                    Field f = c.getDeclaredField(columnName);
                    f.setAccessible(true);//开启私有属性的操作权限
                    f.set(t,value);
                }
                ts.add(t);

            }
            return ts;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    } 
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页