1. 数据库连接池
其实就是一个容器(集合),存放数据库连接的容器。当系统初始化好后,容器被创建,容器中会申请一些连接对象。当用户来访问数据库时,从容器中获取连接对象,用户访问完后,会将连接对象归还给容器。
1.1 好处
- 节约资源
 - 用户访问高效
 
1.2 实现
标准接口:DataSource ,javax.sql包下的,主要方法如下:
- 获取连接:
getConnection() - 归还连接:
close()。 如果连接对象Connection是从连接池中获取的,那么调用close()方法,则不会关闭连接,而是归还连接。 
一般我们不去实现它,有数据库厂商来实现
- C3P0:数据库连接池技术
 - Druid:数据库连接池实现技术,由阿里巴巴提供的
 
2. C3P0数据库连接池技术
2.1 导入Jar包
下载完后解压,然后导入两个包:c3p0-0.9.5.2.jar和mchange-commons-java-0.2.12.jar

Notice:不要忘记导入数据库驱动Jar包
2.2 定义配置文件
- 名称:
c3p0.properties或者c3p0-config.xml - 路径:将文件放在src目录下即可。
 
2.3 创建核心对象
- 数据库连接池对象:
ComboPooledDataSource - 基本使用如下:
 
public class C3P0Demo1 {
    public static void main(String[] args) throws SQLException {
        // 1. 创建数据库连接池对象
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        // 2. 获取一个连接对象
        Connection conn = dataSource.getConnection();
        // 3. 进行具体操作
        System.out.println(conn);
    }
}
3. Druid:数据库连接池实现技术
3.1 使用步骤
- 导入jar包:
druid-1.0.9.jar - 定义配置文件:
properties形式的,可以叫任意名称,可以放任意目录下 - 加载配置文件:使用
Properties对象来加载 - 获取数据库连接池对象:通过工厂类
DruidDataSourceFactory来获取 - 获取连接:
getConnection 
3.2 基本使用示例
// Druid演示
public class DruidDemo1 {
    public static void main(String[] args) throws Exception {
        // 1. 定义配置文件
        // 2. 加载配置文件
        Properties pro = new Properties();
        InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");
        // 3. 获取连接池对象
        DataSource ds = DruidDataSourceFactory.createDataSource(pro);
        // 4. 获取连接
        Connection conn = ds.getConnection();
        // 5. 进行具体操作
        System.out.println(conn);
    }
}
3.3 定义工具类
- 定义一个类
 - 提供静态代码块加载配置文件,初始化连接池对象
 - 提供方法
- 获取连接方法:通过数据库连接池获取连接
 - 释放资源
 - 获取连接池的方法
 
 
