数据库连接池
1. 概念:其实就是一个容器(集合),存放数据库连接(Connection对象) 的容器。
当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,
从容器中获取连接对象;用户访问完之后,会将连接对象归还给容器。
2. 好处:
1. 节约资源
2. 用户访问高效
3.弊端
第一次创建的时候会略微多消耗一点时间,第二次开始就会快很多。
4. 实现:
在Java中怎么表示数据库连接池?
接口:DataSource 链接池又叫数据(Data)源(Source)
1. 标准接口:DataSource java.sql包下的
1. 方法:
* 获取连接:getConnection()
* 归还连接:Connection.close()。 如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则 理解为:不是关闭连接。而是归还连接。
2. 一般我们不去实现它,有数据库厂商来实现。有两种数据库连接池(C3P0、Druid)
1. C3P0: 数据库连接池技术 //了解
以前框架:ssh(spring、structs2、hibernate)
后来框架:ssm(spring、springMVC、mybatis)
2. Druid:数据库连接池实现技术,由阿里巴巴(Made in China)提供的 (重点掌握)
面试题:普通的连接(Connection对象)的close方法和数据库连接池中的连接(Connection对象)的close方法有什么区别?
1.普通的连接:释放、销毁
2.数据库连接池的连接:将连接归还到数据库连接池中 (动态代理)
5. C3P0:数据库连接池技术
* 步骤:
1. 导入jar包 (两个) c3p0-0.9.5.5.jar mchange-commons-java-0.2.19.jar ,
外加配置文件(一个):c3p0-config.xml
* 不要忘记导入数据库驱动jar包
2. 定义配置文件:
* 名称: c3p0.properties 或者 c3p0-config.xml (其他名字不行)
* 路径: 直接将文件放在src目录下即可。 (其他目录也不行)
如果使用C3P0连接池一定要注意放在src下,名字也是固定的 c3p0.properties 或者 c3p0-config.xml
3. 创建核心对象 数据库连接池对象 ComboPooledDataSource
4. 获取连接: getConnection
代码:
//1.创建数据库连接池对象
DataSource ds = new ComboPooledDataSource();
//2. 获取连接对象
Connection conn = ds.getConnection();
(1)为什么要导入jar包?
因为JDK自带的jar包中没有吗,而我现在又要使用,这个时候就必须要导入jar包名
6.Druid:数据库连接池实现技术,由阿里巴巴提供的 //掌握
1. 步骤:
1. 导入jar包 druid-1.0.9.jar
2. 定义配置文件:
* 是properties形式的
* 可以叫任意名称,可以放在任意目录下 //注意和C3p0对比
3. 加载配置文件 使用方式: Properties
4. 获取数据库连接池对象: 通过工厂类来获取 DruidDataSourceFactory
5. 获取连接:getConnection
配置文件:
代码:
# druid.properties文件的配置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/db1
username=root
password=123456
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大超时时间
maxWait=3000
加载配置文件
代码:
Properties pro = new Properties();
InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//4.获取连接池对象
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
//5.获取连接
Connection conn = ds.getConnection();
2. 定义工具类:
1.定义一个类 JDBCutils
2.提供静态代码块加载配置文件,初始化连接池对象
3.提供方法
1.获取连接方法:通过数据库连接池获取连接
2.释放资源
3.获取连接池的方法
代码实现:
private static DataSource ds;
static {
try {
//1、创建Properties对象
Properties pro = new Properties();
//2、连接配置文件
InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(in);
//3、获取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 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 throwables) {
throwables.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close(); //归还连接
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
/**
* 获取连接池的方法
*/
public static DataSource getDataSource(){
return ds;
}
}
工具类的测试:向account添加一条记录
代码实现:
/*
使用新的工具类
*/
public class DruidDemo2 {
public static void main(String[] args) throws Exception {
/**
* 完成添加朝操作,给account添加一条记录
*/
Connection conn = null;
PreparedStatement pstmt =null;
try {
//1、获取连接
conn = JDBCUtils.getConnection();
//2、定义sql
String sql ="insert into account values (null ,?,?)";
//3、获取sql对象
pstmt = conn.prepareStatement(sql);
//4、给 ? 赋值
pstmt.setString(1,"王五");
pstmt.setInt(2,3000);
//5、执行sql
int i = pstmt.executeUpdate();
System.out.println(i);
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//释放资源
JDBCUtils.close(pstmt,conn);
}
}
}
Spring JDBCTemplate
三层结构:控制层(Controller层)、业务层(service层)、持久层(dao层)
JDBCTemplate是我们spring框架的一个组成部分,是持久层的一个实现方式
-
Spring框架对JDBC的简单封装。 提供了一个JDBCTemplate对象简化JDBC的开发(就是对JDBC的一个封装)
*步骤:-
导入jar包
-
创建JdbcTemplate对象。依赖于数据源DataSource
JdbcTemplate template = new JdbcTemplate(ds); 参数:ds是数据库连接池对象(druid连接池)
-
-
调用JdbcTemplate的方法来完成CRUD的操作
* update():执行DML语句。增、删、改语句
注意:使用前需要导入jar包 方法名不要写成excuteUpdate* queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合//了解 * 注意:这个方法查询的结果集长度只能是1 (说白了就是一次性只能查询一条记录) * queryForList():查询结果将结果集封装为list集合 //了解 * 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中 * query():查询结果,将结果封装为JavaBean对象 //最重要 前提:必须先有一个"标准的"JavaBean对象 因为我们传入的字节码文件对象,底层使用反射的方式创建对象,使用反射的调用set方法进行赋值 * query的参数:RowMapper * 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装 * new BeanPropertyRowMapper<类型>(类型.class) * queryForObject:查询结果,将结果封装为对象 //熟悉 特点:查询的结果需要是单行单列的 * 一般用于聚合函数的查询(比如:查询总数)
4.JDBCTemplate快速入门
代码实现:
public class Template01 {
public static void main(String[] args) {
//1、导入jar包
//2、创建JDBCTemplate对象
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
//3、调用方法
String sql = "update account set balance = 5000 where id = ?";
int update = template.update(sql,3);
System.out.println(update);
/**
* 短短几行足以。
* JDBCTemplate:
* 不需要再申请连接了
* 不需要再释放资源了
* JdbcTemplate自己内部解决了
*
* 只关心:如何定义sql语句、执行、处理
*/
}
}
1、练习
需求:
- 修改1号数据的 salary 为 1000
- 添加一条记录
- 删除刚才添加的记录
- 查询 id 为1的记录,将其封装为Map集合
- 查询所有记录,将其封装为List
- 查询所有记录,将其封装为Emp对象的List集合
- 查询总的记录数
Emp代码的实现:
public class Emp {
private Integer id ;
private String name;
private String gender;
private Double salary;
private Date join_date;
private Integer dept_id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public Date getJoin_date() {
return join_date;
}
public void setJoin_date(Date join_date) {
this.join_date = join_date;
}
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 +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
", salary=" + salary +
", join_date=" + join_date +
", dept_id=" + dept_id +
'}';
}
}
练习代码:
public class Template02 {
//每一个@Test都要写一次如下代码,所以直接提升作用域,使其template的作用域为成员变量
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 1、修改1号数据的 salary 为 1000
*/
@Test
public void test1() {
String sql1 = "update emp00 set salary = ? where id = ?";
int i = template.update(sql1,1000,1);
System.out.println(i);
}
/**
* 2、添加一条记录
*/
@Test
public void tset02() {
String sql = "insert into emp00(id,name,gender) values (?,?,?)";
int i = template.update(sql,6,"沙悟净","男");
System.out.println(i);
}
/**
* 3、删除刚才添加的记录
*/
@Test
public void test03() {
String sql = "delete from emp00 where id in (?,?)";
int update = template.update(sql, 6, 7);
System.out.println(update);
}
/**
* 4、查询 id 为1的记录,将其封装为Map集合
* queryForMap方法的代码实现
* 注意:这个方法查询的结果集长度只能是 :1 (说白了就是一次性只能查询一条记录)
*/
@Test
public void test04() {
String sql = "select * from emp00 where id =?";
Map<String, Object> map = template.queryForMap(sql, 1);
System.out.println(map);
//{id=1, name=孙悟空, gender=男, salary=1000.0, join_date=2013-02-24, dept_id=1}
}
/**
* 5、查询所有记录,将其封装为List
* queryForList方法的代码实现
* 将每一条记录封装为一个Map集合,再将Map集合装载到List集合中 (说白了就是重复多次test04)
*/
@Test
public void test05() {
String sql = "select * from emp00";
List<Map<String, Object>> list = template.queryForList(sql);
//遍历 使得输出结果换行。
for (Map<String, Object> map : list) {
System.out.println(list);
}
}
/**
* 6、查询所有记录,将其封装为Emp对象(JavaBean对象)的List集合
* 和package domain下的Emp 组队
*/
@Test
public void test06() {
String sql = "select * from emp00 ";
List<Emp> list = template.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);
}
}
/**
* 6、查询所有记录,将其封装为Emp对象(JavaBean对象)的List集合
* 简化上述代码
*/
@Test
public void test07() {
String sql = "select * from emp00 ";
List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
for (Emp emp : list) {
System.out.println(emp);
}
}
/**
* 7、查询总的记录数
*/
@Test
public void test08() {
String sql = "select count(*) from emp00 ";
Long total = template.queryForObject(sql, Long.class);
System.out.println(total);
}
}