简体   繁体   English

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

[英]How to handle null while setting date in log4j2 jdbcappender?

When I set null value in the date column I get "1900-01-01 00:00:00.000" value in my table and I am expecting NULL in that column. 当我在日期列中设置空值时,我在表中获得“ 1900-01-01 00:00:00.000”值,并且我期望该列中为NULL。 As this is handled properly in jdbc if I put like this 因为如果我这样把它在jdbc中正确处理

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

log4j2.xml 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="%X{ID}" isUnicode="false"/>
            <Column name="startdate" pattern="%X{startdate}" isUnicode="false"/>
            <Column name="enddate" pattern="%X{enddate}" isUnicode="false"/>
        </JDBC>

    </Appenders>

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

</Configuration>

Datatype of columns startdate and enddate is datetime 起始日期和结束日期列的数据类型为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), "");

The same is for String with null value. 对于具有null值的String也是一样。

Inserting null 插入空值

I don't think it's possible to get null into any column of any type using JDBCAppender with patterns like this. 我认为使用JDBCAppender的模式不可能将null插入任何类型的任何列中。

This thread popped up a couple of years ago, followed by this Jira issue . 此线程在几年前突然出现,随后出现了《 吉拉》杂志 None of it seems to have gotten any attention. 它似乎都没有引起任何注意。

The short version is that a StringBuilder is used between pattern and prepared statement, and thus the INSERT always gets a non-null string, even if (in your example) null is the value in the ThreadContext . 简短的版本是在模式和准备好的语句之间使用StringBuilder ,因此INSERT始终获取非空字符串,即使(在您的示例中) ThreadContext的值为null So it's possible to insert an empty string, or the string "null" , but it doesn't appear to be possible to insert the value null . 因此可以插入一个空字符串或字符串"null" ,但似乎无法插入 null

January 1, 1900 1900年1月1日

When I run your example against a MySQL database, the insert fails up front, because MySQL doesn't know how to construct a DATETIME from an empty string. 当我对一个MySQL数据库运行您的示例时,该插入操作会预先失败,因为MySQL不知道如何从一个空字符串构造一个DATETIME

I'm guessing you're using SQL Server, which will happily turn an empty string into 1900-01-01 00:00:00.000 , because of course that's what you meant. 我猜你使用SQL Server,它会高兴地把一个空字符串为1900-01-01 00:00:00.000自然是因为那是你的意思

Regardless of the database you use, JDBCAppender is going to fill the INSERT statement with non-null strings. 无论使用哪种数据库, JDBCAppender都将用非空字符串填充INSERT语句。 What happens from there will vary from DB to DB. 从那里发生的事情将因数据库而异。

Why? 为什么?

At first it may seem strange that the framework is changing your value ( null ) to another value (empty string). 刚开始,框架将您的值( null )更改为另一个值(空字符串)似乎很奇怪。 However, at its core, logging is about strings of text. 但是,日志记录的核心文本字符串。

Yes, there's an appender that will write these strings to a database. 是的,有一个追加程序会将这些字符串写入数据库。 And yes, your database can in turn coax those strings into types like DATETIME or INTEGER . 是的,您的数据库又可以将这些字符串哄骗成DATETIMEINTEGER类的类型。 But to any given appender, it's all really just about manipulating and outputting strings. 但是对于任何给定的附加程序,这实际上只是关于操作和输出字符串。

Possible work-around 可能的解决方法

If you really want to get null into the database using JDBCAppender , you may be able to write a trigger . 如果您确实想使用JDBCAppendernull放入数据库中,则可以编写触发器

Final Observation 最终观察

Not sure if this helps any, but I may as well present all my findings: 不确定这是否有帮助,但我也可以介绍我的所有发现:

Using ColumnMapping instead of Column in your log4j config allows you to specify a class name. 在您的log4j配置中使用ColumnMapping而不是Column可以指定类名。 The presence (or absence) and value of this class name does change the value that is inserted into the database. 该类名的存在(或不存在)和值的确会更改插入数据库中的值。 For example, using SQL Server Express 2014: 例如,使用SQL Server Express 2014:

<ColumnMapping name="startdate" pattern="%X{startdate}" type="java.sql.Timestamp"/>

Will cause the current date and time to be logged when startdate is null, instead of 1900-01-01. startdate为null而不是1900-01-01时,将导致记录当前日期和时间。 Using java.sql.Date instead will log the current date without time. 相反,使用java.sql.Date将记录当前日期,而无需时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM