I'm trying to use JOOQ to dynamically create some statements once and store them, and then as needed attach them to a connection and bind parameters to them and execute them. In my initial development this seems to be working, and JOOQ has been a great help. At first I was unsure JOOQ was going to give me much value in this particular case, as the table and field names to be used were coming in dynamically and so I was not using the generated classes. (It may be a slightly odd use case, I'll spare you the details!) But then I ran into datatype issues in binding values and formatting result data and found that introspecting the generated classes to get datatypes solved my problems.
Making this work so far has been all well and good, however, in refactoring my proof-of-concept code to really separate the storing and usage of Queries, it occurs to me that seems to be no way to detach queries when I am done with them. I'm not sure this is a pragmatic concern, perhaps it is just aesthetic. I kind of expect the semantics to be consistent and leaving a Query hanging around still attached between uses just seems wrong.
And I've realized a pragmatic concern that sort of relates, but is bigger than the attachment issue. What about thread safety? Conceptually I would think I ought to be able to use a constructed representation of a sql statement in multiple threads with different connections simultaneously, but since bind and attach are state-changing operations on the query, surely this ins't the case and I need to rethink by design around saving queries. I suppose I can render the SQL and save that and then instantiate a new Query every time I want to use it. I wonder about the performance cost of doing this, but even that aside this seems...ugly.
I guess that brings me not much to a question as a suggestion that perhaps JOOQ API's separation of SQL statement construction and execution is incomplete and could (should, even) be taken a step further.
Or am I looking at some of the parts of the API in the wrong way conceptually? (Conceptually this is how I'm looking at it: I see SQL building objects...or objects representing built-SQL, do not need to be and ought not have any state related to execution-specific things like connection attachment or parameter binding and as such inherently ought to be able to be thread-safe with regard to execution, though perhaps not with regard to SQL building which could change state approrpiate for them to carry, i.e. state representing what SQL they equate to.)
Is there some different way of doing this that I am missing? Such as if there were a means of cloning a Query...?
After writing all that, I think I've spotted the answer to both my questions. I hadn't realized that bind() returns another ResultQuery. In my proof-of-concept code I was attaching and binding my DSL-constructed query object and executing that directly. Now I see that I can get a new ResultQuery from the bind, and attach and execute that, leaving the original query object unattached (though not unbound it seems...which seems a little wonky to me). The new ResultQuery will go out of scope which I suppose is a way of "detaching" it. From running in a debugger it looks to me like this new ResultQuery is indeed a separate object from the original query object and so I assume I should have no thread-safety concerns if always create a new ResultQuery with bind and use that. Is that all correct?
Is bind() essentially doing query object "cloning"?
I still wonder if it wouldn't be nicer to have some API distinction between stateful statement building objects and immutable objects obtainable from them representing sql statements (or parts) that you have built. Perhaps this is overly idealistic to expect this in conjunction with a fluent DSL style API.
Hello,
2013/9/6 Eric Schwarzenbach <ericjs...@gmail.com>I'm trying to use JOOQ to dynamically create some statements once and store them, and then as needed attach them to a connection and bind parameters to them and execute them. In my initial development this seems to be working, and JOOQ has been a great help. At first I was unsure JOOQ was going to give me much value in this particular case, as the table and field names to be used were coming in dynamically and so I was not using the generated classes. (It may be a slightly odd use case, I'll spare you the details!) But then I ran into datatype issues in binding values and formatting result data and found that introspecting the generated classes to get datatypes solved my problems.
Making this work so far has been all well and good, however, in refactoring my proof-of-concept code to really separate the storing and usage of Queries, it occurs to me that seems to be no way to detach queries when I am done with them. I'm not sure this is a pragmatic concern, perhaps it is just aesthetic. I kind of expect the semantics to be consistent and leaving a Query hanging around still attached between uses just seems wrong.
Your concern is not "just aesthetic". In your use case, you should probably detach queries again. This is illustrated in DefaultDSLContext.fetch(ResultQuery):
@Overridepublic <R extends Record> Result<R> fetch(ResultQuery<R> query) {final Configuration previous = Utils.getConfiguration(query);try {query.attach(configuration);return query.fetch();}finally {query.attach(previous);}}
Hi Lukas,
Thanks for your replies. I just want to say that your openness to talking about consider improvements to your API is very refreshing, and an all too rare thing in the software world.
I would swear that when I stepped over my bind() call in the debugger I saw a different object returned than the query on which I executed it. I must have misinterpreted something.
I'm happy to hear that some of these issues may be addressed in a JOOQ 4, and that there is a way to detach queries. Let me just make sure I'm interpreting your replies correctly around query objects and thread safety. It looks like my options are:
1) don't hold onto a query object, rebuild the query object each time I execute it
2) build it once, extract the sql and hold onto that instead of the query object, and when I want to execute it, instantiate new query object, using DSLContext.resultQuery (in my "select" cases, at least)
3) hold onto the query object and synchronize the lines where I attach, bind, and execute (probably not really desirable but just listing it for completeness)
Is that right or are there other options I missed?
DSL.using(...).select().from(...).fetch();
DSL.using(...).fetch(select().from(...))
DSL.using(...).run(new Runnable() {public void run() {
// These methods pull a Configuration from a ThreadLocal
select().from(...).fetch();insertInto().values(...).execute();}});
DSL.using(...).run(() -> {
// These methods pull a Configuration from a ThreadLocal
select().from(...).fetch();insertInto().values(...).execute();});
Hmm, I wonder though, if jOOQ should maintain a ThreadLocal somewhere, referencing the Configuration for query / routine execution, instead of attaching things... This would result in the following use-cases:
. . .
. . .
... Or you can pool query objects to add thread-safety to them, externally. For instance, using Apache Commons Pool:
2) build it once, extract the sql and hold onto that instead of the query object, and when I want to execute it, instantiate new query object, using DSLContext.resultQuery (in my "select" cases, at least)Yes, you can do that. Others have successfully used jOOQ as a SQL builder only, and executed the statements through Spring JDBC / JdbcTemplate for instance. See also:I personally recommend:a) profiling to see if there is a significant performance gain in choosing that approach (I'd be interested in results!)
b) carefully assessing if you will then still profit from enough jOOQ features. For instance, some type information may be lost when you operate on Strings only.
On Sunday, September 8, 2013 6:34:57 AM UTC-4, Lukas Eder wrote:. . .... Or you can pool query objects to add thread-safety to them, externally. For instance, using Apache Commons Pool:
Yeah I considered listing pooling as another option, but adding a complex runtime mechanism like that as a workaround for a scoping issue feels very wrong to me.
2) build it once, extract the sql and hold onto that instead of the query object, and when I want to execute it, instantiate new query object, using DSLContext.resultQuery (in my "select" cases, at least)Yes, you can do that. Others have successfully used jOOQ as a SQL builder only, and executed the statements through Spring JDBC / JdbcTemplate for instance. See also:I personally recommend:a) profiling to see if there is a significant performance gain in choosing that approach (I'd be interested in results!)
Some simple timings show the query object reconstruction from the sql to be pretty insignificant. I was logging some timings using System.currentTimeMillis() and it was basically not measurable that way (always 0). Switching to System.nanoTime(), my simple test ended up being around 7,000-8,000ns for the reconstruction, vs the 2,500,000 - 3,000,000 for the execution and very simple rendering of the result. This is a very simple query, though.
b) carefully assessing if you will then still profit from enough jOOQ features. For instance, some type information may be lost when you operate on Strings only.
I haven't yet done any comparisons vs executing the sql via JDBC directly, and am undecided on the tradeoff in functionality. I do find the JOOQ datatype handling functionality to be handy, may just stick with it for that, with the idea that I can always change my code to jdbc execution if it becomes a concern (which I think is unlikely), and that some future JOOQ changes may make query object reconstruction unecessary anyway. FWIW, below is what my proof of concept code looks like at the moment (extracted from my class / method structure for simplicity):
Query construction code, executed once during initialization (keep in mind that the tableName, schemaName, and the column name used for the key field are determined at runtime. The jooq generated classes cannot be used directly, and are only used via reflection for column datatypes) :
org.jooq.TableField keyFieldDef = ...// use Java reflection to get TableField from the jooq generated classes,
// from a dynamically sourced column name
DataType keyDataType = tf.getDataType();
Param param = DSL.param("key", keyDataType);
Condition keyCondition = keyFieldDef.equal(param);
ResultQuery<Record> query = DSL.select(getFields(tableName, true)).from(DSL.tableByName(schemaName, tableName))
.where(keyCondition);
String sql = query.getSQL();
What gets saved in member variables between query executions is only sql, and keyDataType.
At execution time (code that may be run by multiple threads)DSLContext create = DSL.using(dataSource, SQLDialect.POSTGRES);
Param param = DSL.param("key", keyDataType);
ResultQuery<Record> resultQuery = create.resultQuery(sql, param);
resultQuery.bind("key", keyValue);
Result<Record> result = resultQuery.fetch();
I left out the java reflection bit, but can provide that if it's useful to anybody. (I did mean to ask if there is a way to get data type information from the jooq-generated classes without using reflection...that would be handy, too, but mine may be an unusual usecase.)
I'm not sure I entirely get it. How exactly does the connection / threadlocal mechanism in use case 2 operate? Would it try to get the ThreadLocal Configuration, and if it didn't exist, use / create a Configuration (with connection) from the using() arguments, and if it did exist, just ignore the using() arguments and use the ThreadLocal Configuration instead?
And does this mean if the query object passed into the fetch() (in your example "select().from(...)") is now thread safe and a single copy can be used in multiple threads?
using(configuration).bind(Query).bind(... bindings ...).fetch();
2013/9/9 Eric Schwarzenbach <ericjs...@gmail.com>
On Sunday, September 8, 2013 6:34:57 AM UTC-4, Lukas Eder wrote:b) carefully assessing if you will then still profit from enough jOOQ features. For instance, some type information may be lost when you operate on Strings only.
I haven't yet done any comparisons vs executing the sql via JDBC directly, and am undecided on the tradeoff in functionality. I do find the JOOQ datatype handling functionality to be handy, may just stick with it for that, with the idea that I can always change my code to jdbc execution if it becomes a concern (which I think is unlikely), and that some future JOOQ changes may make query object reconstruction unecessary anyway. FWIW, below is what my proof of concept code looks like at the moment (extracted from my class / method structure for simplicity):
Query construction code, executed once during initialization (keep in mind that the tableName, schemaName, and the column name used for the key field are determined at runtime. The jooq generated classes cannot be used directly, and are only used via reflection for column datatypes) :Interesting approach :-) I think that this reflection might account for more overhead than the actual query construction. I guess a lookup Map<String, TableField> initialised at application startup might also do the trick...?
org.jooq.TableField keyFieldDef = ...// use Java reflection to get TableField from the jooq generated classes,
// from a dynamically sourced column name
DataType keyDataType = tf.getDataType();
Param param = DSL.param("key", keyDataType);
Condition keyCondition = keyFieldDef.equal(param);
ResultQuery<Record> query = DSL.select(getFields(tableName, true)).from(DSL.tableByName(schemaName, tableName))
.where(keyCondition);
String sql = query.getSQL();
What gets saved in member variables between query executions is only sql, and keyDataType.
At execution time (code that may be run by multiple threads)DSLContext create = DSL.using(dataSource, SQLDialect.POSTGRES);
Param param = DSL.param("key", keyDataType);
ResultQuery<Record> resultQuery = create.resultQuery(sql, param);
resultQuery.bind("key", keyValue);
Result<Record> result = resultQuery.fetch();
Note that Param.setValue() exists:Or setConverted() if you may risk data type confusion:That might be a bit better than calling .bind()
I left out the java reflection bit, but can provide that if it's useful to anybody. (I did mean to ask if there is a way to get data type information from the jooq-generated classes without using reflection...that would be handy, too, but mine may be an unusual usecase.)You can traverse the generated metadata using MY_SCHEMA.getTables() and then access each table's fields
I left out the java reflection bit, but can provide that if it's useful to anybody. (I did mean to ask if there is a way to get data type information from the jooq-generated classes without using reflection...that would be handy, too, but mine may be an unusual usecase.)You can traverse the generated metadata using MY_SCHEMA.getTables() and then access each table's fields
Ah! Yes, that's what I needed. That should avoid all need for reflection except for getting the schema class based on the schema name. Unless there is some method to list the schema objects somewhere?