We have an app that is using hibernate, spring, and DB2 in websphere 7. We have audit triggers and we need to set so the triggers can know the logged in user (we use generic logon to the database). We came up with a new scheme for setting this in a new app so that it can automatically join in new transactions. We overrode the transaction manager and did the work in the doBegin.
These scheme worked great in one app, and seemed to work great in a second app, but now, weeks later, and not consistently (behavior is intermittent and does not happen in local development), we are getting this Pre-bound JDBC Connection found error. Looking online most posts say this is when you use two transaction managers against one data source. That is now what we are doing.
I also read one post wondering if it was because he mixed annotation and AOP based transactions. This app does some of that. I don't really buy that theory, but thought I'd mention it.
Exception:
Caused by:
org.springframework.transaction.IllegalTransactionStateException: Pre-bound JDBC Connection found! HibernateTransactionManager does not support running within DataSourceTransactionManager if told to manage the DataSource itself. It is recommended to use a single HibernateTransactionManager for all transactions on a single DataSource, no matter whether Hibernate or JDBC access.
at java.lang.Throwable.<init>(Throwable.java:67)
at org.springframework.core.NestedRuntimeException.<init>(NestedRuntimeException.java:54)
at org.springframework.transaction.TransactionException.<init>(TransactionException.java:34)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:475)
at gov.usdoj.afms.umc.utils.hibernate.AfmsHibernateTransactionManager.doBegin(AfmsHibernateTransactionManager.java:28)
Code (note that the exception comes from the super.doBegin()):
protected void doBegin(Object arg0, TransactionDefinition arg1) {
super.doBegin(arg0, arg1);
if (!Db2ClientInfo.exists()) {
clearDBProperty();
} else {
setDBProperty(Db2ClientInfo.getClientUserId(), Db2ClientInfo.getClientApplicationId());
}
}
private void setDBProperty(String uId, String appName) {
Session session = getSessionFactory().getCurrentSession();
Properties props = new Properties();
props.setProperty(WSConnection.CLIENT_ID, uId);
props.setProperty(WSConnection.CLIENT_APPLICATION_NAME, appName);
try {
Connection nativeConn = new SimpleNativeJdbcExtractor().getNativeConnection(session.connection());
if (nativeConn instanceof WSConnection) {
WSConnection wconn = (WSConnection) nativeConn;
wconn.setClientInformation(props);
} else {
logger.error("Connection was NOT an instance of WSConnection so client ID and app could not be set");
}
} catch (Exception e) {
throw new RuntimeException("Cannot set DB parameters!", e);
}
}
I just realized I never answered this. It turns out that the exception had nothing whatever to do with our Tx manager. It was the fact that this particular EAR has two apps in it, each pointing to the same data source. Evidently this confuses hibernate. We've plans to separate the apps some day, but creating an identical (except in name) data source and pointing the apps at them separately fixes the issue for now.
Instead of modifying the transaction manager it might be easier (better?) to create a wrapper around your datasource (extending DelegatingDataSource from spring) and override the 2 getConnection methods. For the cleanup you could wrap the connection in a proxy and intercept the close method.
That should be a safer (and easier I guess) way then trying to fiddle with the transaction manager and it works for every technology (JDBC, Hibernate, JPA etc.) as long as you use the wrapped datasource. (The registration could be done with a BeanPostProcessor which detects DataSource instances and simply wraps them in the delegate).
If that is to radical (as it means changing your current applications instead of updating a library). It could be a configuration problem, make sure that you are only loading your configuration (and thus DataSource and TransactionManager) only once, duplicating bean instances might lead to a similair behavior.
For posterity, I just got this problem and the answers here weren't very helpful. We resolved the problem by removing a double import of a core XML file which had the AOP transaction manager definition in it:
<tx:annotation-driven transaction-manager="..."
proxy-target-class="true" />
I'm thinking that it causes there to be 2 transaction managers overlapping the same namespace. To fix it, we moved the imports around so they were being done once.
Hope this helps someone else.
Related
I am working on spring boot and batch application.
Due to batch, the application tries to connect to datasource
with spring-boot:run.
I want to stop that and tried spring.datasource.initialize=false
Along with this also put spring.batch.job.enabled=false
While the second one works fine, it seems the first one is ignored.
Could someone let me know if there is a way to stop db connection on startup?
Thanks in advance
The problem is, that spring/spring-boot loads the whole spring-context when it is "booted". This means, that all defined spring-beans are loaded into the spring-context during this boot-phase. In the case of spring-batch, this also means that the datasource bean is loaded and, if not turned off by "spring.batch.initializer.enabled=false", the spring-batch tables are initialized.
Generally, you cannot prevent this from happening as soon as you have added your spring-batch-starter to your maven dependencies.
Moreover, I don't understand why you want to prevent this from happening. It is just initialisation taking place and, provided that everything is configured correctly, this shouldn't be a problem at all.
Nonetheless, if you really want to stop the datasource from beeing initialized, you could try the following approach. However, I don't know if this will work.
Spring-Batch needs a datasource that is registered under the name "dataSource" in the spring-context. If no spring-bean with that name is found, it creates its own. But if you provide your own implementation/configuration for it, it will use your spring bean.
What you need to do is, to provide a proxy for a datasource that is loaded lazily and then register it under the name "dataSource" in the context:
#Configuration
public class MySetUp {
#Bean
public DataSource dataSource() {
// ... create your "lazy initializing" datasource
}
}
But - and let me stress that - this nothing that I would recommend and I don't see a good reason, why this should be necessary to do.
Furthermore, you mention that you only want load "initial static index page" (I assume, you are talking about html, right?). However, I don't see a "batch" use case, which should display html-pages. It would probably be better to have two different applications in this case.
Probably you could provide some more information about your use case.
As I understand, you don't want to prevent database connection during application startup.
Instead, you want to prevent execution of batch scripts.
Correct me, please, if I got it wrong.
To prevent execution of batch scripts set:
spring.batch.initializer.enabled=false
I am fetching the connection in jdbctemplate in below fashion:-
getJdbcTemplate().getDataSource().getConnection()
Is it necessary to close the connection fetched in the above manner? The spring JDBCTemplate API states that connection closures will be handled automatically , so I am not sure if this is happening correctly.
http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/jdbc.html
When you are obtaining the DataSource from the JdbcTemplate and use that to obtain a Connection you are basically completely bypassing the JdbcTemplate. You now have a very complex way of obtaining a new Connection. Because this connection isn't managed by Spring but yourself you also need to close it and apply exception handling.
It is better to use the ConnectionCallback instead to get a Connection. The JdbcTemplate will then manage the Connection and do all resource handling.
getJdbcTemplate().execute(new ConnectionCallback<Void>() {
public Void doInConnection(Connection conn) {
// Your JDBC code here.
}
});
It would even better to use one of the other JdbcTemplate methods and write proper code which would save you from messing with plain JDBC code at all.
I am trying to find a way to make sure custom resources like files that are created within a transaction (using #Transactional) are cleaned up in case that transaction rolls back. I tried implementing a custom TransactionManager but could not find a way to register it but I do know for example spring-rabbitmq has its own transaction manager that taps into the existing transactions. Any ideas how to solve this?
Not sure that I got you correctly, but according to tag name you are using spring.
You can handle it via Spring AOP.
You should just create your own annotation(e.g. YourOwnTransactional) , and check it.
If annotation exists, you can just call like :
#Around(#anyPublicMethod() && #annotation(YourOwnTransactional))
public void aroundAddAdvice(ProceedingJoinPoint pjp){
try{
pjp.proceed();
}catch(YourException e){
//rollback
}
}
edited.
We are using declarative spring transaction attribute for database integrity. Some of our code call webservice which do bunch of stuffs in sharepoint. The problem is when webservices take longer time users get deadlock from spring which is holding up backend.
If I make a new thread inside a function which has spring transaction declarative attribute will that be ignored from spring?
[Transaction(TransactionPropagation.Required, ReadOnly = false)]
public void UploadPDFManual(/*parameters*/)
{
//DO some data base related things
if (revisionPDFBytes != null)
{
//my sharepoint call which calls webservice
Task.Factory.StartNew(() => DocumentRepositoryUtil.CreateSharepointDocument(docInfo)); // I draw a new thread from ASPNET worker thread pool.
}
}
Anything other options I should go for?
You don't need doing it in a transaction. Transaction makes a database save an object properly. That's it. All other stuff must be done after the transaction commit. In Java, you can make it with Spring's transaction synchronization or JMS. Take a look at the accepted answer over here.
More useful info specific for .NET (see 17.8).
I have mybatis 3.0.4 with mybatis-spring integration 1.0.1 deployed within Fuse (OSGi). I've created a basic database within SQLServer 2008. In Spring I've configured a TransactionAwareDataSourceProxy data source and a DataSourceTransactionManager transaction manager.
Now I've created my own bundle to be deployed within Fuse which inserts some rows into the database. I've told the bundle to use the configured data source and transaction manager. The method which carries out the logic looks like this:
#Transactional(propagation=Propagation.REQUIRED)
public void go(RecsCashContext context) throws ActionException {
When this method throws an exception I can follow Spring through seeing the expected behaviour triggered. This leads me to Springs JtaTransactionManager and doRollBack(..).
So everything looks promising, except that when I look at the database, sure enough it's in an unstable state as previous inserts have not been roll back.
I'm at a loss on this one and I'm struggling to find any information online. Any thoughts?
What kind of exception is being thrown? Unless you tell Spring to explicitly rollback when a particular exception is thrown, it will proceed. By default, Spring's transaction handling only rolls back when an unchecked exception (e.g. RuntimeException) is thrown. In your case, if you're expecting the rollback to occur when ActionException occurs, you're out of luck unless you make the following modification:
#Transactional(rollbackFor={ActionException.class})
public void go(RecsCashContext context) throws ActionException {
More details are in here, specifically in section 10.5.6.1, #Transactional settings
As it turns out Fuse (servicemix) already exposes a transaction manager via an OSGi service within bundle org.apache.aries.transaction.manager_0.2.0.incubating [49]. As a result when I was looking up the transaction manager service, the one exposed by bundle 49 got picked up first.
This was resolved by clearly specifying the transaction manager I was interested in. At the moment I am doing this using the bean-name propery:
<osgi:reference id="transactionManager" bean-name="transactionManager" interface="org.springframework.transaction.PlatformTransactionManager" />
Though this could also be done by using a filter, but preferably we'll just make use of the transaction manager service that's already being expose as opposed to providing our own.