数据库连接池
- 连接池的相关概念
- c3p0连接池
- Druid连接池
- jdbcTemplate
一、连接池的相关概念
1.1、什么是连接池?
一个存放数据库连接对象的容器(集合),每次程序需要访问数据库时,就会来连接池拿走一个连接对象,用完再“归还”。用于节约资源,提高程序的效率。
1.2、连接池的作用
在不使用连接池的情况下,每当程序需要访问数据库,都必须先创建连接对象,当访问完成以后,为了避免内存溢出,所以又得将连接对象销毁(conn.close()),当访问量比较大大时,这种方式会给CPU造成极大的压力。
解决思路:创建几个静态连接对象,由这几个连接对象交替去访问数据库。避免了频繁的创建、销毁连接对象操作。
连接池的本质:就是一个预先存放了一些连接对象的容器(集合),每当程序需要访问数据库时,就会从容器中拿走一个连接对象,用完以后又还回来,避免了频繁的创建、销毁连接对象的操作,大大提高了程序的效率。
1.3、来由
Java官方很清楚连接池的重要性,所以向外提供了一个接口(javax.sql.DataSource)方便程序员在项目中引入、使用连接池 。
连接池的实现原理并不复杂,所以有很多的厂商、技术大佬开发了各种连接池,常用的连接池有C3P0、Druid。一个由MySQL官方提供,一个由阿里巴巴开发的。没个连接池内部都处理了Connection的colse()方法,使其不会释放连接池对象,而是归还连接池对象。
javax.sql.DataSource接口中的方法:getConnection():获取数据库连接对象,每一个连接池都必须实现这个方法。
二、c3p0连接池
C3P0是一个开源的jdbc连接池,由MySQL官方提供,用的人还是蛮多的。它实现了数据源和jndi绑定,支持jdbc3规范和jdbc2的标准扩展。c3p0是异步操作的,缓慢的jdbc操作通过帮助进程完成。扩展这些操作可以有效的提升性能。目前使用它的开源项目有Hibernate,Spring等。c3p0有自动回收空闲连接功能。
2.1、配置文件说明
总共由两种配置文件,c3p0-config.xml和c3p0.properties。因为xml用的比较多,所以这里只讨论第一种。
xml配置文件必须放到src目录下,文件名最好不要改,要改的话也不能用底杠,只能用中杠。
<?xml version="1.0" encoding="UTF-8"?><!--version:版本号 encoding:字符编码-->
<c3p0-config>
<!--默认的连接池-->
<default-config>
<!--数据库连接参数-->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test1?serverTimezone=UTC&characterEncoding=utf-8</property>
<property name="user">root</property>
<property name="password">duanhui0</property>
<!--连接池参数-->
<property name="initolPoolSize">5</property><!--初始化连接数-->
<property name="maxPoolSize">10</property><!--最大连接数-->
<property name="chockoutTimeout">3000</property><!--等待时间3秒-->
</default-config>
<!--可选的连接池-->
<named-config name="linux">
<!--数据库连接参数-->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://192.168.198.129:3306/test1</property>
<property name="user">root</property>
<property name="password">duanhui0</property>
<!--连接池参数-->
<property name="initolPoolSize">5</property><!--初始化连接数-->
<property name="maxPoolSize">10</property><!--最大连接数-->
<property name="chockoutTimeout">3000</property><!--等待时间3秒-->
</named-config>
</c3p0-config>
2.2、使用步骤
-
导入两个jar包到项目中:c3p0-0.9.5.2.jar和mchange-commons-java-0.2.11.jar
记得Add as library
-
定义配置文件:src/c3p0-config.xml
-
创建核心对象————连接池对象:ComboPooledDataSource
DataSource ds = new ComboPooledDataSource(); /** * 关于ComboPooledDataSource类,其实有两个构造方法。 * 无参构造:new ComboPooledDataSource()用于创建默连接池(<default-config>)的对象。 * 有参构造:new ComboPooledDataSource(String name)用于创建指定连接池的对象,参数决定了具体创建哪个 * 连接池的对象。比如:new ComboPooledDataSource("linux")就是创建<named-config name="linux">连接池 * 的连接对象。 */
-
获取数据库连接对象:getConnection()
Connection conn = ds.getConnection();
-
有了数据库连接对象,就相当于拥有了一整个世界了,就可以拿着这个去各种揉躏数据库了。
-
归还数据库连接对象(毕竟连接池中的连接对象也是有限的)
conn.close();
三、Druid连接池
3.1、配置文件说明
c3p0不同的是,Druid连接池只有一种配置文件:druid.properties
# 数据库连接4要素
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test1?serverTimezone=UTC&characterEncoding=utf-8
username=root
password=duanhui0
# 初始化连接数
initialSize=5
# 最大连接数
maxActive=10
# 获取连接时的最大等待时间3秒
maxWait=3000
# 最大连接池数量
maxIdle=8
# 最小连接池数量
minIdle=3
3.2、使用步骤
-
将jar包导入到项目中:druid-1.0.9.jar
记得Add as library
-
定义配置文件:druid.properties
-
读取配置文件
Properties pro = new Properties(); FileInputStream input = new FileInputStream("src/resources/druid.properties"); pro.load(input); input.close();
-
获取连接池对象:DataSource
DataSource source = DruidDataSourceFactory.createDataSource(pro);
-
获取数据库连接对象:getConnection()
Connection conn = source.getConnection();
-
有了数据库连接对象,就相当于拥有了一整个世界了,就可以拿着这个去各种揉躏数据库了。
-
释放资源
conn.close();
3.3、定义工具类
-
定义一个utils类
-
提供静态代码块加载配置文件,初始化连接池对象
-
对外提供方法:
- 获取连接池对象:
- 获取DB连接对象:
- 释放资源:
import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; public class JDBCutils { //成员变量 private static DataSource ds; static{ //1、加载配置文件 Properties properties = new Properties(); try { InputStream input = new FileInputStream("src/resources/druid.properties"); properties.load(input); input.close(); ds = DruidDataSourceFactory.createDataSource(properties); } catch (FileNotFoundException e) { System.out.println("配置文件路径错误"); e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } // 方法一:获取连接池对象 public static DataSource getDateSource(){ return ds; } //方法二:获取数据库连接对象 public static Connection getConnection() throws SQLException { Connection connection = ds.getConnection(); return connection; } //方法三:释放资源 public static void colse(Statement statement,Connection connection){ colse(null,statement,connection); } //重载方法三 public static void colse(ResultSet result,Statement statement, Connection connection){ if (result != null){ try { result.close(); } catch (SQLException e) { e.printStackTrace(); } } if (statement != null){ try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
-
编写测试类进行测试
@Test public void test(){ Connection conn = null; PreparedStatement pps = null; try { conn = JDBCutils.getConnection(); String sql = "insert into test1 values(null,?)"; pps = conn.prepareStatement(sql); pps.setString(1,"testUtil"); int result = pps.executeUpdate(); System.out.println(result); } catch (SQLException e) { e.printStackTrace(); }finally { JDBCutils.colse(pps,conn );//释放资源 } }
四、jdbcTemplate
Spring框架对jdbc进行了简单的封装,并提供了jdbcTemplate对象简化jdbc操作。
4.1、使用步骤
-
导入Spring框架相关jar包
- commons-logging-1.2.jar
- spring-beans-5.1.10.RELEASE.jar
- spring-core-5.1.10.RELEASE.jar
- spring-jdbc-5.1.10.RELEASE.jar
- spring-tx-5.1.10.RELEASE.jar
-
创建jdbcTemplate对象
jdbcTemplate template = new jdbcTemplate(JDBCutils.getDateSource());//JDBCutils为上面的工具类
-
编写SQL
String sql = "insert into test1 values(null,?)";
-
调用jdbcTemplate的方法执行SQL并返还结果
-
update():执行DML语句
-
queryForMap():将结果封装到map集合。查询结果只能有一条记录,key=字段名,value=字段值
-
queryForList():将结果封装到List集合。将每一条记录封装成一个Map,再将Map保存进List集合。
-
query():将结果封装成JavaBean对象
参数:sql, 值1,值2,…,new BeanPropertyRowMapper<javaBean>(javaBean全类名.class)
返回值:List<JavaBean> list
- queryForObject():将查询结果封装成对象,一般用于聚合函数的查询。
参数:sql4, 值1,值2,…,引用数据类型.class
返回值:引用数据类型(如:Long、Integer等)
int count = template.update(sql,"template");//返回值是受影响的行数,“template”用于补全SQL
-
4.2、经典案例
- 添加一条记录
- 查询该记录,封装为List集合
- 修改该记录
- 查询该记录,封装为Map集合
- 删除该记录
- 查询所有的记录,封装为Emp对象的List集合
@Test//测试CRUD
public void test2(){
//InputStream input ;
//input = JDBCUtils.class.getClassLoader().getResourceAsStream("resources/druid.properties");
JdbcTemplate template = new JdbcTemplate(JDBCutils.getDateSource());
//1、添加一条数据
String sql1 = "insert into employee values(3,?,?,?)";
int insert = template.update(sql1,"袁树",21,10000.0);
System.out.println(insert==1?"添加成功":"执行失败");
//2、查询id=3的记录,并将查询结果封装到Map集合
String SQL1 = "select * from employee where id = ?";
Map<String,Object> map = template.queryForMap(SQL1,3);//只能用于查询一条记录
System.out.println(map);
//3、修改一条数据
String sql2 = "update employee set salary=? where id = 3";
int update = template.update(sql2,15000);
System.out.println(update==1?"修改成功":"执行失败");
//4、查询所有记录,并将查询结果封装到List集合
String SQL2 = "select * from employee";
List<Map<String, Object>> list = template.queryForList(SQL2);
System.out.println(list);
//5、删除一条数据
String sql3 = "delete from employee where id = ?";
int delete = template.update(sql3,3);
System.out.println(delete==1?"删除成功":"执行失败");
//6、查询所有记录,
String SQL3 = "select * from employee";
List<Employee> list2 = template.query(SQL3, new RowMapper<Employee>() {
@Override
public Employee mapRow(ResultSet resultSet, int i) throws SQLException {
Employee em = new Employee();
em.setId(resultSet.getInt("id"));
em.setName(resultSet.getString("name"));
em.setAge(resultSet.getInt("age"));
em.setSalary(resultSet.getDouble("salary"));
return em;
}
});
System.out.println(list2);
//7、查询总记录数
String sql4 = "select count(*) from employee";
Long count = template.queryForObject(sql4,Long.class);
System.out.println(count);
}
4.3、surprize
@Test//简化查询结果转Javabean的步骤
public void test3(){
JdbcTemplate template = new JdbcTemplate(JDBCutils.getDateSource());
String sql = "select * from employee";
//一步到位
List<Employee> list = template.query(sql, new BeanPropertyRowMapper<Employee>(Employee.class));
System.out.println(list);
}
对于javabean中的类,成员方法不要用基本数据类型,因为基本类型无法接收null,如果数据库中有null值,那么在你接收的时候就很容易bug了。
https://zhidao.baidu.com/question/1387795592417884260.html
关于queryRunner类的方法-参数介绍