Somebody knows an example with EJB3 and Mybatis where the container controls the transaction, the only part of code I founded was:
SQLMapConfig.xml
<transactionManager type="EXTERNAL">
<property name="SetAutoCommitAllowed" value="false"/>
<dataSource type="JNDI">
<property name="DataSource" value="java:comp/env/jdbc/sisds"/>
</dataSource>
</transactionManager>
But I have many questions, for example,
When the container make the commit?
When the container release the session to the pool?
Thanks in Advance
The container commits the transaction based on how your EJBs are configured. If you are using bean managed transactions, then you have to manage the UserTransaction yourself.
Regardless, you have to manage the MyBatis SqlSession yourself. Setting the tx type to EXTERNAL (MANAGED in Mybatis 3), simply means that MyBatis never calls commit on the DB connection - it relies on the container to commit.
Related
My app is made of a Spring rest controller calling a service using redis.
I am using spring boot starter redis 1.2.5 and I have defined a template in my beans.xml file:
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="${spring.redis.host}"
p:use-pool="true"
p:port="${spring.redis.port}"
/>
<bean id="redisTemplateForTransaction" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnectionFactory"
p:keySerializer-ref="stringRedisSerializer"
p:valueSerializer-ref="jsonRedisSerializerForTransaction"
p:enableTransactionSupport="true">
<qualifier value="redisTemplateForTransaction" />
</bean>
When I launch more than 8 queries my app blocks. I understand I have reached the default number of connections in the pool.
Why aren't the connections returned automatically at the end of the request processing ?
How to work in a transactional mode so that any incoming request will get its redis connection and return it at the end of the processing ?
You need to enable transaction management for your application by providing a PlatformTransactionManager bean.
The easiest way to do so is adding #EnableTransactionManagement to your Spring Boot application. If that's not possible, configure a PlatformTransactionManager bean. Reusing an existing DataSourceTransactionManager is the easiest way. If you do not use a JDBC-compliant database, simply drop in a H2 in-memory database.
If you want to use a JTA transaction manager, see this blog post: https://spring.io/blog/2011/08/15/configuring-spring-and-jta-without-full-java-ee/
HTH, Mark
I have implemeted a web application using Struts2 and Hibernate 4.3.5
I am facing some problems and need some clarification on some connection pooling properties.
To make connection pooling with hibernate I have used c3p0-0.9.1.jar
Below are the connection pooling Properties of c3p0 in hibernate.cfg.xml
<!-- Connection Pooling using c3p0 -->
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.timeout">500</property>
<property name="hibernate.c3p0.max_statements">2</property>// I heard somewhere that this property improves performance.. But dont know How it improves
<property name="hibernate.c3p0.idle_test_period">300</property>
<property name="hibernate.c3p0.preferredTestQuery">
select sysdate from dual;
</property>
In my application I have used * session-per-request* patterns by setting following property in hibernte-cfg.xml
<!-- To open the connection when the request hits. -->
<property name="hibernate.current_session_context_class">thread</property>
When I use this I am getting Session as following
//Here MyHiberantaeUtil is my own class having singleton pattern and Static block
// To read hibernate-cfg.xml and will create SessionFactroy object.
SessionFactory sessionFactory = MyHibernateUtil.getSessionFactory();
Session session = sessionFactory.getCurrentSession();
As per the documentation .. When I use this pattern connection should be created when request is requested and should be closed when request completed.
For my case Its creating connection .. i.e I can get Session Using this getCurrentSession() But its not closing when The request ended.
To test connection pooling I have used jconsole tool in my jdk
Where I can see
`numBusyConection = 2(If that is two requests.)`
I would like to know is there any thing I missed . Why thread property is not working as expected ?
And how to say that Request has completed and request has generated ?
Is session-per-request is best pattern or better to go any other patterns ?
I did not find this class `org.hibernate.connection.C3P0ConnectionProvider` in any jar files.. But My application is connecting to DB and working fine.
Please help thanks in advance.
The JDBC connection is opened when first needed and closed when the Session is closed. You need to manually close the session when you go out of your Service layer:
session.close();
Otherwise the connections won't be closed and you'll starve the connection pool.
It's a better idea to use Spring, because it has support for automatically creating/closing sessions for you. Your MyHibernateUtil is no match for what Spring has to offer:
local transactions
global transactions
transaction annotations and automatic commit on success or rollback on runtime exceptions
Setting up Spring with Hibernate is as easy as using the HibernateUtil class.
This might be a repetitive question for you, but I couldn't find (atleast I couldn't understand) a satisfactory answer, hence asking again.
I am working with two data sources (MySQL and Oracle). Following is a flow of execution:
Main method-A calls method-B (Which writes into Oracle DB) then it(Method-A) calls method-C (Which writes into mySQL DB) then it(Method-A) calls method-D(Which writes into Oracle DB).
If failure occurs at any of place, everything should be rolled back. Currently only changes in Oracle DB are getting rolled back & mySQL DB is not getting rolled back.
I have defined two transactional managers.
=========> First <=========
<tx:annotation-driven transaction-manager="txManager" mode='proxy' proxy-target-class='true’/>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="SessionFactory" />
</bean>
<bean id=“SessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean” parent="AbstractSessionFactory" depends-on="AppConfigHelper”>
<property name="hibernateProperties”>
...
ORACLE DB Properties
</property>
</bean>
<aop:aspectj-autoproxy/>
==============================
=========> Second <=========
<tx:annotation-driven transaction-manager="txManager2" mode='proxy' proxy-target-class='true'/>
<bean id="txManager2" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="SessionFactory2" />
<qualifier value="CherryTransaction" />
</bean>
<aop:aspectj-autoproxy/>
<bean id="SessionFactory2" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" parent="AbstractSessionFactory2" depends-on="AppConfigHelper">
<property name="hibernateProperties">
...
MYSQL DB Properties
</property>
</bean>
==============================
On top of method-A I have used #Transactional annotation
On top of method-B I have used #Transactional annotation
On top of method-C I have used #Transactional("txManager2")
annotation
On top of method-D I have used #Transactional annotation
Question Is:
Why is MySQL changes are not getting rolled back?
Is the only way to get this working is to use Global transaction management using JTA? (Its a legacy system, and this is the only place where I need to interact with two DBs)
Can you please point me to an example / tutorial where this kind case is handled?
Sincerely thanks for reading this!
For that to work, AFAIK you'd need to use JTA. Even that won't help if you're using a storage engine in MySQL that doesn't support transactions. With MySQL, only InnoDB and BDB storage engines support transactions.
If you are using MySQL with storage engine that supports transactions, you need to configure XA drivers for both Oracle and MySQL datasource and ensure that both datasources are enlisted in the transaction of your container. Spring then needs to participate in the same transaction. You can't use HibernateTransactionManager for this, but need the JtaTransactionManager, as explained in this thread.
So, what you need for this to work is
Use InnoDB or BDB storage engines on MySQL
Configure XA datasources in your application server instead of regular ones
Use JtaTransactionManager on Spring configuration
After reading previous questions about this error, it seems like all of them conclude that you need to enable XA on all of the data sources. But:
What if I don't want a distributed
transaction? What would I do if I want to
start transactions on two different
databases at the same time, but
commit the transaction on one database
and roll back the transaction on
the other?
I'm wondering how my code
actually initiated a distributed
transaction. It looks to me like I'm
starting completely separate
transactions on each of the
databases.
Info about the application:
The application is an EJB running on a Sun Java Application Server 9.1
I use something like the following spring context to set up the hibernate session factories:
<bean id="dbADatasource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/dbA"/>
</bean>
<bean id="dbASessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dbADatasource" />
<property name="hibernateProperties">
hibernate.dialect=org.hibernate.dialect.Oracle9Dialect
hibernate.default_schema=schemaA
</property>
<property name="mappingResources">
[mapping resources...]
</property>
</bean>
<bean id="dbBDatasource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/dbB"/>
</bean>
<bean id="dbBSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dbBDatasource" />
<property name="hibernateProperties">
hibernate.dialect=org.hibernate.dialect.Oracle9Dialect
hibernate.default_schema=schemaB
</property>
<property name="mappingResources">
[mapping resources...]
</property>
</bean>
Both of the JNDI resources are javax.sql.ConnectionPoolDatasoure's. They actually both point to the same connection pool, but we have two different JNDI resources because there's the possibility that the two, completely separate, groups of tables will move to different databases in the future.
Then in code, I do:
sessionA = dbASessionFactory.openSession();
sessionB = dbBSessionFactory.openSession();
sessionA.beginTransaction();
sessionB.beginTransaction();
The sessionB.beginTransaction() line produces the error in the title of this post - sometimes. I ran the app on two different sun application servers. On one runs it fine, the other throws the error. I don't see any difference in how the two servers are configured although they do connect to different, but equivalent databases.
So the question is
Why doesn't the above code start
completely independent transactions?
How can I force it to start
independent transactions rather than
a distributed transaction?
What configuration could cause the difference in
behavior between the two application
servers?
Thanks.
P.S. the stack trace is:
Local transaction already has 1 non-XA Resource: cannot add more resources.
at com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.enlistResource(J2EETransactionManagerOpt.java:124)
at com.sun.enterprise.resource.ResourceManagerImpl.registerResource(ResourceManagerImpl.java:144)
at com.sun.enterprise.resource.ResourceManagerImpl.enlistResource(ResourceManagerImpl.java:102)
at com.sun.enterprise.resource.PoolManagerImpl.getResource(PoolManagerImpl.java:216)
at com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:327)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:189)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:165)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:158)
at com.sun.gjc.spi.base.DataSource.getConnection(DataSource.java:108)
at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:82)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
at org.hibernate.jdbc.JDBCContext.connection(JDBCContext.java:142)
at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:85)
at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1354)
at [application code ...]
1 Why doesn't the above code start completely independent transactions?
The app. server manages the transaction for you which can, if necessary, be a distributed transaction. It enlists all the participants automatically. When there's only one participant, you don't notice any difference with a plain JDBC transaction, but if there are more than one, a distributed transaction is really needed, hence the error.
2 How can I force it to start independent transactions rather than a
distributed transaction?
You can configure the datasource to be XA or Local. The transactional behavior of Spring/Hibernate can also be configured to use either regular JDBC transactions or delegate the management of transactions to the JTA distributed transaction manager.
I suggest you switch the datasource to non-XA and try to configure Spring/Hibernate to use the JDBC transactions. You should find the relevant information in the documentation, here what I suspect is the line to change:
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager" />
This should essentially means that you are not using the app. server distributed transaction manager.
3 What configuration could cause the difference in behavior between the
two application servers?
If you have really exactly the same app and configuration, this means that in one case only one participant is enlisted in the dist. transaction, while there are two in the 2nd case. One participant corresponds to one physical connection to a database usually. Could it be that in one case, you use two schema on two different databases, while in the 2nd case you use two schema on the same physical database? A more probable explanation would be that the datasource were configured differently on the two app. server.
PS: If you use JTA distributed transactions, you should use UserTransaction.{begin,commit,rollback} rather than their equivalent on the Session.
After reading previous questions about this error, it seems like all of them conclude that you need to enable XA on all of the data sources.
No, not all, all except one (as the exception is saying) if your application server supports Logging Last Resource (LLR) optimization (which allows to enlist one non-XA resource in a global transaction).
Why doesn't the above code start completely independent transactions?
Because you aren't. When using beginTransaction() behind EJB Session Beans, Hibernate will join the JTA transaction (refer to the documentation for full details). So the first call just works but the second call means enlisting another transactional resource in the current transaction. And since none of your resources are XA, you get an exception.
How can I force it to start independent transactions rather than a distributed transaction?
See #ewernli answer.
What configuration could cause the difference in behavior between the two application servers?
No idea. Maybe one of them is using at least one XA datasource.
It seems that Hibernate transactional cache mode requires the use of a JTA transaction manager. In an app server such as Glassfish, Weblogic, etc, Spring can use the JTA transaction manager. Tomcat does not have a JTA transaction manager.
Is there one that people use in this scenario? Or do people just not use transactional cache mode with Tomcat?
It depends on you ORM implementation, for example for JPA Spring has a transaction manager for using outside Java EE containers. here's how you declare it:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
I usually use annotations to demarcate transaction boundaries (with #Transaction), to do this you just have to add to the configuration file this other line:
<tx:annotation-driven transaction-manager="transactionManager" />
present in this XSD namespace: "http://www.springframework.org/schema/tx"
Atomikos is one JTA transaction manager that can be bundled with your app to work in a Tomcat deployment.