在 log4j2 jdbcapender 中设置日期时如何处理 null?

Posted

技术标签:

【中文标题】在 log4j2 jdbcapender 中设置日期时如何处理 null?【英文标题】:How to handle null while setting date in log4j2 jdbcappender? 【发布时间】:2017-11-30 12:07:12 【问题描述】:

当我在日期列中设置空值时,我在表中得到“1900-01-01 00:00:00.000”值,并且我期望该列中为 NULL。 因为如果我这样放的话,这在 jdbc 中得到了正确处理

preparedStatement.setBindParam(Types.TIMESTAMP, 12, startdate);

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug">

    <CustomLevels>
        <CustomLevel name="TESTLOG" intLevel="552" />
    </CustomLevels>

    <Appenders>

        <JDBC name="myAppender" tableName="MYTABLE">
            <DataSource jndiName="java:MyDataSource" />
            <Column name="ID" pattern="%XID" isUnicode="false"/>
            <Column name="startdate" pattern="%Xstartdate" isUnicode="false"/>
            <Column name="enddate" pattern="%Xenddate" isUnicode="false"/>
        </JDBC>

    </Appenders>

    <Loggers>
        <Root level="trace"  includeLocation="false">
            <AppenderRef ref="myAppender" level="TESTLOG" />
        </Root>
    </Loggers>

</Configuration>

startdate 和 enddate 列的数据类型是 datetime

ThreadContext.put("startdate", startdate != null ? startdate.toString() : null);
ThreadContext.put("enddate", a_reportEndDate != null ? enddate.toString() : null);
final Logger LOGGER = LogManager.getLogger();
LOGGER.log(Level.forName("TESTLOG", 552), "");

对于空值的字符串也是如此。

【问题讨论】:

也许您的表是使用时间戳列的默认值创建的? 【参考方案1】:

插入空值

我认为使用JDBCAppender 和这样的模式不可能将null 放入任何类型的任何列中。

This thread 是几年前出现的,紧随其后的是 this Jira issue。似乎都没有引起任何注意。

简短的版本是在模式和准备好的语句之间使用StringBuilder,因此INSERT总是得到一个非空字符串,即使(在你的例子中)null是@中的值987654329@。所以可以插入一个空字符串,或者字符串"null",但是好像不能插入null

1900 年 1 月 1 日

当我针对 mysql 数据库运行您的示例时,插入预先失败,因为 MySQL 不知道如何从空字符串构造 DATETIME

我猜你正在使用 SQL Server,它会很高兴地将一个空字符串转换为 1900-01-01 00:00:00.000,因为当然这就是你的意思。

无论您使用什么数据库,JDBCAppender 都会用非空字符串填充INSERT 语句。从那里发生的事情因数据库而异。

为什么?

起初,框架将您的值 (null) 更改为另一个值(空字符串)可能看起来很奇怪。然而,就其核心而言,日志记录关于文本字符串的。

是的,有一个附加程序可以将这些字符串写入数据库。是的,您的数据库可以反过来将这些字符串转化为DATETIMEINTEGER 之类的类型。但是对于任何给定的 appender,它实际上只是关于操作和输出字符串。

可能的解决方法

如果您真的想使用JDBCAppendernull 输入数据库,您可以使用write a trigger。

最终观察

不确定这是否有帮助,但我不妨介绍一下我的所有发现:

在 log4j 配置中使用 ColumnMapping 而不是 Column 允许您指定类名。此类名称的存在(或不存在)和值确实会更改插入到数据库中的值。例如,使用 SQL Server Express 2014:

<ColumnMapping name="startdate" pattern="%Xstartdate" type="java.sql.Timestamp"/>

startdate 为空时,将记录当前日期和时间,而不是 1900-01-01。改用java.sql.Date 将记录当前日期而没有时间。

【讨论】:

由于我使用的是 java 6,并且 log4j-core-2.3.jar 不支持 ColumnMapping

以上是关于在 log4j2 jdbcapender 中设置日期时如何处理 null?的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring Boot 应用程序中未针对休眠和弹簧过滤 Log4j2 日志级别

使用Log4J 2查找JNDI变量查找时如何设置默认值?

如何在 IDE 中使用一个 log4j2 配置文件进行运行时,使用另一个 log4j2 配置文件进行打包/部署?

Log4j2 配置 - 找不到 log4j2 配置文件

Log4j2 简单使用

深入源码解析日志框架Log4j2