2013/4/12 Lukas Eder <[email protected]>:
> Hi there,
>
> 2013/4/7 Christopher Deckers <[email protected]>:
>> Hi Lukas,
>>
>>> I wish to exclude the DSLContext / Executor from these thoughts. It is
>>> complicating things unnecessarily. It has no state / lifecycle of its
>>> own. Introducing it in the way I originally did was confusing. The
>>> thought of having "new Executor" along with the name "Executor" seemed
>>> to indicate that it has a life of its own. It doesn't. It had a 1-to-1
>>> relationship with Configuration, adding DSL capabilities.
>>
>>
>> Configuration does not expose methods with Connection. DSLContext creation
>> does, which means it is not safe to use because it may have a state
>> (especially if the part of the application a developer is working on is
>> independant from the part of the API that creates the DSLContext).
>>
>> JOOQ could garantee this by having only one "using" method:
>>     using(Configuration).
>>
>> For quick runs of queries that do not need listeners (and other
>> Configuration stuff), you could have something like:
>>     new UnsafeConfiguration(Connection, Dialect)
>> which lazy users could use:
>>     using(new UnsafeConfiguration(Connection, Dialect))
>>
>> This would clearly show the intent, warn the users, etc. They would know
>> that sharing the resulting Configuration may be dangerous (and its Javadoc
>> would document why it is unsafe, because of the way it provides
>> connections).
>
> The "UnsafeConfiguration" is really called DefaultConfiguration, and
> it exists :-)
> And I'm making it public for reuse.
>
> But the contract on "using(Connection, SQLDialect)" is clear. It is
> convenience for "using(new DefaultConfiguration(Connection,
> SQLDialect))". I bet you will try to argue against this convenience.
> jOOQ always overloads methods for tedious repetitive tasks. It has
> been like this before, and I'd like to keep it this way.
>
>>> As I will
>>> explain further down, everything you want to do can be done without
>>> allowing "Executor" to have its own lifecycle.
>>
>>
>> It can, but it is not guaranteed. When 20-50 developers work on the same
>> business application, with many modules and so on, you can only rely on the
>> hard rules set by libraries. If a rule is not clear or has several different
>> meaning, it is dangerous, especially if that library is used throughout the
>> whole application.
>>
>> If I were the only developer on the applications I work on, I wouldn't care
>> :)
>
> OK, then let's learn from the "best" and I'll reiterate one of my
> examples. Let's have a look at javax.sql.DataSource. Its contract
> clearly specifies:
>
> 1. Basic implementation -- produces a standard Connection object
> 2. Connection pooling implementation -- produces a Connection object
> that will automatically participate in connection pooling. This
> implementation works with a middle-tier connection pooling manager.
> 3. Distributed transaction implementation -- produces a Connection
> object that may be used for distributed transactions and almost always
> participates in connection pooling. This implementation works with a
> middle-tier transaction manager and almost always with a connection
> pooling manager.
>
> Now, this is a definite invitation to shoot yourself in the foot, from
> an API perspective. You can simply not know what happens with the
> returned Connection, except if you read docs. Still, I've worked in
> teams of 20-50 developers, and some architect has solved this problem
> about 10 years ago, and ever since, no one cared where the connection
> really came from. It came from some static method calling Weblogic's
> JNDI mechanisms.
>
> The same applies to a jOOQ Connection. Only 1-2 guys from the 20-50
> developers will actually try to understand how to use an
> org.jooq.Configuration. All the others will operate on a
> pre-configured DSLContext object, that is obtained through a static
> method, through dependency injection, you name it.
>
>>> I agree. Although, I think that the ConnectionProvider *should* be
>>> loose to cover all use cases.
>>
>>
>> By being loose, you prevent use cases (like 3rd party tools taking a
>> Configuration as a parameter to use connections for their own needs, a 3rd
>> party execute listener that needs a dedicated connection, etc.).
>> Please, show me a use case where being loose helps compared to having the
>> hard rule of "acquire" always returning a dedicated connection?
>
> - A batch job. You always want precisely the same connection for every query.
> - Within a distributed javax.transaction.UserTransaction. Your
> ConnectionProvider doesn't even know whether it should return the same
> connection, or a new one. The container manages that.
>
> Hardening the contract will make it more difficult to use jOOQ at all.
> It makes it simpler for 3rd party tools that want to acquire
> connections through jOOQ's API (let's name them the jOOQ Console). But
> should they really do that in the first place? If the console needs a
> dedicated connection, then it should provide a Popup for user input.
> You can't just expect to get a dedicated connection from all
> installations of jOOQ, no matter what the connection / transaction
> model is, and think they will be able to give you one. Such a use-case
> shouldn't drive the design decisions of a jOOQ core
> ConnectionProvider.
>
> Or to name your example of the Runnable and the Swing context:
>
> I won't add Configuration.getDedicatedConnectionForJOOQConsole() :-)
>
> Please tell me, if I'm missing the point here, and if you know a
> concrete use-case of a 3rd party tool that really relies on jOOQ
> providing it with a "dedicated" connection through the
> ConnectionProvider API.
>
>> I know you want to be loose on every aspects, but that results in a fuzzy
>> API where multi-developers project cannot make assumptions (or wrong ones).
>> These unspecified aspects then have to be handled through company policies,
>> provided the issues are identified, and may be occasionaly overlooked
>> (blowing up in production of course).
>
> Yes. And No! Loose doesn't mean fuzzy. Loose just means that jOOQ
> defines a minimal contracts on its SPI for jOOQ to work.
>
> So the architect / lead-developer implements that once, and then
> everyone gets back to business. Any tight contract I will define now
> will be thrown back at me because I hadn't thought of this and that
> and yet another way to handle connections, transactions, etc.
>
>>> Yes, it is hard to get it right. Do note that this was much harder to
>>> get right before jOOQ 3.0, before the introduction of a
>>> ConnectionProvider. In order to get it right, a properly pooled (and
>>> thus shareable) DataSource was needed.
>>
>> I am not sure how connections taken from a DataSource are supposed to be
>> returned to their pool. Any experience on real applications using DataSource
>> to explain the lifecycle?
>
> Yes. Weblogic, JTA environments (I quote that all the time). The
> lifecycle is this:
>
> Within the DAO:
> ============
>
> 1. I get a DataSource via JNDI. That's a lot of magic to me already.
> 2. I get a Connection from that DataSource. It "magically" knows in
> which JTA transaction I am in, right now.
> 3. Connection.close(). This puts it in a "special" state, whose
> documentation I hadn't found on Weblogic
> 4. I can get another Connection from the DataSource. "Magically", it
> will be the same as before, with that "special" state reset.
> 5. I close it again.
>
> Within the Service:
> ==============
>
> 1. I get a UserTransaction via JNDI. More magic.
> 2. I call some DAOs. See above
> 3. I call tx.commit() or tx.rollback(). From now on, the DAOs don't
> work anymore, as they cannot get a DataSource via JNDI. But if I
> didn't close all my connections before, I get exceptions here.
>
> The above is really easy to use from a user perspective, although I
> don't want to look at Weblogic's internals :-)
>
> Anyway, this leads to a real dumb ConnectionProvider implementation
> that just delegates everything to Weblogic. Again, here in this gist
> by Ben Manes, you have the same "dumb" ConnectionProvider
> implementation that "just doesn't care". Spring already got everything
> right:
> https://gist.github.com/ben-manes/5316351
>
> So, "loose" is the way to go for ConnectionProvider, in my opinion.
> Loose doesn't mean fuzzy. The contract is crystal clear. jOOQ will
> release() every connection that was acquired(). Clients know their
> transaction model better than jOOQ. They will know how to properly
> implement "acquire()".
>
>>> B) jOOQ can provide default implementations for the
>>> ExecuteListenerFactory, e.g. a DefaultExecuteListenerFactory, which
>>> would contain a constant list of ExecuteListeners.
>>
>>
>> Let's take the example of the DebuggerListener. How should I code it? The
>> whole point of the factory is so that DebuggerListener is a new instance per
>> run and thus can retain state. How would JOOQ instanciate it if it were to
>> automatically use such kind of stateful listener but wanted a static list of
>> listeners?
>
> Yes, I got that wrong in my first understanding of
> ExecuteListenerProvider. You're right about this. So let's re-iterate:
>
> - Configuration.executeListenerProviders() returns a list of
> ExecuteListenerProvider
> - ExecuteListenerProvider implementations are free to choose whether
> they return new instances at every call
> - There are convenience methods to register "global" ExecuteListeners,
> which are wrapped in a DefaultExecuteListenerProvider
>
> Does that wrap it up? I'll update the code on GitHub ASAP...

