Tomcat 与 数据库连接池 的小坑
连接池的优点众所周知。
我们可以自己实现数据库连接池,也可引入实现数据库连接池的jar包,按要求进行配置后直接使用。
关于这方面的资料,好多dalao博客上记录的都是旧版本Tomcat的配置方式,很可能随版本更新有所变化,在实际应用时一定要注意这个坑,特别注意Tomcat启动输出中是否有警告或者其他错误,以免被简单的问题卡死。
之前参考孤傲苍狼dalao的博客配置Tomcat内置连接池,因为使用了旧版配置属性,最大连接数maxActive,而新版Tomcat已经用maxTotal取代之,导致最大连接数配置无效默认为8,失了智一样困扰了一个晚上,第二天才猛的找回智商在Tomcat启动输出中发现警告:
22-Jan-2018 12:44:57.030 警告 [localhost-startStop-1] org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory.getObjectInstance Name = DBPool Property maxActive isnot used in DBCP2, use maxTotal instead. maxTotal default value is 8. You have set value of "100" for "maxActive" property, which is being ignored.
查了一下才知道新版Tomcat已经不认这个属性了。
教训:参考别人经验一定要注意别人使用的软件版本,注意软件告诉你的信息,及时发现错误,切忌生搬硬套。
孤傲苍狼dalao数据库连接池的博客:https://www.cnblogs.com/xdp-gacl/p/4002804.html
在此进行一些摘要,特别注意dalao似乎用的Tomcat7,此处不做修改,使用时注意版本变化!
2.2、编写数据库连接池
编写连接池需实现java.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:
- Connection getConnection()
- Connection getConnection(String username, String password)
实现DataSource接口,并实现连接池功能的步骤:
- 在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。
- 实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。
- 当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。Collection保证将自己返回到LinkedList中是此处编程的难点。
数据库连接池核心代码
使用动态代理技术构建连接池中的connection
1 proxyConn = (Connection) Proxy.newProxyInstance(this.getClass()
2 .getClassLoader(), conn.getClass().getInterfaces(),
3 new InvocationHandler() {
4 //此处为内部类,当close方法被调用时将conn还回池中,其它方法直接执行
5 public Object invoke(Object proxy, Method method,
6 Object[] args) throws Throwable {
7 if (method.getName().equals("close")) {
8 pool.addLast(conn);
9 return null;
10 }
11 return method.invoke(conn, args);
12 }
13 });
数据库连接池编写范例:
1 package me.gacl.demo;
2
3 import java.io.InputStream;
4 import java.io.PrintWriter;
5 import java.lang.reflect.InvocationHandler;
6 import java.lang.reflect.Method;
7 import java.lang.reflect.Proxy;
8 import java.sql.Connection;
9 import java.sql.DriverManager;
10 import java.sql.SQLException;
11 import java.util.LinkedList;
12 import java.util.Properties;
13 import javax.sql.DataSource;
14
15 /**
16 * @ClassName: JdbcPool
17 * @Description:编写数据库连接池
18 * @author: 孤傲苍狼
19 * @date: 2014-9-30 下午11:07:23
20 *
21 */
22 public class JdbcPool implements DataSource{
23
24 /**
25 * @Field: listConnections
26 * 使用LinkedList集合来存放数据库链接,
27 * 由于要频繁读写List集合,所以这里使用LinkedList存储数据库连接比较合适
28 */
29 private static LinkedList<Connection> listConnections = new LinkedList<Connection>();
30
31 static{
32 //在静态代码块中加载db.properties数据库配置文件
33 InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties");
34 Properties prop = new Properties();
35 try {
36 prop.load(in);
37 String driver = prop.getProperty("driver");
38 String url = prop.getProperty("url");
39 String username = prop.getProperty("username");
40 String password = prop.getProperty("password");
41 //数据库连接池的初始化连接数大小
42 int jdbcPoolInitSize =Integer.parseInt(prop.getProperty("jdbcPoolInitSize"));
43 //加载数据库驱动
44 Class.forName(driver);
45 for (int i = 0; i < jdbcPoolInitSize; i++) {
46 Connection conn = DriverManager.getConnection(url, username, password);
47 System.out.println("获取到了链接" + conn);
48 //将获取到的数据库连接加入到listConnections集合中,listConnections集合此时就是一个存放了数据库连接的连接池
49 listConnections.add(conn);
50 }
51
52 } catch (Exception e) {
53 throw new ExceptionInInitializerError(e);
54 }
55 }
56
57 @Override
58 public PrintWriter getLogWriter() throws SQLException {
59 // TODO Auto-generated method stub
60 return null;
61 }
62
63 @Override
64 public void setLogWriter(PrintWriter out) throws SQLException {
65 // TODO Auto-generated method stub
66
67 }
68
69 @Override
70 public void setLoginTimeout(int seconds) throws SQLException {
71 // TODO Auto-generated method stub
72
73 }
74
75 @Override
76 public int getLoginTimeout() throws SQLException {
77 // TODO Auto-generated method stub
78 return 0;
79 }
80
81 @Override
82 public <T> T unwrap(Class<T> iface) throws SQLException {
83 // TODO Auto-generated method stub
84 return null;
85 }
86
87 @Override
88 public boolean isWrapperFor(Class<?> iface) throws SQLException {
89 // TODO Auto-generated method stub
90 return false;
91 }
92
93 /* 获取数据库连接
94 * @see javax.sql.DataSource#getConnection()
95 */
96 @Override