如何在无法编辑Tomcat server.xml中MySQL数据源的情况下,通过JndiDatasourceLookup为连接添加URL参数?
如何在无法编辑Tomcat server.xml中MySQL数据源的情况下,通过JndiDatasourceLookup为连接添加URL参数?
嗨,这个场景我太熟悉了——没法改Tomcat的server.xml配置,却要解决零时间戳的转换异常,确实头疼。不过不用慌,有两个靠谱的办法能搞定,完全不用碰数据源的原始配置:
方法一:每次获取连接后直接设置属性
MySQL的JDBC连接本身支持直接设置zeroDateTimeBehavior属性,不用非得在URL里加参数。你可以在通过JNDI拿到数据源后,每次获取连接时强转为MySQL特定的连接类,手动配置这个属性:
首先获取原始JNDI数据源:
JndiDataSourceLookup lookup = new JndiDataSourceLookup(); DataSource originalDs = lookup.getDataSource("你的JNDI数据源名称");
然后在使用连接时做配置:
try (Connection conn = originalDs.getConnection()) { // 判断是否为MySQL JDBC连接 if (conn instanceof com.mysql.cj.jdbc.JdbcConnection) { com.mysql.cj.jdbc.JdbcConnection mysqlConn = (com.mysql.cj.jdbc.JdbcConnection) conn; // 设置零时间戳转换规则为convertToNull mysqlConn.setZeroDateTimeBehavior("convertToNull"); } // 接下来正常执行数据库操作即可 } catch (SQLException e) { // 处理异常逻辑 }
不过这个方法需要每次获取连接都手动设置,如果你用了连接池,连接会被复用,所以更推荐下面的包装方法,一劳永逸。
方法二:包装数据源,统一处理所有连接
写一个简单的数据源包装类,把从JNDI获取到的数据源包起来,每次获取连接时自动帮你配置好zeroDateTimeBehavior属性:
先定义包装类:
public class MySqlConfiguredDataSource implements DataSource { private final DataSource delegate; public MySqlConfiguredDataSource(DataSource delegate) { this.delegate = delegate; } // 核心方法:获取连接后自动配置 @Override public Connection getConnection() throws SQLException { Connection conn = delegate.getConnection(); configureMysqlConnection(conn); return conn; } @Override public Connection getConnection(String username, String password) throws SQLException { Connection conn = delegate.getConnection(username, password); configureMysqlConnection(conn); return conn; } // 实现DataSource接口的其他方法,全部委托给原始数据源 @Override public <T> T unwrap(Class<T> iface) throws SQLException { return delegate.unwrap(iface); } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return delegate.isWrapperFor(iface); } @Override public PrintWriter getLogWriter() throws SQLException { return delegate.getLogWriter(); } @Override public void setLogWriter(PrintWriter out) throws SQLException { delegate.setLogWriter(out); } @Override public void setLoginTimeout(int seconds) throws SQLException { delegate.setLoginTimeout(seconds); } @Override public int getLoginTimeout() throws SQLException { return delegate.getLoginTimeout(); } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return delegate.getParentLogger(); } // 统一配置MySQL连接的方法 private void configureMysqlConnection(Connection conn) throws SQLException { if (conn instanceof com.mysql.cj.jdbc.JdbcConnection) { com.mysql.cj.jdbc.JdbcConnection mysqlConn = (com.mysql.cj.jdbc.JdbcConnection) conn; mysqlConn.setZeroDateTimeBehavior("convertToNull"); // 如果还有其他需要设置的JDBC参数,也可以在这里统一添加 } } }
然后使用包装后的数据源:
JndiDataSourceLookup lookup = new JndiDataSourceLookup(); DataSource originalDs = lookup.getDataSource("你的JNDI数据源名称"); // 用自定义包装类包裹原始数据源 DataSource configuredDs = new MySqlConfiguredDataSource(originalDs); // 之后所有数据库操作都用configuredDs来获取连接即可
如果你的项目用了Spring框架,还可以把包装后的数据源注册成Bean,让整个应用自动使用:
@Bean public DataSource dataSource() { JndiDataSourceLookup lookup = new JndiDataSourceLookup(); DataSource originalDs = lookup.getDataSource("你的JNDI数据源名称"); return new MySqlConfiguredDataSource(originalDs); }
这样不管哪里用到数据源,拿到的连接都会自动配置好零时间戳的转换规则,完全不用再手动处理啦。
备注:内容来源于stack exchange,提问作者TheBudderBomb
相关产品推荐
相关产品推荐

