My web application runs on Tomcat 7.0 and uses Spring 3.2, Hibernate 4.3 and Oracle Database.
The entityManagerFactory is configured as org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean and the transactionManager is org.springframework.orm.jpa.JpaTransactionManager. The dataSource is defined as org.springframework.jndi.JndiObjectFactoryBean and internally refers to a connection pool of type org.apache.tomcat.jdbc.pool.DataSourceFactory.
Each time when a connection is fetched from the pool by the entityManager, I'd like to execute a custom sql statement in that connection. It will only change a property in the Oracle session context, like so:
dbms_session.set_context(context, propName, propValue);
So no dml is done.
Each time when a connection is released back to the pool, a similar statement should be executed to clear the property value.
The property value should be fetched dynamically from the spring-security context, so I can't hardcode this into a connection test statement.
I've also looked into Hibernate interceptors, but I've found no way to execute any sql in the same session from within an interceptor.
Any ideas?
Related
I'm making use of Oracle Weblogic's (12.1.3) JNDI datasource for connection pooling. The max idle time for a connection is set to 30 seconds in the admin console. But, there is this method that takes more than a minute to complete, which results in the connection getting automatically closed.
My problem is that I have set autoCommit as false, and I'm unable to rollback the transaction in case of an Exception. I'm making use of pure JDBC. I tried using Spring's JdbcTemplate, surprisingly there is no Connection related issue when I'm making use of the #Transactional annotation.
Is there a technique using which I can keep the connections that I get from the Weblogic's JNDI datasource alive for more than 30 seconds, without modifying the configurations in the admin console?
I am executing SQLs via following code statement.
Application server is weblogic 12c
and Spring 3.1.1 API is used.
getJdbcTemplate().execute()...
I am wondering if getJdbcTemplate() returns DB connection itself or a reference to connection pool hosted at weblogic.
And if connection is closed after sql is executed?
If you define the datasource on Weblogic level and you reference that via a JNDI lookup in your spring configuration ==> will return a connection from the pool it was configured on Weblogic.
However with Spring you can configure your own pool without using Weblogic's one.
So depends on how you use it.
Cheers.
I'm not certain how to get a DataSource object. I was able to use the DriverManager method to obtain a connection to a SQL database running on localhost, but every time I try to use the DataSource method to do so I wind up getting exceptions (mostly for naming).
What I was wondering is:
Is it possible to get a DataSource object for local hosted databases?
Does the DataSource class need to be published, or is it like DriverManager where you just get a connection with no new class creation?
Could you show an example?
A DataSource allows getting a JDBC connection mostly from a pool of connections. A DataSource object represents a particular DBMS or some other data source, such as a file. If a company uses more than one data source, it will deploy a separate DataSource object for each of them. The DataSource interface is implemented by a driver vendor. You externalize DB connection properties file and fetch the object using JNDI. Using a Datasource you need to know only the JNDI name. The Application server cares about the details.
It can be implemented in three different ways:
A basic DataSource implementation produces standard Connection objects that are not pooled or used in a distributed transaction.
A DataSource implementation that supports connection pooling produces Connection objects that participate in connection pooling, that is, connections that can be recycled.
A DataSource implementation that supports distributed transactions produces Connection objects that can be used in a distributed transaction, that is, a transaction that accesses two or more DBMS servers.
Like, in Spring, you can configure the datasource in an XML file and then (1) either inject it into your bean, (2) get it from ApplicationContext.
DataSource ds = (DataSource) ApplicationContextProvider.
getApplicationContext().getBean("myDataSource");
Connection c = ds.getConnection();
Suggested Reading:
Connecting with DataSource Objects
Why do we use a DataSource instead of a DriverManager?
Data access with JDBC
How to retrieve DB connection using DataSource without JNDI?
Best way to manage DB connections without JNDI
Is it possible to use a single Transaction boundary for Hibernate Session and a plain JDBC query. ?
The database and the datasource configurations are similar for both.
Yes. Use HibernateTransactionManager. Below is taken from its javadoc
This implementation is appropriate for applications that solely use
Hibernate for transactional data access, but it also supports direct
data source access within a transaction (i.e. plain JDBC code working
with the same DataSource). This allows for mixing services that access
Hibernate (including transactional caching) and services that use
plain JDBC (without being aware of Hibernate)! Application code needs
to stick to the same simple Connection lookup pattern as with
DataSourceTransactionManager (i.e. DataSourceUtils.getConnection or
going through a TransactionAwareDataSourceProxy).
Note that to be able to register a DataSource's Connection for plain
JDBC code, this instance needs to be aware of the DataSource (see
setDataSource). The given DataSource should obviously match the one
used by the given SessionFactory. To achieve this, configure both to
the same JNDI DataSource, or preferably create the SessionFactory with
LocalSessionFactoryBean and a local DataSource (which will be
autodetected by this transaction manager).
we use Weblogic server and always set autoCommit to 'false' when getting Connection to Oracle 10g.
I want to know if there is a setting in Weblogic wherein it will automatically Commit transactions if a Commit or Rollback is not explicitly called from within application code. I heard similar setting exists in Websphere.
It looks like you are not using either Container-managed or Bean-managed transactions. Or, for that matter, you are merely retrieving a connection from a DataSource and then disabling autocommit, without the initial establishment a transaction context; this implies that you are using JDBC transactions (that rely on the transaction manager of the underlying database).
When you use Container or Bean managed transactions, you will no longer have to worry about the autocommit property of a Connection used in a transaction, as the container will ensure that the autocommit property is set to false, before returning the Connection to the application.
If you need to use Container-managed transactions, you'll need to use EJBs. Any transaction associated with an EJB will commit automatically, unless a RuntimeException or an ApplicationException is thrown.
If you need to use Bean-managed or programmatic transactions, you will have to use the UserTransaction API.
If you are using an ORM framework like Hibernate that is responsible for establishing connections, then you ought to remember that it is Hibernate that is responsible for switching off the autocommit property of the Connection. and in most cases, it would switch off the property.
If you intend to use JDBC transactions, despite the better alternative of JTA transactions, then you could attempt to set the defaultAutoCommit property for the driver, from either Admin Console, or in the JDBC configuration file of the Datasource. The snippet of the JDBC configuration file is shown below:
<?xml version='1.0' encoding='UTF-8'?>
<jdbc-data-source xmlns="http://xmlns.oracle.com/weblogic/jdbc-data-source" xmlns:sec="http://xmlns.oracle.com/weblogic/security" xmlns:wls="http://xmlns.oracle.com/weblogic/security/wls" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/weblogic/jdbc-data-source http://xmlns.oracle.com/weblogic/jdbc-data-source/1.0/jdbc-data-source.xsd">
<name>JDBC Data Source-Oracle</name>
<jdbc-driver-params>
<url>jdbc:oracle:thin:#localhost:1521:oracle</url>
<driver-name>oracle.jdbc.OracleDriver</driver-name>
<properties>
<property>
<name>user</name>
<value>app</value>
</property>
<!-- Disable autocommit for connections-->
<property>
<name>defaultAutoCommit</name>
<value>false</value>
</property>
</properties>
...
In the Administration Console, you may add the defaultAutoCommit=false property in the Properties textarea of the DataSource configuration:
The connections configured inside of a connection pool on the App Server are not really closed when you call the connection.close() method, they are actually returned back to the connection pool, and can be used by the next requesting object. Not sure if the DataSource connection pools will track if there are uncommitted changes on a connection being returned to the pool and perform an auto commit or rollback on it?
Setting autoCommit to false is the right thing to do.
All RDBMS that I know of commit the transaction at the end unless explicitly rolled back. Do you see a different behavior? If you suspect something is wrong, one option is to turn on logging in the database server, where you would be able to see the commit request. I am afraid I don't know how to do it in Oracle.
Logging in app server may not be useful because it too may not be issuing explicit commit