babyfish-ct / jimmer

A revolutionary ORM framework for both java and kotlin.
Apache License 2.0
873 stars 86 forks source link

[Feature Request] Kotlin Non-Blocking #771

Open thalesdev opened 1 week ago

thalesdev commented 1 week ago

Is there any chance of adding non-blocking features? In the development of idiomatic applications in Kotlin, the use of coroutines is essential. It would be very interesting to have a data layer with the non-blocking jimmer. With an API similar to that of Micronaut Data R2DBC

JeanPoffo commented 1 week ago

It would really be an excellent feature!

babyfish-ct commented 1 week ago

This is a huge feature request, which will not be considered before 1.0. Because save-command is very complicated, and its internal mechanism is too complicated. It took a year to make up my mind to refactor it, and the refactoring took 3 months.

The currently save command of the document is old and is being refactored, only the save-command related project in the attached examples is the latest demonstration

In addition, I also want to use the time when Jimmer evolves to 1.0 to observe whether the newer JDK can sufficiently optimize the virtual thread that currently performs poorly.

ForteScarlet commented 1 week ago

I guess wrapping up the sqlClient operations with withContext is an option to consider.

withContext(Dispatchers.VirtualOrIO) {
    sql.executeQuery(...)
}

Instead of making wholesale changes to the API or copying an asynchronous API with almost the same amount of work, I think it's better to look forward to virtual threads, if only for the sake of better resource utilization for IO behavior.

Even though virtual threads aren't performing as well as we might expect, at least it's still trying, isn't it?

As far as I know, PostgreSQL, H2 and MySQL(9.x) should already have optimisations or changes for virtual thread.

SWQXDBA commented 2 days ago

I think R2DBC will fade away as virtual threads mature. Locking due to the synchronized keyword is also addressed in jdk24. As time goes on, there is less and less reason to use R2DBC.

JeanPoffo commented 19 hours ago

@ForteScarlet is not that simple. Mannualy using different contexts, the thread is changed arbitrarily and the common mechanisms of transaction does not support this case. For this motive, native async mechanisms (R2DBC) are the best approach.

ForteScarlet commented 10 hours ago

@JeanPoffo It's true that switching contexts does cause threads to be more alive and kicking. But with Jimmer, it has no state, doesn't care about transactions, and can also provide specific connections in almost any API.

Transactions that can fail due to thread switches are usually caused by the same thing as annotated transactions(e.g. spring's @Transactional ) or ThreadLocal connections.

I think there are many ways to compromise, such as starting a transaction in the context.

withContext(Dispatchers.xxx) {
    transactionManager.execute {
        sql.createQuery(...) {...}
    }
}

Or manually control your connection and transaction.

val dataSource: DataSource = ...
val newConnection = getConnection(dataSource)

try {
    withContext(Dispatcher1) {
        sql.createQuery(...) { ... }.execute(newConnection)
    }

    withContext(Dispatcher2) {
        sql.entities.save(..., con = newConnection) {
            // Save command DSL...
        }
    }

    // commit when success.
    newConnection.commit()
} catch (error: Throwable) {
    // Rollback when error
    newConnection.rollback()
}

releaseConnection(newConnection)

In Kotlin, ThreadLocal can also work together with context, for example, using ThreadLocal.asContextElement() (This may be useful if you plan to customise the ConnectionManager ).

In Exposed, they also provide a solution to turn on transactions using a suspend function, although they are also JDBC-based.

Of course, all this is not to deny R2DBC; if it can truly fully support R2DBC, that would definitely be a wonderful thing!

However, as mentioned by @SWQXDBA, with the gradual maturation of virtual threads, the boundary between reactive programming and virtual threads in the JVM will become increasingly blurred.

For Kotlin, it might be okay, but for Java, both writing and debugging with reactive APIs is not a very good experience.

Regardless, the above is just my personal opinion. I am also very much looking forward to the day when Jimmer can support R2DBC! Perhaps in the future, there will be even more excellent solutions for Java database connectivity 😄