I understood that SqlLobValue automatically close inputStream by framework. See this

but it's not.

this is my code that show don't close inputStream automatically.

val lobHandler: LobHandler = DefaultLobHandler() // reusable object
val stream = MyInputStream(".gitignore")
namedParameterJdbcTemplate.jdbcTemplate.update(
    "INSERT INTO data (id, name, no, text) VALUES (?, ?, ?, ?)", arrayOf(
        12345,
        "ajsodp",
        12390,
        SqlLobValue(stream, 10, lobHandler),
    ), intArrayOf(Types.INTEGER, Types.VARCHAR, Types.INTEGER, Types.BLOB)
)
println("closed? ${stream.isClosed}") # closed? false
stream.close()
println("closed? ${stream.isClosed}") # closed? true

class MyInputStream(name: String) : FileInputStream(name) {

    var isClosed = false

    override fun close() {
        if (!isClosed) {
            isClosed = true
            super.close()
        }
    }
}

Should i close inputStream manually?

Comment From: sbrannen

I understood that SqlLobValue automatically close inputStream by framework.

The documentation states that the framework will automatically close the LobCreator. It does not state that it will automatically close a supplied InputStream.

A LobCreator is obtained from the LobHandler. When using the DefaultLobHandler in its default configuration, getLobCreator() will return a DefaultLobCreator which does not close the InputStream. If you set the createTemporaryLob to true, getLobCreator() will return a TemporaryLobCreator which will close the InputStream.

Thus it depends on your configuration.

If you use the defaults for DefaultLobHandler you need to close the InputStream manually. If you set createTemporaryLob to true, the InputStream will be closed automatically.

In light of that I am closing this issue.