关于数据库连接池的一些自我理解和使用(以C3P0为例),搭配MySql(8.0以上)
关于数据库连接池的一些自我理解和使用(以C3P0为例),搭配MySql(8.0以上)
首先就是环境的准备了
c3p0包的maven连接: 点击进入c3p0包的maven连接.
MySql的下载连接: 点击进入下载页面.
JDBC驱动连接:点击进入下载页面.
再说说为什么要选择数据库连接池?
为什么要使用数据库连接池呢?
首先,先去回顾一下不使用数据库连接池的时候,操作数据库的流程:
创建连接 -->调用连接去做一系列的操作 -->关闭连接
再次使用的话就要再次创建连接,众所周知,创造一个新的往往是很慢的并且很耗费性能的,就像你 需要一件物品,但是发现没有,所以就去工厂里边等人家再造一件一样;但是如果不关闭连接的话就又像你出门了结果家门没关,结果就很危险了吧。
基于以上,所有就有大佬想,我能不能一下子去工厂中取很多链接,然后放到自家的仓库(数据库连接池)中,每当用到的时候去取,用完了在放回去(这个就是相当于一个关闭的操作了),如果一次用的多了,就再去工厂中取一批,这样一想对比之前的操作流程就会发现优化了特别多,但是又有人会问,我的链接没关,会出现风险吗?这个大佬也是考虑过的,这个在你使用的过程中仓库会自动帮你管理,当你项目结束的时候,这个仓库就自动销毁了,里面的所有连接也就是没有了,所有也就不必担心了。所以说,有了数据库连接池之后的数据库操作流程就是:
取连接 -->操作数据库–>将连接放回
数据库连接池有很多种,自行选择,但是原理都一样,然后看看大佬分析,自己选择
简单介绍一下,数据库连接池有很多种,毕竟大佬有很多,网上的性能分析的文章也有很多,自己选择啊,下面附上网址,这里边全都是开源的
Java开源数据库连接池: 点击进入查看大佬分析.
然后就到了重头戏的上手流程了
怎么让数据库连接池管理自己的数据库连接
-
这就需要配置文件了,c3p0是默认加载的,所以就需要使用人家默认的**配置文件名字(c3p0-config.xml)**了,要不怎么找到对应的配置文件呢?注意:一定要将配置文件放到源码文件夹下面,要不项目打包的时候,文件加载不进去,它还是找不啊,蓝色的在IDEA中表示源码文件夹
-
然后就需要编写配置文件了,这个配置文件也是有固定格式的,别的数据库连接池和这样的套路基本类似
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 命名的配置,可以通过方法调用实现 -->
<named-config name="test">
<property name="user">xxxxx</property>
<property name="password">xxxxx</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/xxxxx(?useUnicode=true&characterEncoding=utf-8&useSSL=false)</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<!-- 如果池中数据连接不够时一次增长多少个 -->
<property name="acquireIncrement">5</property>
<!-- 初始化数据库连接池时连接的数量 -->
<property name="initialPoolSize">20</property>
<!-- 数据库连接池中的最大的数据库连接数 -->
<property name="maxPoolSize">25</property>
<!-- 数据库连接池中的最小的数据库连接数 -->
<property name="minPoolSize">5</property>
</named-config>
</c3p0-config>
解释一下上面的配置文件哈(账号、密码还有数据库的名字就不用说了吧):
< named-config name=“test”>这个就是配置的名字了,从这点就可以看出来,这个配置文件是能管理多个数据源的,对吧,毕竟换个名字它就又是新的数据源了。
< property name=“jdbcUrl”>jdbc:mysql://localhost:3306/xxxxx(?useUnicode=true&characterEncoding=utf-8&useSSL=false)< /property>,这个就要重点说一下了,这个就是数据库的版本问题了,为什么我的数据库名字后面跟了一个括号呢?括号里边的内容那么长。这个当然是有原因的了,MySql 8.0之前就直接忽略括号里边的内容就行了,不用写上,但是MySql 8.0之上的小伙伴就要注意了,括号里边的内容是必须写上的,当然,括号就不要加了啊(嘿嘿),下面就来解释一下为什么这样做
Thu May 14 11:07:40 CST 2020 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Thu May 14 11:07:40 CST 2020 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Thu May 14 11:07:40 CST 2020 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Thu May 14 11:07:42 CST 2020 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Thu May 14 11:07:42 CST 2020 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
提取一个出来就是下面的样子,但是会出特别多的警告,还能用,但是能解决这个还是最好的:
Thu May 14 11:07:40 CST 2020 WARN: Establishing SSL connection without server’s identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn’t set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to ‘false’. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
数据库作为数据源已经被管理起来了,那么下一步该干什么呢?
肯定是获取连接了,和关闭练级的数据库管理类了,至于操作数据库当然是放到dao层了,这里就不多说了。
两个版本的工具类,一个简单一个难,供参考:
简单介绍一下两个版本,复杂的是附带事务控制的,简单的是不带事务的
然后再简单的说一下事务,简单来说就是 一错全错,撤销操作;全对提交,修改数据
举个例子:
比如说,网购的时候进行付款操作,这个操作就分为好多步骤吧,程序是顺序执行的吧,如果是先修改库存,然后再进行结账,就可能会出现这样一种情况,程序执行到修改库存的操作的时候把库存数据修改了,然后向下执行,执行到付款操作了,结果由于种种原因,这个语句执行报错了,但是你数据库修改成功了,因为是在报错之前执行的,这样就会导致错误发生,不管是谁亏了,总归是程序出错了数据库出错了,但是如果加上事务的话,再次重复之前的操作,这样也是到付款的时候执行失败了,但是因为加了事务特性,所以数据库就会把这个方法中这句语句之前执行的全部撤销掉,所以说也就是相当于没执行这个方法(就是把报错之前执行的数据库操作全部撤销)
前面的是简单版本的,后面是难的版本的,根据需求任选其一:
- 简单版本:
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JDBCUitls {
/**
* 根据之前配置的名字获取被管理的数据源 <named-config name="test">
*/
private static DataSource dataSource = new ComboPooledDataSource("test2");
/**
* 获取数据库连接
* @return 数据库连接
*/
public static Connection getConnection(){
Connection connection=null;
try {
connection =dataSource.getConnection();
}catch (SQLException e){
e.printStackTrace();
}
return connection;
}
/**
* 关闭连接(将连接放回仓库,方便下次取用)
* @param connection 要关闭的连接
*/
public static void close(Connection connection) {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
- 复杂版本:
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class JDBCUtils {
/**
* 根据之前配置的名字获取被管理的数据源 <named-config name="test">
*/
public static DataSource dataSource = new ComboPooledDataSource("test");
/**
* 根据事物特性(有错回滚,无错提交),并保证多线程时的数据安全安全,所以使用threadLocal关联数据库连接
*/
public static ThreadLocal<Connection> conns = new ThreadLocal<>();
/**
* 从连接池中获取数据连接,并和当前线程联系起来
* @return 连接
*/
public static Connection getConnection(){
Connection connection = conns.get();
if(connection == null){
try {
connection = dataSource.getConnection();
//添加联系
conns.set(connection);
//取消自动提交
connection.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
return connection;
}
/**
* 事务成功后提交,并关闭连接(将连接放回仓库,方便下次取用)
*/
public static void commitAndClose() {
Connection connection = conns.get();
//之前如果操作过数据库,得到连接,提交并释放资源
if (connection!=null){
try {
//提交
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//移除联系
conns.remove();
}
/**
* 事务失败之后回滚,并关闭连接(将连接放回仓库,方便下次取用)
*/
public static void rollbackAndClose() {
Connection connection = conns.get();
//获取之前的连接,回滚事务,并释放资源
if (connection != null) {
try {
//回滚事务
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//移除联系
conns.remove();
}
}
这些都干完了,那么之后该干什么呢?
这个,之后肯定是快乐的CURD操作了啊,在这就不具体展开说了,之后可能会在写一遍吧
总结
都写完了,肯定是要干一个总结的呀,如果有什么错误,一定要提出来啊,大家一起学习进步,我也是一个小萌新。
然后就是抛出几个问题,让大家思考一下,就是数据库操作会做很多,怎样才能优化一下?前端的请求有很多,一个请求要对应一个servlet,那么100个请求是不是要写100个servlet呢?最后就是,页面的数据封装问题,页面1个数据得用一个request.getParameter("");那么100个呢?这样写,是不是得累死啊
上一篇: Lnmp架构之源码安装
下一篇: DBCP数据库连接池的简单使用