研究主题:tomcat连接mysql
一.tomcat连接mysql的两种连接方式:
简单连接(不使用连接池)
使用tomcat连接池
二.简单分析:(简介部分摘自一篇博客,觉得写得非常赞,读了非常有快感,就引用来与大家分享)
对于一个简单的数据库应用,由于对于数据库的访问不是很频繁。这时可以简单地在需要访问数据库时,就创建一个连接,用完后就关闭它
这样也不会带来什么明显的性能上的开销。但是对于一个复杂的数据库应用,QPS和TPS都并发很大的时候情况就完全不同了。频繁的建立,关闭连接,会极大的降低系统
的性能,TCP的三次握手和四次断开每次都需要消耗系统资源来处理,因此对于连接的使用成了系统性能的瓶颈
通过建立一个数据库连接池以及一套连接使管理策略,使得一个数据库连接上可以高效,安全的复用,避免了数据库连接的频繁建立,闭关的
开销,对于共享资源,有一个很著名的设计模式:资源池。该模式正式为了解决资源频繁分配,释放所造成的问题。把该模式应用到数据库
连接管理领域,就是建一个数据库连接池,提供一套高效的连接分配,使用策略,最终目标是实现连接的高效,安全的复用。
数据库连接池的基本原理是在内部对象池中维护一定数量的数据库连接,并对外提供数据库连接获取和返回方法,即API。如:
外部使用者可以通过getConnection()方法获取连接,使用完毕后再通过releaseConnection()方法将连接返回,注意此时连接并没有关闭
而是由连接池管理器回收,并为下一次使用做好准备。
数据库连接池技术带来的优势:
资源重用,由于数据库连接得到重用,避免了频繁创建,释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境
的平稳性(减少内存碎片及数据库临时进程/线程的数量)。更快的系统响应速度。数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于
池中备用。与httpd的三种MPM工作方式类似,提前做好请求接收准备相关工作,此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有
的可用连接,避免了数据库连接初始化和释放过程的时间开销,以空间换时间,从而缩减了系统整体响应时间。新的资源分配手段。对于多应用共享同一
数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术,今年前也许还是个新鲜的话题,对于目前的业务系统而言,如果设计中
还没有考虑到连接池的应用,那赶快在设计文档中加上这部分的内容把。某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源
统一的连接管理,避免数据库连接泄露。在较为完备的数据库连接池实现中,可根据预先的连接占用设定超时时间,强制收回被占用的连接。从而避免了
常规数据库操作中可能出现的资源泄露。
三.tomcat连接mysql的组件JDBC,你可以简单的理解为tomcat连接mysql驱动,或者JDBC翻译只不过它会多国语言。不同协议之间要实现互通必须加一个中间层
JDBC(JAVA Data Base Connectivity)数据库连接是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。
JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序
有了JDBC,向各种关系数据发送SQL语句就是一件很容易的事。换言之,有了JDBC API,就不必为访问Sybase数据库专门写一个程序,为访问Oracle数据库又专门写
一个程序,或为访问Informix数据库又编写另一个程序等等,程序员只需用JDBC API写一个程序就够了,它可向相应数据库发送SQL调用。同时,将Java语言和JDBC
结合起来使程序员不必为不同的平台编写不同的应用程序,只须写一遍程序就可以让它在任何平台上运行,这也是Java语言“编写一次,处处运行”的优势
四.配置
说明:$CATALINA_HOME 表示tomcat的安装根目录,也叫家目录,此处我实验的tomcat一个实例的家目录如下:(我这台机子跑的是tomcat多实例)
export CATALINA_HOME="/usr/local/tomcat/instance/tomcat8002"
export CATALINA_BASE="/usr/local/tomcat/instance/tomcat8002
Host: 172.18.100.98
Port: TCP 8002
Connector HTTP
appBase:/usr/local/tomcat8002/webapps
[root@Tomcat_A tomcat8002]# tree -L 1
.
├── bin
├── conf
├── lib
├── logs
├── temp
├── webapps
└── work
A.tomcat简单连接mysql(不需要专门设置tomcat,只需把jdbc jar包扔到tomcat家目录下的lib,然后由web应用程序通过java方法调用JDBC来连接MySQL,程序端实现)
Step1.下载JDBC并解压( Mysql官方地址 http://dev.mysql.com/downloads/connector/j/)
shell>cd /usr/local/tomcat8002
shell>wget -c http://cdn.mysql.com//Downloads/Connector-J/mysql-connector-java-5.1.39.tar.gz
shell>unzip mysql-connector-java-5.1.39.tar.gz
Step2.拷贝解压后的jdbc相关jar包到$CATALINA_HOME/lib下
shell>cp -ra mysql-connector-java-5.1.39/mysql-connector-java-5.1.39-bin.jar /usr/local/tomcat8002/lib
Step3.通过web app来访问测试与mysql的连接,此处通过提供一个jsp测试页来模拟应用程序,注意文件必须以.jsp结尾,否则当做文本处理,此处我的测试页叫mysql.jsp代码如下:
shell>mkdir webapps/DBTest # 提供一个通过URL访问此页面的对应的文件系统路径,放在tomcat的数据家目录(appBase所指)下即可
shell>vim /usr/local/tomcat8002/webapps/DBTest/mysql.jsp
<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="UTF-8"%> #注意字符编码,如果此页面有打印汉字,请把字符集配置为UTF-8,否则请求后页面返回乱码
<%@ page import="java.util.*" %>
<%@ page import="com.mysql.jdbc.Driver" %> #导入jdbc的相关类
<%@ page import="java.sql.*" %>
<%
String driverName="com.mysql.jdbc.Driver";
String userName="admin"; # 访问Mysql的一个用户名,这里仅是为测试,随便一个普通用户就可以
String userPasswd="admin"; # 访问Mysql密码
String dbName="tomcatdb"; # 通过用户admin可以访问的数据库,此数据库必须实现存在
String url="jdbc:mysql://172.18.200.200/"+dbName+"?user="+userName+"&password="+userPasswd; #定义访问数据库的IP的地址,端口,默认库,用户名和密码
Class.forName("com.mysql.jdbc.Driver").newInstance();
try
{
Connection connection=DriverManager.getConnection(url); #调用字符串变量url,主要是上面定义访问数据库时的一些参数和选项
out.println("Mysql connect is OK !"); # 如果访问默认数据库tomcatdb成功,则打印“Mysql connect is OK!”
connection.close(); # 断开与数据库的连接,默认mysql与客户端一般是长连接
}
catch( Exception e )
{
out.println( "connent mysql error:" + e ); # 如果访问默认数据库失败,则打印错误信息
}
%>
Step5.测试通过JDBC访问mysql,即怎么知道tomcat连接数据库是否成功,给出以下几种方式
1 打开浏览器输入 http://172.18.100.98:8002/DBTest/mysql.jsp #如果访问成功,则会返回“Mysql connect is OK!”,否则报错
2 shell>curl -i http://172.18.100.98:8002/DBTest/mysql.jsp
3 在被访问的数据库上使用抓包工具tcpdump查看,具体如下:
shell>tcpdump -i eth0 tcp dst port 3306 and dst host 172.18.200.200 -ennvvAASs 0 # 如果刷新页面能成功,则会抓到一些信息,-i 后面的网卡应该为通过此网卡能访问到mysql的网络设备
4 在数据库服务器上通过一些网路监控命令,如iftop ,iptraf,nethogs # 如果访问成功,则会有四层TCP的mysql相关信息
B.使用tomcat连接池
Step1.下载JDBC并解压( Mysql官方地址 http://dev.mysql.com/downloads/connector/j/)
shell>cd /usr/local/tomcat8002
shell>wget -c http://cdn.mysql.com//Downloads/Connector-J/mysql-connector-java-5.1.39.tar.gz
shell>unzip mysql-connector-java-5.1.39.tar.gz
Step2.拷贝解压后的jdbc相关jar包到$CATALINA_HOME/lib下
shell>cp -ra mysql-connector-java-5.1.39/mysql-connector-java-5.1.39-bin.jar /usr/local/tomcat8002/lib
Step3.启用并初始化一个连接池,四种配置方式(按配置生效的作用域)
全局:即对每个web app都生效
局部:只对某个或某些web app生效
# 是否全局或局部主要是看配置文件中引不引入新的docBase 或者 appBase,通过这两个参数可以指定web应用的数据根目录
习惯用来全局生效的配置文件
1>.$CATALINA_HOME/conf/context.xml # tomcat会监视此文件的修改,如果有修改会重新部署web应用,所以支持热部署
<?xml version='1.0' encoding='utf-8'?>
<Context> # Context 标签内不用指定appBase,当然你可以指定appBase,那就不是全局生效了,如果有appBase或docBase
... #那只要在appBase或docBase所指的路径下部署的应用才生效,此文件习惯不加appBase或docBase,纯属个人习惯
</Context>
2>.$CATALINA_NAME/conf/server.xml # tomcat的主配置文件中修改,修改此文件不会重新部署响应的web应用,即可以全局生效,又可以局部生效
一般需要通过Context这个标签引入
<Context path="/url" docBase="path/appname " reloadable="ture" privileged="true">
...
</Context>
习惯用来局部生效的配置文件
3>.$CATALINA_HOME/conf/Catalina/localhost/$appName.xml
#$appName.xml为你部署应用的项目名称,tomcat会监视此文件的修改,如果有修改会重新部署web应用,所以也支持热部署,一般需要自己手动创建$appName.xml
shell>vim $CATALINA_HOME/conf/Catalina/localhost/$appName.xml
4>$CATALINA_HOME/webapps/$appName/META-INF/context.xml
#tomcat会监视此文件的修改,如果有修改会重新部署web应用,所以支持热部署,一般需要在$CATALINA_HOME/webapps/$appName 手动创建META-INF目录
启用tomcat连接池的代码如下,你可以放在上面4种方式中的一种,本次实验推荐使用第三中配置方式,$appName=DBTest,此次我把测试页放到了DBTest这个目录下
shell>vim /usr/local/tomcat8002/conf/Catalina/localhost/DBTest.xml
<?xml version="1.0" encoding="UTF-8"?> # xml配置格式文件都该有这一行,和配置本身没有多大关系
<Context path="/DBTest" docBase="DBTest" crossContext="true">
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
username="admin"
password="admin"
maxActive="850"
maxidle="80"
maxWait="10000"
removeAbandoned="true"
removeAbandonedTimeout="5"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://172.18.200.200:3306/tomcatdb?autoReconnect=true"
minEvictableIdleTimeMillis="4000"
timeBetweenEvictionRunsMillis="5000"/>
</Context>
#对以上参数代表的含义做一下简单说明
name # 初始化一个连接池,name用来指定连接池名字 ,后续访问mysql需要向此连接池发出连接申请,即要调用此name
auth # 是连接池管理权属性,Container表示容器管理
type # 对象类型
username #连接mysql的用户名
password #连接mysql的密码
maxActive # 最大连接数据库连接数,设 0 为没有限制,即最大并发连接数
maxidle #最大等待连接中的数量,超过空闲时间,数据库连 接将被标记为不可用,然后被释放。设为0表示无限,即最多空闲连接数
maxWait:最大建立连接等待时间, 单位为 ms, 如果超过此时间将接到异常。设为-1表示 无限制
driverClassName # 驱动的类名
url="jdbc:mysql://172.18.200.200:3306/tomcatdb?autoReconnect=true" 连接数据库用到的参数
jdbc:mysql #表示通过jdbc连接数据库类型为mysql
172.18.200.200:3306 # 数据库的地址和监听端口
tomcatdb # 连接数据库的默认库名
?autoReconnect=true #连接失败后尝试重连的次数,默认为3次
Step4.修改项目WEB-INF/web.xml 配置文件(若无,请新建),在“</web-app>”之上添加如下代码:
shell>vim /usr/local/tomcat8002/DBTest/WEB-INF/web.xml
<web-app>
<resource-ref>
<description>DB Connection</description> # 连接池描述信息,随便但最好做到见名思意
<res-ref-name>jdbc/TestDB</res-ref-name> # 连接池引用的名字此处要和上面Resource name 保持一致
<res-type>javax.sql.DataSource</res-type> # 连接池类型和上面type保持一致
<res-auth>Container</res-auth> # 连接池管理权属性,和上面auth保持 一致
</resource-ref>
</web-app>
Step5.提供测试tomcat启用连接池后的jsp测试页,放到相应的web app应用下即可,此处我放到/usr/local/tomcat8002/DBTest/下 并命名为mysql-pool.jsp,代码如下
简单代码:只测试是否能连接,没有执行查询语句
<%@ page language="java" %>
<%@ page import="com.mysql.jdbc.Driver" %>
<%@ page import="javax.sql.*" %>
<%@ page import="java.sql.*" %>
<%@ page import="javax.naming.*" %>
<%
try
{
Context initContext = new InitialContext(); # 使用InitialContext new一个initContext 初始化对象
Context envContext = (Context)initContext.lookup("java:/comp/env"); # 连接池访问方式和下面的配置一起决定,完整路径:“java:/comp/env/jdbc/TestDB”
DataSource ds = (DataSource)envContext.lookup("jdbc/TestDB"); # 连接池名字要和Resource里的name一致
Connection connection = ds.getConnection(); # 使用ds对象的getConnection()方法请求通过连接池连接mysql
out.println("Mysql connect is OK !"); # 连接成功,则返回Mysql connect is OK !
connection.close(); # 关闭连接,注意此处关闭是指连接池收回连接,释放本次的请求连接
}
catch( Exception e )
{
out.println( "connent mysql error:" + e ); # 连接失败则,输出错误
}
%>
带select查询的jsp代码:
<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*" %>
<%@ page language="java" %>
<%@ page import="com.mysql.jdbc.Driver" %>
<%@ page import="javax.sql.*" %>
<%@ page import="java.sql.*" %>
<%@ page import="javax.naming.*" %>
<%
try
{
Context initContext = new InitialContext();
Connection conn=null;
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/TestDB");
conn = ds.getConnection();
Statement stmt=conn.createStatement(ResultSet.CONCUR_READ_ONLY,ResultSet.CONCUR_UPDATABLE);
ResultSet rs=stmt.executeQuery("select * from admin"); # 填写你的查询语句,前提是你在数据库服务器上有创建测试的数据库和表
while(rs.next()){
out.println(rs.getInt(1));
out.println(rs.getString(2));
out.println(rs.getString(3));
}
out.println("数据库操作成功!"); # 查询成功则返回 "数据库操作成功!"
rs.close();
stmt.close();
conn.close();
} catch( Exception e ){
out.println( "connent mysql error:" + e ); # 连接失败,输出错误信息,此处可以看到连接失败后尝试的次数
}
%>
Step6.在172.18.200.200的主机上创建测试数据库tomcatdb和表admin
shell>mysql -uroot -p # 使用root登录
mysql>create database tomcatdb character set utf8;
mysql>use tomcatdb
mysql>create table admin(
->userid int(10) unsigned not null,
->username char(20) not null,
->userpass varchar(30) default null,
->primary key (userid)
)engine=InnoDB default charset=utf8;
mysql>desc admin;
+----------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+------------------+------+-----+---------+-------+
| userid | int(10) unsigned | NO | PRI | NULL | |
| username | char(20) | YES | | NULL | |
| userpass | varchar(30) | YES | | NULL | |
+----------+------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql>insert into admin value
->(1,"tomcat","tomcatpass"),
->(2,"redis","redispass"),
->(3,"nginx","nginxpass"),
->(4,"mysql","mysqlpass);
mysql> select * from admin where userid<=4 and userid>=1 and userpass like '%pass' order by userid desc limit 0,4;
+--------+----------+------------+
| userid | username | userpass |
+--------+----------+------------+
| 4 | mysql | mysqlpass |
| 3 | nginx | nginxpass |
| 2 | redis | redispass |
| 1 | tomcat | tomcatpass |
+--------+----------+------------+
4 rows in set (0.04 sec)
mysql> select count(*) from admin where userid<=4 and userid>=1 and userpass like '%pass' order by userid desc limit 0,4;
+----------+
| count(*) |
+----------+
| 4 |
+----------+
1 row in set (0.00 sec)
mysql> select * from admin where userid<=4 and userid>=3 and userpass like '%pass' order by userid desc limit 1;
+--------+----------+-----------+
| userid | username | userpass |
+--------+----------+-----------+
| 4 | mysql | mysqlpass |
| 3 | nginx | nginxpass |
+--------+----------+-----------+
2 rows in set (0.00 sec)
mysql> select count(*) from admin where userid<=4 and userid>=3 and userpass like '%pass' order by userid desc limit 1;
+----------+
| count(*) |
+----------+
| 2 |
+----------+
1 row in set (0.02 sec)
说明:当在mysql命令行模式输入多行命令时,非常有用的命令
mysql>
提示符 含义
mysql> 准备好接受新命令。
-> 等待多行命令的下一行。
‘> 等待下一行,等待以单引号(“’”)开始的字符串的结束。
“> 等待下一行,等待以双引号(“””)开始的字符串的结束。
`> 等待下一行,等待以反斜点(‘`’)开始的识别符的结束。
/*> 等待下一行,等待以/*开始的注释的结束
mysql>sdfsdfs c #取消操作,回到mysql>
mysql>
mysql>123
->456
->789e # 进入mysql的vi模式,和shell里的vi一样,可以修改之前的命令。非常强大
mysql>create database test
->use test
->create table student
->p # 打印上一条命令,你可以复制下来,用的时候粘贴即可
--------------
create database test use test create table students
--------------
mysql> create database test use test create table students
->
mysql> create database test use test create table students bck:create
bck:create # 使用ctrl+r 然后输入历史命令里的关键字,它会帮你找出最近和此关键字匹配的命令,和shell一样用法
Step7.在172.18.200.200 数据库主机上使用tcpdump抓包,开始监控
shell>tcpdump -i eth0 tcp dst port 3306 and dst host 172.18.200.200 -ennvvAASs 0 # 如果用户访问http://172.18.100.98:8002/DBTest/mysql-pool.jsp 就会抓到SELECT 语句
Step8.访问测试页mysql-pool.jsp
tomcat8002 这台主机上使用curl工具访问
shell>curl -i http://172.18.100.98/DBTest/mysql-pool.jsp
访问成功返回如下信息:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=34A44B073DFE4923C96873D56BDE44FB.Tomcat_A8002; Path=/DBTest/; HttpOnly
Content-Type: text/html;charset=utf-8
Content-Length: 107
Date: Sun, 18 Sep 2016 02:59:30 GMT
1 <---------------userid=1
tomcat <---------------username=tomcat
tomcatpass <---------------userpass=tomcatpass
2
redis
redispass
3
nginx
nginxpass
4
mysql
mysqlpass
数据库操作成功!
主机 172.18.200.200 返回如下信息:
10:59:30.291334 00:0c:29:c2:00:82 > 00:0c:29:57:d6:0f, ethertype IPv4 (0x0800), length 90: (tos 0x0, ttl 64, id 16926, offset 0, flags [DF], proto TCP (6), length 76)
172.18.100.98.49261 > 172.18.200.200.3306: Flags [P.], cksum 0x73c1 (correct), seq 2606082206:2606082230, ack 1672819362, win 259, options [nop,nop,TS val 49144395 ecr 49129503], length 24
..)W....).....E..LB.@.@.s>..db.....m...U..c.2.....s......
...K.........select * from admin <-------------哈哈,看到了什么
10:59:30.292212 00:0c:29:c2:00:82 > 00:0c:29:57:d6:0f, ethertype IPv4 (0x0800), length 109: (tos 0x0, ttl 64, id 16927, offset 0, flags [DF], proto TCP (6), length 95)
172.18.100.98.49261 > 172.18.200.200.3306: Flags [P.], cksum 0x3cdd (correct), seq 2606082230:2606082273, ack 1672819651, win 289, options [nop,nop,TS val 49144397 ecr 49129503], length 43
..)W....).....E.._B.@.@.s*..db.....m...U..c.3....!<......
...M....'....SHOW KEYS FROM `admin` FROM `tomcatdb` <---------------还有这,所以tcpdump真的很强
模拟tomcat连接不到mysql
1.通过tcpwrap 和 /etc/hosts.deny,/etc/hosts.allow
查看服务的二进制程序是否依赖libwrap库,比如sshd
shell>ldd `which sshd` | grep -i "libwrap" # ldd 只能检查二进制可执行程序的动态库依赖关系
libwrap.so.0 => /lib64/libwrap.so.0 (0x00007fea0adee000)
shell>echo "ssh:172.18.100.98 deny all" >> /etc/hosts.allow # 协议:IP/network deny all,表示只有172.18.100.98 可以通过ssh协议访问本机,其他都被拒绝
测试效果如下
[root@Slave1 ~]# ssh root@172.18.200.200
root@172.18.200.200's password:
Permission denied, please try again.
root@172.18.200.200's password:
查看mysql是否依赖libwrap库
shell>ldd `which mysqld` | grep -i "libwrap"
shell>echo $? # 查看上条命令执行结果状态,只有0表示成功。# mysqld 不依赖libwrap库
2.通过iptables,在filter表中input链上禁止来自172.18.100.98的用户访问本地tcp 3306提供的服务
shell>iptable -L -nv --line # 注意防火墙的默认策略和现有的防火墙规则。
shell>iptables -t filter -I INPUT 1 -p tcp -s 172.18.100.98 -d 172.18.200.200 --dport 3306 -j DROP #如果默认策略为DROP,就不用添加此条规则,如果默认策略为ACCEPT,则添加此规则到第一条
shell>watch -n 1 'iptables -L -nv --line'
Chain INPUT (policy ACCEPT 718 packets, 34988 bytes)
num pkts bytes target prot opt in out source destination
1 335 19925 DROP tcp -- * * 172.18.100.98 172.18.200.200 # pkts 335 表示此规则匹配到了335个包,都被拒掉了
tcp dpt:3306
tcpdump 结果如下:能看到来自172.18.100.98的请求但没有看到172.18.200.200到172.18.100.98 的响应,说明当数据包到达200.200这台主机的内核空间时,被linux netfilter模块过滤掉了,所以到不了用户空间3306所指的进程
11:46:38.880410 00:0c:29:c2:00:82 > 00:0c:29:57:d6:0f, ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 64, id 31306, offset 0, flags [DF], proto TCP (6), length 60)
172.18.100.98.49336 > 172.18.200.200.3306: Flags [S], cksum 0xc5be (correct), seq 1018473209, win 14600, options [mss 1460,sackOK,TS val 51972993 ecr 0,nop,wscale 6], length 0
0x0000: 000c 2957 d60f 000c 29c2 0082 0800 4500 ..)W....).....E.
0x0010: 003c 7a4a 4000 4006 3b22 ac12 6462 ac12 .<zJ@.@.;"..db..
0x0020: c8c8 c0b8 0cea 3cb4 aaf9 0000 0000 a002 ......<.........
0x0030: 3908 c5be 0000 0204 05b4 0402 080a 0319 9...............
0x0040: 0b81 0000 0000 0103 0306 ..........
11:46:39.567454 00:0c:29:c2:00:82 > 00:0c:29:57:d6:0f, ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 64, id 48704, offset 0, flags [DF], proto TCP (6), length 60)
172.18.100.98.49335 > 172.18.200.200.3306: Flags [S], cksum 0x1096 (correct), seq 1868180174, win 14600, options [mss 1460,sackOK,TS val 51973680 ecr 0,nop,wscale 6], length 0
0x0000: 000c 2957 d60f 000c 29c2 0082 0800 4500 ..)W....).....E.
0x0010: 003c be40 4000 4006 f72b ac12 6462 ac12 .<.@@.@..+..db..
0x0020: c8c8 c0b7 0cea 6f5a 2ace 0000 0000 a002 ......oZ*.......
curl结果:一开始curl一直卡着,其实是等待连接池失败连接重试 一共重试三次,每次尝试时间maxWait="10000",即每次10s ,30s过后,都要返回给客户端结果,但连接池一直会尝试连接mysql,tcpdump里可以看到
[root@Tomcat_A tomcat8002]# curl -i http://172.18.100.98:8002/DBTest/mysql-pool2.jsp
HTTP/1.1 200 OK <-------------为什么状态返回值还是 200 因为你的测试页里有连接尝试失败后返回异常,只不过这是个错误页面,但是jsp的正常响应,只是通过你jsp里的方法访问不到mysql而已
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=A6813E97F41C523A41D733FD29DFD8FB.Tomcat_A8002; Path=/DBTest/; HttpOnly
Content-Type: text/html;charset=utf-8
Content-Length: 186
Date: Sun, 18 Sep 2016 03:40:37 GMT
connent mysql error:com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.
# Attempted reconnect 3 times ---> 可知重试了3次
tomcat日志
shell>tailf /usr/local/tomcat8002/logs/catalina.out # 反馈信息如下
com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:195)
com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:184)
com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:200)
com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1086)
com.mchange.v2.resourcepool.BasicResourcePool.doAcquireAndDecrementPendingAcquiresWithinLockOnSuccess(BasicResourcePool.java:1073)
com.mchange.v2.resourcepool.BasicResourcePool.access$800(BasicResourcePool.java:44)
com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask.run(BasicResourcePool.java:1810)
com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:648)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Cannot open connection
#明显抛出异常了,在172.18.200.200 执行iptables -D INPUT 1
总结:不做不知道,一做吓一跳,不要怕出错,不要怕看不懂代码,先做出效果来再说,写代码也不是天生的,只要一心向佛,总有一天你也是代码达人,不求写出多么优秀的代码,但求别人能看懂如果运维不去学一门正真意义上的编程语言,我只能说等待开发的小爷们给你翻白眼吧,建议jsp,python,lua,运维是一种任重而道远的背锅历程,哈哈不要轻易怀疑自己的智商,如果说点打击的话开发最终拼的是脑子,我本不想说这种话,怕你们给我攒人气,但毕竟那就是事实,一个人的聪明就决定了他可提升的高度,聪明的人尚且在哪里努力学习,像我们这种天生脑子就转的不快的人就更应该拿出多于他几倍的时间来研究学习,以此来缩短我们与这些本就聪明的大牛之间的距离,当然有的人也拿出了多于他几倍的时间,只不过是在发牢骚或者泡妞 ,我这里不是说不让你发牢骚不取媳妇,而是当你用羡慕的目光观望和你在同一个行业但薪水不一样的大牛时,最起码你脑子里第一个想的应该是计划,我要在多长多长时间达到一个什么目标,而不是你累计吃了多少六个核桃。学习没有捷径,如果学习有统一范式,那么你不上清华北大你真冤。既然我们不能垂直扩展,那我们就想办法横向扩展。天道酬勤,不是不牛,只是时候未到