代码实现
// Druid连接池的工具类
public class DruidUtils {
    // 1. 定义成员变量
    private static DataSource ds;
    // 静态初始化代码块
    static{
        try {
            Properties pro = new Properties();
            pro.load(DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
            // 获取DataSource对象
            ds = DruidDataSourceFactory.createDataSource(pro);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 获取连接
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
    // 释放资源
    public static void close(Statement stmt,Connection conn){
        close(null,stmt,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();
            }
        }
    }
    // 获取连接池方法
    public static DataSource getDataSource(){
        return ds;
    }
}
// 测试工具类
// 使用工具类
public class DruidDemo2 {
    public static void main(String[] args) {
        // 完成添加操作,给account表添加一条记录
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            // 获取连接池对象
            conn = DruidUtils.getConnection();
            // 定义sql
            String sql = "insert into account values(null,?,?)";
            // 获取执行sql对象
            pstmt = conn.prepareStatement(sql);
            // 给?赋值
            pstmt.setString(1,"小六");
            pstmt.setDouble(2,2699);
            // 执行sql
            int count = pstmt.executeUpdate();
            System.out.println(count);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DruidUtils.close(pstmt,conn);
        }
    }
}
4. Spring JDBC
是Spring框架对JDBC的简单封装,提供了一个JDBCTemplate对象简化JDBC的开发
4.1 使用步骤
- 导入Jar包
 - 创建
JDBCTemplate对象,该对象依赖于数据源DataSource,例:JdbcTemplate template = new JdbcTemplate(ds); - 调用
JDBCTemaplate的方法来完成CRUD的操作 
常用方法:
| 方法名 | 作用 | 
|---|---|
update() | 
执行DML语句。增、删、改语句 | 
queryForMap() | 
查询结果,将结果集封装为Map集合。列名作key,值作value,将这条记录封装为一个Map集合返回。注:该方法查询结果集长度只能是1 | 
queryForList() | 
查询结果,将结果集封装为List集合。将每一条记录封装为一个Map集合,再将Map集合装载到List集合中 | 
queryForObject() | 
查询结果,将结果封装为对象。一般用于聚合函数的查询 | 
query() | 
查询结果,将结果封装为JavaBean对象。一般我们使用new BeanPropertyRowMapper<类型>(类型.class)来完成数据到JavaBean的自动封装。 | 
4.2 使用示例
// jdbcTemplate基础入门
public class JDBCTemplateDemo1 {
    public static void main(String[] args) {
        // 创建jdbcTemplate对象
        JdbcTemplate jt = new JdbcTemplate(DruidUtils.getDataSource());
        // 调用方法
        String sql = "update account set balance=3000 where id=?";
        int count = jt.update(sql, 6); // 返回值是影响的行数
        System.out.println(count); // 1
    }
}
4.3 练习
- 修改6号数据的salary为10000
 - 添加一条记录
 - 删除刚刚添加的记录
 - 查询id为8的记录,将其封装为Map集合
 - 查询所有记录,将其封装为List
 - 查询所有记录,将其封装为Emp对象的List集合
 - 查询总记录数
 
public class Exercise {
        // 获取JdbcTemplate对象
        // 使用Junit单元测试,让方法单独执行
        private JdbcTemplate jt = new JdbcTemplate(DruidUtils.getDataSource());
        // 编写sql语句并执行
        @Test
        public void test1(){
            // 1. 修改6号数据的salary为10000
            String update = "update staff set salary=10000 where id=?";
            jt.update(update,6);
        }
        @Test
        public void test2(){
            // 2. 添加一条记录,字段分别为id,name,性别,工资,入职时间,部门id
            jt.update("insert into staff(id,name,salary) values(?,?,?)",13,"冬兵",7889);
        }
        @Test
        public void test3(){
            // 3. 删除刚刚添加的记录
            jt.update("delete from staff where name=?","冬兵");
        }
        @Test
        public void test4(){
            // 4. 查询id为8的记录,将其封装为Map集合
            // 注意:这个方法查询的结果集只能是1
            Map<String, Object> stringObjectMap = jt.queryForMap("select * from staff where id=?", 8);
            System.out.println(stringObjectMap); // {id=8, name=美队, gender=男, salary=8000.0, join_date=2008-08-08, dept_id=2}
        }
        @Test
        public void test5(){
            // 5. 查询所有记录,将其封装为List
            List<Map<String, Object>> maplist = jt.queryForList("select * from staff");
            for (Map<String, Object> stringObjectMap : maplist) {
                System.out.println(stringObjectMap);
            }
        }
        @Test
        public void test6(){
            // 6. 查询所有记录,将其封装为Emp对象的List集合,自己完成实现类
            String sql = "select * from staff";
            List<Emp> list = jt.query(sql, new RowMapper<Emp>() {
                @Override
                public Emp mapRow(ResultSet rs, int i) throws SQLException {
                    Emp emp = new Emp();
                    int id = rs.getInt("id");
                    String name = rs.getString("name");
                    String gender = rs.getString("gender");
                    double salary = rs.getDouble("salary");
                    Date join_date = rs.getDate("join_date");
                    int dept_id = rs.getInt("dept_id");
                    emp.setId(id);
                    emp.setName(name);
                    emp.setGender(gender);
                    emp.setSalary(salary);
                    emp.setJoin_date(join_date);
                    emp.setDept_id(dept_id);
                    return emp;
                }
            });
            for (Emp emp : list) {
                System.out.println(emp);
            }
        }
        @Test
        public void test6_2() {
            // 6. 查询所有记录,将其封装为Emp对象的List集合,使用jdbc提供的实现类来完成
            String sql = "select * from staff";
            List<Emp> list = jt.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
            for (Emp emp : list) {
                System.out.println(emp);
            }
            /*
            Failed to convert property value of type 'null' to required type 'int' for property 'dept_id'
            需要将Emp类中变量改为为引用数据类型,然后重新生成方法
             */
        }
        @Test
        public void test7(){
            // 7. 查询总记录数
            String sql = "select count(id) from staff";
            Long count = jt.queryForObject(sql, Long.class);
            System.out.println(count);
        }
}