There is something I don't understand :
Is Hibernate a DB manager and not only ORM?
My question: I have SpringBootApplication and use hibernate for connection to database and ORM aspect. In my mind, connection to DB is continuous.
On another hand, I want a puncual on-demand connection to an access DB, so I used simple java.sql.* library :
Class.forName("org.hsqldb.jdbcDriver").newInstance();
Connection connection = DriverManager.getConnection("jdbc:ucanaccess://myDB.mdb", login, password);
This works but in order to not map manually each result query to a domain object, I would like to use hibernate to do :
getCurrentSession()
.createSQLQuery( "select e.id as id,e.first_name as firstName,e.password as password from xxxxxx")
.addScalar("id",StandardBasicTypes.INTEGER )
.addScalar("firstName",StandardBasicTypes.STRING )
.addScalar("password",StandardBasicTypes.STRING )
.setResultTransformer(Transformers.aliasToBean(Employee.class))
.list();
in order to have query result automatically bind to DOmain object.
BUT this is only available for hibernate library, not java.sql (or I didn't find).
SO should I have a second hibernate connection but not permanent so not configured in application.properties/hibernate.properties and so not managed by Spring (in order to have punctual connection)? In my mind, I would like to do something identical to java.sql previous example but with hibernate.
You will understand that I think I miss something about hibernate philosophy.
Thank you.
Related
All I have implemented multitenancy with mysql and hibernate but I have doubts that it will work in real world.
As per following quote from hibernate document it should be possible:
Connections could point to the database itself (using some default schema) but the Connections would be altered using the SQL SET SCHEMA (or similar) command. Using this approach, we would have a single JDBC Connection pool for use to service all tenants, but before using the Connection it would be altered to reference the schema named by the “tenant identifier” associated with the currently logged in user.
Here is the link from where I got above paragraph.
Multitenancy in hibernate
So I override the MultiTenantConnectionProvider as below
#Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
Connection tenantSpecificConnection = dataSource.getConnection();
if (!StringUtils.isEmpty(tenantIdentifier)) {
Statement statement = tenantSpecificConnection.createStatement();
statement.executeQuery("use " + tenantIdentifier);
statement.close();
tenantSpecificConnection.setSchema(tenantIdentifier);
} else {
tenantSpecificConnection.setSchema(Constants.DEFAULT);
}
return tenantSpecificConnection;
}
It is very basic iteration, a first one, I am just able to switch the database. But with this I also have questions. Would this work in real world? I think multiple users will cause trouble while using this? According to hibernate documentation it should not but it looks it may cause problems. Has anyone tried this, please need help on this one.
I'm using Spring and JDBC template to manage database access, but build the actual SQL queries using JOOQ. For instance, one DAO may look like the following:
public List<DrupalTaxonomyLocationTerm> getLocations(String value, String language) throws DataAccessException {
DSLContext ctx = DSL.using(getJdbcTemplate().getDataSource(), SQLDialect.MYSQL);
SelectQuery q = ctx.selectQuery();
q.addSelect(field("entity_id").as("id"),);
q.addFrom(table("entity").as("e"));
[...]
}
As you can see from the above, I'm building and executing queries using JOOQ. Does Spring still take care of closing the ResultSet I get back from JOOQ, or do I somehow "bypass" Spring when I access the data source directly and pass the data source on to JOOQ?
Spring doesn't do anything with the objects generated from your DataSource, i.e. Connection, PreparedStatement, ResultSet. From a Spring (or generally from a DataSource perspective), you have to do that yourself.
However, jOOQ will always:
close Connection objects obtained from a DataSource. This is documented in jOOQ's DataSourceConnectionProvider
close PreparedStatement objects right after executing them - unless you explicitly tell jOOQ to keep an open reference through Query.keepStatement()
close ResultSet objects right after consuming them through any ResultQuery.fetchXXX() method - unless you explicitly want to keep an open Cursor with ResultQuery.fetchLazy()
By design, jOOQ inverses JDBC's default behaviour of keeping all resources open and having users tediously close them explicitly. jOOQ closes all resources eagerly (which is what people do 95% of the time) and allows you to explicitly keep resources open where this is useful for performance reasons.
See this page of the jOOQ manual for differences between jOOQ and JDBC.
Currently I made a connection to a database in this way:
MyClass.java
try {
DataSource datasource = JNDILoader.getDataSourceObject(pathToSource);
Class.forName("net.sourceforge.jtds.jdbc.Driver");
connection = datasource.getConnection();
stmt = connection.prepareStatement("{call storageProcedureXXX(?,?)}");
stmt.setString(1, "X");
stmt.setString(2, "Y");
result = stmt.executeQuery();
}catch (SQLException){
//TODO
}catch(Exception){
//TODO
}
That works for 1 class that makes the requests for the data, but , would be better if I create a singleton class and get the connection from it? (performance?, maintenability?, simplicity?). Which option would be better: Singleton vs StorageProcedures per each request?.
Note: At the end, the application (Restful Web Service) will need to connect to different databases to load data for different specialized classes, even , the classes would need loads data from plain text.
First of all you are mixing two different things: singleton and stored procedures. Singleton is design pattern, and stored procedures are procedures executed on database, typically encapsulating some business logic.
What you wrote is not really preferred way of connecting to database. If you have many request and create one connection for each request son you will have problems with too many connections to database. You should use connection pool. The most famous for Java is DBCP. Another one is c3p0.
For connection on different databases you should use something like Hibernate.
Stored procedure are executed on the database. You pass/retrieve data to/from it through the connection.
You have to check if it is thread safe (I don't think so), if you'll do concurrent calls or not.
Generally a stored procedure = 1 transaction happening in the database.
Why are you using stored procedure in the 1st place?
Let's say I have an existing DataSource to a master database. I now need to create a new database, and execute some DDLs on that database. Is this possible with e.g, "USE" command, or do I need to create a new DataSource with the name of the new database in the JDBC url?
You can run the "USE" command as a regular JDBC statement.
Statement stmt = connection.createStatement();
stmt.execute("USE the_other_db");
Dependending on your DBMS and driver you might also be able to use the JDBC API call setCatalog():
connection.setCatalog("the_other_db")
The USE statement works, but since it's stateful, you have to make sure that it's part of the same connection as the latter statements.
If you use Spring's JdbcTemplate instead of working with java.sql.Connection and java.sql.Statement directly, you can use a SingleConnectionDataSource.
I need to be able to set a MySQL user variable that is used in a trigger in a Spring MVC Hibernate web ap. This user variable is used in MySQL triggers on the tables that are being manipulated by Hibernate. I need this user variable to be correctly set during all of Hibernate's write accesses to the database.
Unfortunately HQL does not have a technique for setting MySQL user variables and the method I have found for directly executing MySQL does not seem to work with the transaction. Since the user variable's life span is that of the database connection I need the MySQL to execute using the same connection that they HQL will be executed with. However my transactions seem to run the HQL after the native MySQL has been executed and thus the expected user variable is not present for the MySQL trigger.
To execute native MySQL queries I have been using:
HibernateEntityManager em=(HibernateEntityManager) getEntityManager();
Connection connection=em.getSession().connection();
Statement s = connection.createStatement();
s.executeUpdate("SET #current_user_id="+userId);
When the Spring MVC commits my transaction it runs the HQL queries and then throws an exception because the #current_user_id is causing the MySQL trigger to break. I verified this by testing without the triggers present.
I found this SO question that is very similar to mine: How to use Mysql variables with Hibernate?
So I followed the suggestion and used a stored procedure and the executeNativeQuery method on the entity manager to call it.
Here is my stored procedure code:
DROP PROCEDURE IF EXISTS set_current_user
CREATE PROCEDURE set_current_user(IN user_id BIGINT)
BEGIN
SET #current_user_id = user_id
END
And I call it with:
Query q = em.createNativeQuery("CALL set_current_user("+userId+")");
q.executeUpdate();