Spring数据库连接池url参数踩坑及解决
在使用Spring数据库连接池时,很多开发者可能会遇到一些莫名其妙的问题,比如连接不上、连接超时、连接池达到最大连接数等等,这些问题可能很难排查。其中一个容易被忽视的问题是url参数配置不当,这会导致数据库连接池的异常。
1. url参数
首先,我们来了解一下url参数有哪些,以及它们分别代表什么含义。下面是比较常见的几个参数:
-
jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
-
useUnicode=true:使用Unicode字符集,可避免中文乱码;
- characterEncoding=utf-8:设定字符编码为utf-8;
-
allowMultiQueries=true:开启允许多语句查询。
-
jdbc:mysql://127.0.0.1:3306/test?user=root&password=123456&useSSL=false
-
user=root:指定数据库用户名;
- password=123456:指定数据库密码;
- useSSL=false:禁用SSL连接。
我们在使用Spring连接池时,经常需要配置连接池的参数,如下:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test" />
<property name="user" value="root" />
<property name="password" value="123456" />
<property name="initialPoolSize" value="5" />
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="40" />
<property name="acquireIncrement" value="2" />
</bean>
注意:上述配置中没有包括url的参数,因为Spring在访问数据库时会自动加上一些参数,如useUnicode、characterEncoding等。
2. 问题的产生
但是有时候,我们自己也会在url中加入一些参数,比如allowMultiQueries=true。这时,就可能会出现一些问题。
比如下面的配置:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test?allowMultiQueries=true" />
<property name="user" value="root" />
<property name="password" value="123456" />
<property name="initialPoolSize" value="5" />
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="40" />
<property name="acquireIncrement" value="2" />
</bean>
虽然加了allowMultiQueries参数,但是会发现,这并没有起到作用,依然无法执行多查询语句。而且,这时c3p0连接池也可能会出现一些问题,比如连接超时,连接不上等等。
3. 解决方案
原因就是Spring会自动将一些参数拼接到url中,重复的参数就会覆盖掉我们自己写的参数。解决方案也很简单,只需要在参数后面再加上&号即可。
比如,正确的配置应该是:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test?allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8" />
<property name="user" value="root" />
<property name="password" value="123456" />
<property name="initialPoolSize" value="5" />
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="40" />
<property name="acquireIncrement" value="2" />
</bean>
需要注意的是,在加上&号后,用来分隔参数的“&”号,需要转义为&。
另外,使用Spring和一些开源框架的时候,建议不要在url中添加额外的参数,如果想要增加配置的话,可以通过Spring提供的setter方法,来设置一些特殊的参数。
4. 示例说明
示例一
现在我有一个Spring的连接池配置,如下:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&autoReconnect=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="maxActive" value="100"/>
<property name="maxIdle" value="20"/>
<property name="maxWait" value="1000"/>
</bean>
连接数据库时,会出现以下异常:
java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
这是由于MySQL 8.0以上版本将serverTimezone配置为UTC时,driver一定要配置成8.0以上版本,否则需要设置server时区为别的(比如Asia/Shanghai)。
解决方法是在url中添加serverTimezone参数,修改后的配置如下:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="maxActive" value="100"/>
<property name="maxIdle" value="20"/>
<property name="maxWait" value="1000"/>
</bean>
示例二
再来看一个连接不上数据库的问题。比如下面的配置:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="123456" />
</bean>
启动应用时,会抛出如下异常:
org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)
这是由于MySQL对root用户的连接进行了限制,需要在MySQL中增加root的授权。可以通过如下命令进行授权:
GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY '123456' WITH GRANT OPTION;
然后重新启动应用,就可以成功连接数据库了。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring数据库连接池url参数踩坑及解决 - Python技术站