JavaWeb-JDBC连接池&JdbcTemplate&DBUtils

博客
JavaWeb

JDBC连接池概念

概念:其实就是一个容器(集合),存放数据库连接的容器。
当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。

好处:
	1. 节约资源
	2. 用户访问高效

JDBC连接池实现

1.标准接口:DataSource

方法:

  • 获取连接:getConnection()。
  • 归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了,是归还连接。

一般我们不去实现它,有数据库厂商来实现

  • C3P0:数据库连接池技术。
  • DBCP:数据库连接池技术。
  • Druid:数据库连接池实现技术,由阿里巴巴提供的。

2.C3P0:数据库连接池

1.C3P0使用步骤

C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。

1. 导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar,不要忘记导入数据库驱动jar包。
2. 定义配置文件:
	名称: c3p0.properties 或者 c3p0-config.xml。(会自动加载)
	路径:直接将文件放在src目录下即可。
3. 创建核心对象 数据库连接池对象 ComboPooledDataSource。
4. 获取连接:getConnection。

2.C3P0代码实现

/**
 * c3p0的演示
 */
public class C3P0Demo1 {
    public static void main(String[] args) throws SQLException {
        //1.创建数据库连接池对象
        DataSource ds  = new ComboPooledDataSource();//自动加载c3p0-config.xml配置文件
        //2. 获取连接对象
        Connection conn = ds.getConnection();
        //3. 打印
        System.out.println(conn);
		//测试最大连接数(正在连接的数),超过了最大连接数,就会报错。
		//testMaxConnectionNum();
    }
    public static void testMaxConnectionNum() throws SQLException {
        // 1.1 获取DataSource,使用指定名称配置
        DataSource ds  = new ComboPooledDataSource("otherc3p0");
        //2.获取连接
        for (int i = 1; i <= 10 ; i++) {
            Connection conn = ds.getConnection();
            System.out.println(i+":"+conn);
        }
    }
}

3.C3P0工具类

/**
 * C3P0连接池的工具类
 */
