I have a Java method which passes a CLOB to a PL/SQL procedure using JDBC. I was able to do that using the createClob() method of the Connection class.
Here is the Java Doc for the Connection class. If you notice other than createClob() method there are also createBlob() , createArrayOf() , createNClob() methods in this class.
I am curious why the creation of instances of Blob , Clob , NClob is part of the Connection class ? It seems a bit out of place. Why should datatypes and its creation be tied to connection object ?
Why can't we create instances of these datatypes independently ? I am planning to expose this method with the following signature in a SOAP Web Services:
public String handleEmployeeReview(int empId , String fileName)
It seems little odd that a web service client would first have to create a Connection instance for creating a instance of Clob. (Unless there is another way of creating and passing Clobs that I am unaware of.)
Which also makes me wonder if my choice of Clob datatype for this method is the right one. Considering its being exposed in the web service.
JDBC is designed to be database engine independent. The database types INT, VARCHAR, TIMESTAMP, etc., could have a more common implementation into Java types: int, String, java.sql.Timestamp which extends from java.util.Date, and on.
Data types like BLOB, CLOB, NLOB are more specific fields that can be implemented very differently in database engines, some database engines don't even support arrays as data type for table columns, but still JDBC should provide a transparent interface to communicate the client code and the database engine. The designers of JDBC interfaces thought that the creation of these objects should depend on the JDBC implementation (this is, a CLOB object is database engine specific), and the best place to provide the creation of CLOB objects (and similar) would be provided by the java.sql.Connection interface, since you at least need to open a physical database connection to create an instance of such specific database engine object. IMO this is the proper interface to do it, since it allows using the same CLOB object in different PreparedStatements and CallableStatements with no problems.
The usage of Connection#createClob method and similars should be used by your dao layer only. Other datasources may use a different approach to store binary data of your files e.g. a direct byte[] that is stored in memory, for this case the datasource would be a cache system, not a direct database.
Related
I'm using Apache Derby as an in-memory mock database for unit testing some code that works with MySQL using jOOQ.
The production database uses enums for certain fields (this is a given and out of scope of this question - I know enums are bad but I can't change this part now), so jOOQ generates code to handle the enums.
Unfortunately, Derby does not support enums and when I try to create the database in Derby (from jOOQ SQL generator), I get errors.
My solution was to user-defined types that mimic the enum by wrapping the relevant jOOQ generated enum Java class. So, for example, if I have an enum field kind in the table stuffs, jOOQ SQL generator creates Derby table creation SQL that talks about stuffs_kind.
To support this I created the class my.project.tests.StuffsKindDebyEnum that wraps the jOOQ generated enum type my.project.model.StuffsKind. I then run the following SQL through Derby, before running the jOOQ database creation SQL:
CREATE TYPE stuffs_kind EXTERNAL NAME 'my.project.tests.StuffsKindDerbyEnum' LANGUAGE JAVA
When I then use jOOQ to insert new records, jOOQ generates SQL that looks somewhat like this:
insert into "schema"."stuffs" ("text", "kind")
values (cast (? as varchar(32672)), cast(? as stuffs_kind)
But binds a string value to the kind argument (as expected), and it work for MySQL but with Derby I get an exception:
java.sql.SQLDataException: An attempt was made to get a data value of type
'"APP"."STUFFS_KIND"' from a data value of type 'VARCHAR'
After looking at all kinds of ways to solve this problem (including trying to treat enums as simple VARCHARs), and before I give up on being able to test my jOOQ-using code, is there a way to get Derby to "cast" varchar into user-defined types? If could put some Java code that can handle that, it will not be a problem as I can simply do StuffsKind.valueOf(value) to convert a string to the correct enum type, but after perusing the (very minimal) Derby documentation, I can't figure out if it is even should be possible.
Any ideas are welcome!
Implementing a dialect sensitive custom data type binding:
The proper way forward here would be to use a dialect sensitive, custom data type binding:
https://www.jooq.org/doc/latest/manual/sql-building/queryparts/custom-bindings
The binding could then implement, e.g. the bind variable SQL generation as follows:
#Override
public void sql(BindingSQLContext<StuffsKindDerbyEnum> ctx) throws SQLException {
if (ctx.family() == MYSQL)
ctx.render().visit(DSL.val(ctx.convert(converter()).value()));
else if (ctx.family() == DERBY)
ctx.render()
.sql("cast(
.visit(DSL.val(ctx.convert(converter()).value()))
.sql(" as varchar(255))");
else
throw new UnsupportedOperationException("Dialect not supported: " + ctx.family());
}
You'd obviously also have to implement the other methods that tell jOOQ how to bind your variable to a JDBC PreparedStatement, or how to fetch it from a ResultSet
Avoiding the MySQL enum
Another, simpler way forward might be to avoid the vendor-specific feature and just use VARCHAR in both databases. You can still map that VARCHAR to a Java enum type using a jOOQ Converter that will work the same way in both databases.
Simplify testing by avoiding Derby
A much simpler way forward is to test your application directly on MySQL, e.g. on an in-memory docker virtualisation. There are a lot of differences between database vendors and their features, and at some point, working around those differences just to get slightly faster tests doesn't seem reasonable.
The exception is, of course, if you have to support both Derby and MySQL in production, in case of which the data type binding is again the best solution.
I've got to learn Java JDBC currently.
Today I had a look on how Stored Procedures are called from within JDBC.
What I don't get ..., when I have a Stored Procedure like for example this one:
CREATE PROCEDURE demo.get_count_for_department
(IN the_department VARCHAR(64), OUT the_count INT)
BEGIN
...
"the_count" is marked as an out parameter. Type is also specified. So this should all be known.
Nevertheless I have to specify the type again
statement.registerOutParameter(2, Types.INTEGER);
I have to put the type in there again? It seems redundant to me.
Why do I have to give two parameter in there at all?
statement = connection.prepareCall("{call get_count_for_department(?, ?)}");
I haven't seen this in any other programming language. You only have to take care for the in-parameter. For the out-parameter takes the function care itself.
Why is that different here?
Perhaps someone can drop me a few lines. So that I get a better idea about how those Stored Procedure-calls work.
The reason is that the sql statement is just a string as seen from java perspective.
The task of a JDBC driver is to send that string to the database and receive results.
You could read the stored procedure metadata to get information about the stored procedure you are about to call but that takes time and possibly multiple queries to the DB.
If you want that kind of integration you go a step up from JDBC and use some kind of utilities or framework to map DB object to java ones.
Depending on the database it might technically not be necessary. Doing this allows a JDBC driver to execute the stored procedure without first having to query the database for metadata about the statement, and it can also be used to disambiguate between multiple stored procedures with the same name (but different parameters).
I am aware of what Serialization is however I have not found any real practical example describing the latter one (saving an object in a database taking advantage of the JAVA_OBJECT mapping).
Do I have first to serialize the object and then save it to the database?
In the case of MySQL, you don't have to serialize the object first, the driver will do it for you. Just use the PreparedStatement.setObject method.
For example, first in MySQL create the table:
create table blobs (b blob);
Then in a Java program create a prepared statement, set the parameters, and execute:
PreparedStatement preps;
preps = connection.prepareStatement("insert into blobs (b) values (?)");
preps.setObject(1, new CustomObject());
preps.execute();
Don't forget that the class of the object that you want to store has to implement the Serializable interface.
Serialization is used to save the state of an object and marshall it to a stream and share it with a remote process. The other process just need to have the same class version to deserialize the stream back to an object.
The problem with the database approach is that you will need to expose the databse even to the remote process. This is generally not done due to various reasons, mainly security.
How should I work with UUID and JPA?
Should I assign the random UUID value to a String field in my class? Or should I have a field with type UUID and do something else to it when I want to map it to a column?
That depends on the database.
There are databases such as H2, MSSQL and PostgreSQL that support a uniqueidentifer type.
For these types you can extend the provided Dialect (i.e - PostgreSQLDialect) and add handling of the new type.
I implemented something like that, based on the following post , for both MSSQL and Postgresql.
For databases that do not support a uniqueidentifier/UUID type, you should use String.
This means that you should also ask yourself if your application must support multiple database vendors, or if you can stick with a single vendor (and then select the first option, if applicable).
Possibly a simple (read dumb) question. I am in design phase of a web application - standard Spring MVC and planning on using Spring DAO support (jdbctemplate - no hibernate & no ibatis etc).
I am currently modeling my data objects for the RDBMS. What is the best practise for data types? Let's say my primary key of a table is Numeric - Do I model that in my object as Long or long? Any problem / advantage of one over another?
Gurus?
Long is nullable. So an object with a null id (in Java) can represent an object that is not (yet) persisted. You can explicitly configure Hibernate to treat it that way, and if you don't use Hibernate, it's still good practice to give you DAO methods a way of finding out whether a particular object is already in the database or not.
I prefer to have a type "Identity" that is Serializable (Comparable, Clonable etc) and which String representation is used e.g. to build URLs. Only the DAO implementation knows which exact type it is. It could be Long or it could be a combined primary key. Above the Data Access layer, the application only deals with the Identity.
If the identity is null, the object is not persisted (has no identity assigned via the persistence store).