This is now implemented on Github master and contained in the latest
3.0.0-SNAPSHOT. I'll release 3.0.0-RC3 today.

Last-minute feedback before RC3 is welcome ;-)
If not, I think the current ExecuteListenerProvider will more or less
match your expectations. It is indeed a good solution to allow for
injecting stateless / stateful ExecuteListeners into jOOQ without jOOQ
noticing.

>>> I don't think that we need the additional complexity by adding
>>> the possibility of creating "per-Executor" setups.
>>
>>
>> By-the-way, I agree to that, I just mentioned it to cover all cases from
>> global to specific.
>
> Finally one less open topic! :-)
>
>>> If you feel that there is still a missing piece as I might not have
>>> gotten the full picture yet (e.g. contracts too loose, additional
>>> lifecycle for DSLContext), feel free to continue this discussion.
>>
>>
>> I wonder whether we understand each other, because you say:
>> - Loose contracts allow more flexibility.
>> - Hard contracts make them hard to implement.
>> which is in opposition with what I say:
>> - Hard contracts do not restrict flexibility.
>> - Hard contracts remove ambiguity: any tool/developer knows how to
>> use/implement without mistakes.
>> - Loose contract lead to API misuse, bugs and potential bureaucracy.
>
> I don't agree with all of this, as you know :-)
> Besides, jOOQ really doesn't need any harder contract on the
> ConnectionProvider. The jOOQ Console may need it, but I won't consider
> the Console as a driving force for core contracts.

-- 
You received this message because you are subscribed to the Google Groups "jOOQ 
User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to