public class JDBCUtils3 {
    private static DataSource cpds = new ComboPooledDataSource();//自动加载c3p0-config.xml配置文件
    /**
     * 获取连接
     *
     * @return
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException {
        return cpds.getConnection();
    }
    /**
     * 获取连接池
     *
     * @return
     */
    public static DataSource getDataSource() {
        return cpds;
    }
    /**
     * 增删改有关可以关闭的对象Statement,Connection。
     * @param stmt
     * @param conn
     */
    public static void close(Statement stmt, Connection conn) {
       /*if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }*/
       close(null,stmt,conn);
    }
    /**
     * 查有关可以关闭的对象ResultSet,Statement,Connection。
     * @param resultSet
     * @param stmt
     * @param conn
     */
    public static void close(ResultSet resultSet, Statement stmt, Connection conn) {
        if(resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (stmt!=null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

c3p0-config.xml配置文件

<c3p0-config>
  <!-- 使用默认的配置读取连接池对象 -->
  <default-config>
  	<!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/db4</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/db3</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>

3.DBCP:数据库连接池

1.DBCP使用步骤

DBCP(DataBase connection pool),数据库连接池。是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件。由于建立数据库连接是一个非常耗时耗资源的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。

第一步:引入DBCP连接池的jar包.
单独使用dbcp需要2个包:commons-dbcp.jar,commons-pool.jar
第二步:编写DBCP代码:
     手动设置参数:
     配置文件设置参数:

2.DBCP代码实现

public class DBCPDemo {
  public static void main(String[] args) throws Exception {
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		Properties properties = new Properties();
		try{
			properties.load(new FileInputStream("src/dbcpconfig.properties"));
			DataSource dataSource = BasicDataSourceFactory.createDataSource(properties);
			// 获得连接:
			conn = dataSource.getConnection();
			// 编写SQL:
			String sql = "select * from category";
			// 预编译SQL:
			stmt = conn.prepareStatement(sql);
			// 执行SQL:
			rs = stmt.executeQuery();
			while(rs.next()){
				System.out.println(rs.getInt("cid")+"   "+rs.getString("cname"));
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JDBCUtils.release(rs,stmt, conn);
		}
	}

4.Druid:数据库连接池

1.Druid使用步骤

1. 导入jar包 druid-1.0.9.jar
2. 定义配置文件:
	  是properties形式的。
	  可以叫任意名称,可以放在任意目录下。
3. 加载配置文件。Properties
4. 获取数据库连接池对象:通过工厂来来获取  DruidDataSourceFactory。
5. 获取连接:getConnection。

2.Druid代码实现

/**
 * Druid演示
 */
public class DruidDemo {
    public static void main(String[] args) throws Exception {
        //1.导入jar包
        //2.定义配置文件
        //3.加载配置文件
        Properties pro = new Properties();
        InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
        pro.load(is);
        //4.获取连接池对象
        DataSource ds = DruidDataSourceFactory.createDataSource(pro);
        //5.获取连接
        Connection conn = ds.getConnection();
        System.out.println(conn);
    }
}

3.Druid工具类

/**
 * Druid连接池的工具类
 */
public class JDBCUtils {
    //1.定义成员变量 DataSource
    private static DataSource ds;
    static {
        try {
            //1.加载配置文件
            Properties pro = new Properties();
            pro.load(JDBCUtils2.class.getClassLoader().getResourceAsStream("druid.properties"));
            //2.获取DataSource
            ds = DruidDataSourceFactory.createDataSource(pro);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 获取连接
     */
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
    /**
     * 获取连接池方法
     */
    public static DataSource getDataSource() {
        return ds;
    }
    /**
     * 增删改相关可以关闭的对象Statement,Connection。
     * @param stmt
     * @param conn
     */
    public static void close(Statement stmt, Connection conn) {
       /* if(stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();//归还连接
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }*/
        close(null, stmt, conn);
    }
    /**
     * 查相关可关闭的对象ResultSet,Statement,Connection。
     * @param rs
     * @param stmt
     * @param conn
     */
    public static void close(ResultSet rs, Statement stmt, Connection conn) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();//归还连接
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

druid.properties配置文件

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///mydatabase
username=root
password=root
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000

SpringJDBC

Spring框架对JDBC的简单封装,提供了一个JDBCTemplate对象简化JDBC的开发。
其实Spring框架对JDBC简化了传参,以及对结果集的封装。

1.SpringJDBC使用步骤

1. 导入jar包

在这里插入图片描述

2. 创建JdbcTemplate对象,依赖于数据源DataSource。

JdbcTemplate template = new JdbcTemplate(ds);

3. 调用JdbcTemplate的方法来完成CRUD的操作。

update():执行DML语句,增、删、改语句。
queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合。
	注意:这个方法查询的结果集长度只能是1。
queryForList():查询结果将结果集封装为list集合。
	注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中。
query():查询结果,将结果封装为JavaBean对象。
	query的参数:RowMapper
		一般我们使用BeanPropertyRowMapper实现类,可以完成数据到JavaBean的自动封装。
 		new BeanPropertyRowMapper<类型>(类型.class)。
queryForObject:查询结果,将结果封装为对象。
	一般用于聚合函数的查询。

2.SpringJDBC练习

练习的实体类

public class Emp {
    private Integer id;
    private String ename;
    private Integer job_id;
    private Integer mgr;
    private Date joindate;
    private Double salary;
    private Double bonus;
    private Integer dept_id;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getEname() {
        return ename;
    }
    public void setEname(String ename) {
        this.ename = ename;
    }
    public Integer getJob_id() {
        return job_id;
    }
    public void setJob_id(Integer job_id) {
        this.job_id = job_id;
    }
    public Integer getMgr() {
        return mgr;
    }
    public void setMgr(Integer mgr) {
        this.mgr = mgr;
    }
    public Date getJoindate() {
        return joindate;
    }
    public void setJoindate(Date joindate) {
        this.joindate = joindate;
    }
    public Double getSalary() {
        return salary;
    }
    public void setSalary(Double salary) {
        this.salary = salary;
    }
    public Double getBonus() {
        return bonus;
    }
    public void setBonus(Double bonus) {
        this.bonus = bonus;
    }
    public Integer getDept_id() {
        return dept_id;
    }
    public void setDept_id(Integer dept_id) {
        this.dept_id = dept_id;
    }
    @Override
    public String toString() {
        return "Emp{" +
                "id=" + id +
                ", ename='" + ename + '\'' +
                ", job_id=" + job_id +
                ", mgr=" + mgr +
                ", joindate=" + joindate +
                ", salary=" + salary +
                ", bonus=" + bonus +
                ", dept_id=" + dept_id +
                '}';
    }
}

代码演示

1.修改1号数据的cname为动物园门票。

	JdbcTemplate jt = new JdbcTemplate(JDBCUtils.getDataSource());
	@Test
    public void test1() {
        //1.修改1号数据的cname为动物园门票。
        //String sql = "update tab_category set cname = ? where cid = ?";
        String sql = "update tab_category set cname = ?";
        //返回的是影响的行数
        int row = jt.update(sql, "动物园门票");
        System.out.println(row);//8
    }

2.添加一条记录。

	JdbcTemplate jt = new JdbcTemplate(JDBCUtils.getDataSource());
	@Test
    public void test2() {
        //2.添加一条记录。
        String sql = "insert into tab_category values(?,?)";
        //返回的是影响的行数
        int row = jt.update(sql, 9, "太空游");
        System.out.println(row);
    }

3.删除刚才添加的记录。

	JdbcTemplate jt = new JdbcTemplate(JDBCUtils.getDataSource());
	@Test
    public void test3() {
        //3.删除刚才添加的记录。
        String sql = "delete from tab_category where cid = ?";
        //返回的是影响的行数
        int row = jt.update(sql, 9);
        System.out.println(row);
    }

4. 查询id为1的记录,将其封装为Map集合。

	JdbcTemplate jt = new JdbcTemplate(JDBCUtils.getDataSource());
	@Test
    public void test4() {
        //4. 查询id为1的记录,将其封装为Map集合。
        //String sql = "select * from tab_category where cid = ?";
      //报错:org.springframework.dao.IncorrectResultSizeDataAccessException: Incorrect result size: expected 1, actual 2
        //返回Map集合的长度只能是1。
        String sql = "select * from tab_category where cid = ? or cid = ?";
        Map<String, Object> map = jt.queryForMap(sql, 1, 2);
        System.out.println(map);
    }

5. 查询所有记录,将其封装为List。

	JdbcTemplate jt = new JdbcTemplate(JDBCUtils.getDataSource());
 	@Test
    public void test5() {
        //5. 查询所有记录,将其封装为List。
        String sql = "select * from tab_category";
        List<Map<String, Object>> lists = jt.queryForList(sql);
        for (Map<String, Object> map : lists) {
           System.out.println(map); 
        }
    }

结果:

{cid=1, cname=门票}
{cid=2, cname=酒店}
{cid=3, cname=香港车票}
{cid=4, cname=处境游}
{cid=5, cname=国内游}
{cid=6, cname=港澳游}
{cid=7, cname=抱团定制}
{cid=8, cname=全球自由行}

6. 查询所有记录,将其封装为tab_category对象的List集合。

 	JdbcTemplate jt = new JdbcTemplate(JDBCUtils.getDataSource());
 	//方式1
 	@Test
    public void test6() {
        //6. 查询所有记录,将其封装为tab_category对象的List集合。
        String sql = "select * from tab_category";
        List<Category> categoryList = jt.query(sql, new RowMapper<Category>() {
            @Override
            public Category mapRow(ResultSet resultSet, int i) throws SQLException {
                Category c = new Category();
                //resultSet结果集
                int cid = resultSet.getInt("cid");
                String cname = resultSet.getString("cname");
                //设置结果
                c.setCid(cid);
                c.setCname(cname);
                return c;
            }
        });
        //遍历集合
        for (Category c : categoryList) {
            System.out.println(c);
        }
    }
	//方式2
    @Test
    public void test6_1() {
        //6. 查询所有记录,将其封装为tab_category对象的List集合。
        String sql = "select * from tab_category";
        List<Category> categoryList = jt.query(sql, new BeanPropertyRowMapper<Category>(Category.class));
        for (Category category : categoryList) {
            System.out.println(category);
        }
    }

7. 查询总记录数。

	JdbcTemplate jt = new JdbcTemplate(JDBCUtils.getDataSource());
	@Test
    public void test7() {
        //7. 查询总记录数。
        String sql = "select count(*) from tab_category";
        Integer count = jt.queryForObject(sql, Integer.class);
        System.out.println(count);
    }

8. 将查询记录,封装到Category对象中。

	JdbcTemplate jt = new JdbcTemplate(JDBCUtils.getDataSource());
	@Test
    public void test8() {
        //8.将查询记录,封装到Category对象中。
        String sql = "select * from tab_category where cid = ?";
        Category category = jt.queryForObject(sql, new BeanPropertyRowMapper<Category>(Category.class), 1);
        System.out.println(category);
    }

DBUtils

DBUtils其实和JDBCTemplate是一样的,简单封装了JDBC操作,DBUtils是后来加上的,其实有的人也会用到该工具类。就简单写下。

1.ResultSetHandler

导入依赖commons-dbutils-1.7.jar包

我们知道在执行select语句之后得到的是ResultSet,然后我们还需要对ResultSet进行转换,得到最终我们想要的数据。你可以希望把ResultSet的数据放到一个List中,也可能想把数据放到一个Map中,或是一个Bean中。
DBUtils提供了一个接口ResultSetHandler,它就是用来ResultSet转换成目标类型的工具。你可以自己去实现这个接口,把ResultSet转换成你想要的类型。
DBUtils提供了很多个ResultSetHandler接口的实现,这些实现已经基本够用了,我们通常不用自己去实现ResultSet接口了。

  • MapHandler:单行处理器!把结果集转换成Map<String,Object>,其中列名为键;
  • MapListHandler:多行处理器!把结果集转换成List<Map<String,Object>>;
  • BeanHandler:单行处理器!把结果集转换成Bean,该处理器需要Class参数,即Bean的类型;
  • BeanListHandler:多行处理器!把结果集转换成List;
  • ColumnListHandler:多行单列处理器!把结果集转换成List,使用ColumnListHandler时需要指定某一列的名称或编号,例如:new ColumListHandler(“name”)表示把name列的数据放到List中;
  • ScalarHandler:单行单列处理器!把结果集转换成Object。一般用于聚集查询,例如select count(*) from tab_student;

1.Map处理器

在这里插入图片描述

2.Bean处理器

在这里插入图片描述

3.Column处理器

在这里插入图片描述

4.Scalar处理器

在这里插入图片描述

2.QueryRunner之查询

QueryRunner的查询方法是:
public T query(String sql, ResultSetHandler rh, Object… params)
public T query(Connection con, String sql, ResultSetHandler rh, Object… params)
query()方法会通过sql语句和params查询出ResultSet,然后通过rh把ResultSet转换成对应的类型再返回。

代码演示

	@Test
	
	public void fun1() throws SQLException {
		DataSource ds = JdbcUtils.getDataSource();
		QueryRunner qr = new QueryRunner(ds);
		String sql = "select * from tab_student where number=?";
		//把一行记录转换成一个Map,其中键为列名称,值为列值。
		Map<String,Object> map = qr.query(sql, new MapHandler(), "S_2000");
		System.out.println(map);
	}
	
	@Test
	
	public void fun2() throws SQLException {
		DataSource ds = JdbcUtils.getDataSource();
		QueryRunner qr = new QueryRunner(ds);
		String sql = "select * from tab_student";
		//把转换集转换成List<Map>,其中每个Map对应一行记录。
		List<Map<String,Object>> list = qr.query(sql, new MapListHandler());
		for(Map<String,Object> map : list) {
			System.out.println(map);
		}
	}
	
	@Test
	public void fun3() throws SQLException {
		DataSource ds = JdbcUtils.getDataSource();
		QueryRunner qr = new QueryRunner(ds);
		String sql = "select * from tab_student where number=?";
		//把结果集转换成一个Bean对象,在使用BeanHandler时需要指定Class,即Bean的类型。
		Student stu = qr.query(sql, new BeanHandler<Student>(Student.class), "S_2000");
		System.out.println(stu);
	}
	
	@Test
	public void fun4() throws SQLException {
		DataSource ds = JdbcUtils.getDataSource();
		QueryRunner qr = new QueryRunner(ds);
		String sql = "select * from tab_student";
		//把结果集转换成List<Bean>,其中每个Bean对应一行记录。
		List<Student> list = qr.query(sql, new BeanListHandler<Student>(Student.class));
		for(Student stu : list) {
			System.out.println(stu);
		}
	}
	
	@Test
	public void fun5() throws SQLException {
		DataSource ds = JdbcUtils.getDataSource();
		QueryRunner qr = new QueryRunner(ds);
		String sql = "select * from tab_student";
		多行单例处理器,即获取name列数据。
		List<Object> list = qr.query(sql, new ColumnListHandler("name"));
		for(Object s : list) {
			System.out.println(s);
		}
	}
	
	@Test
	public void fun6() throws SQLException {
		DataSource ds = JdbcUtils.getDataSource();
		QueryRunner qr = new QueryRunner(ds);
		String sql = "select count(*) from tab_student";
		//单行单列处理器,一般用于聚合查询,在使用ScalarHandler时可以指定列名,如果不指定,默认为第1列。
		Number number = (Number)qr.query(sql, new ScalarHandler());
		//对聚合函数的查询结果,有的驱动返回的是Long,有的返回的是BigInteger,所以这里我们把它转换成Number,Number是Long和BigInteger的父类!然后我们再调用Number的intValue()或longValue()方法就OK了。
		int cnt = number.intValue();
		System.out.println(cnt);
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值