Spring hibernate transactions propagations aren't working properly - java

I have a transactional class in my project with following 2 methods:
#Repository(value = "usersDao")
#Transactional(propagation = Propagation.REQUIRED)
public class UsersDaoImpl implements UsersDao {
#Autowired
SessionFactory sessionFactory;
/* some methods here... */
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW,readOnly = false,rollbackFor = {Exception.class})
public void pay(Users payer, int money) throws Exception {
if( payer.getMoney() < money ) {
throw new Exception("");
}
payer.setMoney(payer.getMoney()-money);
this.sessionFactory.getCurrentSession().update(payer);
}
#Override
#Transactional(readOnly = false,rollbackFor = {Exception.class})
public void makeTransfer(Users from, Users to, int money) throws Exception {
System.out.println("Attempting to make a transfer from " + from.getName() + " to " + to.getName() + "... sending "+ money +"$");
to.setMoney(to.getMoney()+money);
if( from.getMoney() < 10 ) {
throw new Exception("");
}
pay(from, 10);
if( from.getMoney() < money ) {
throw new Exception("");
}
from.setMoney(from.getMoney()-money);
this.sessionFactory.getCurrentSession().update(from);
this.sessionFactory.getCurrentSession().update(to);
}
}
The assumption is that when somebody's making a transfer, they must pay 10$ tax. Let's say there are 2 users who have 100$ both and I want to make a transfer (User1->User2) of 95$. First in makeTransfer I check if User1 is able to pay a tax. He is so I'm moving forward and checking if he's got 95$ left for transfer. He doesn't so the transaction is rolled back. The problem is, in the end they both have 100$. Why? For method pay I set Propagation.REQUIRES_NEW, which means it executes in a separate transaction. So why is it also rolled back? The tax payment should be actually save into a database and only the transfer should be rolled back. The whole point of doing this for me is understanding propagations. I understand them teoretically but can't manage to do some real example of it(How propagation change affects my project). If this example is misunderstanding I'd love to see another one.

What M. Deinum said.
Furthermore, according to the Spring documentation:
Consider the use of AspectJ mode (see mode attribute in table below)
if you expect self-invocations to be wrapped with transactions as
well. In this case, there will not be a proxy in the first place;
instead, the target class will be weaved (that is, its byte code will
be modified) in order to turn #Transactional into runtime behavior on
any kind of method.
To use aspectj, write
<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>
instead of
<tx:annotation-driven transaction-manager="transactionManager" />
Source:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html

I solved my problem. Thanks guys for pointing out allowing AspectJ but that wasn't the end. I did deeper research and it turned out that in #Transactional Spring Beans there's an aspect proxy, which is responsible(as far as get it) for operating on transactions(creating, rolling back etc.) for #Transactional methods. But it fails on self reference, because it bypasses proxy, so no new transactions are created. A simple way I used to get this working is calling function pay(..) not refering to this, but to a bean from the spring container, like this:
UsersDaoImpl self = (UsersDaoImpl)this.context.getBean("usersDao");
self.pay(from, 10);
Now, as it refers to the bean, it goes through the proxy so it creates a new transaction.
Just for learning issues I used those two lines to detect whether the two transactions are the same objects or not:
TransactionStatus status = TransactionAspectSupport.currentTransactionStatus();
System.out.println("Current transaction: " + status.toString());

Related

TransactionAttributeType.REQUIRES_NEW in conjunction with #Observes(during = TransactionPhase.AFTER_SUCCESS)

I recently stumbled into the next piece of Java EE6 code:
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void example(#Observes(during = TransactionPhase.AFTER_SUCCESS) final ExampleEvent exampleEvent) {
Is REQUIRES_NEW really needed?
I mean example method will always be called only after any previous transaction has ended successfully ( because of TransactionPhase.AFTER_SUCCESS).
Or am I missing something?
Your are only observing ExampleEvent, so your example()-Method will not be called by itself (based on the #TransactionAttribute) unless your do something like this:
#Inject
private Event<ExampleEvent> exampleEvent;
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void example(#Observes(during = TransactionPhase.AFTER_SUCCESS) final ExampleEvent exampleEvent) {
ExampleEvent event = new ExampleEvent();
exampleEvent.fire(event);
}
It makes sense to keep the #TransactionAttribute because the previous transaction just finished (AFTER_SUCCESS), so there is no current transaction therefore a new one is needed to be created. It can be possible that this would be done automatically (depending on the AS implementation) even without the annotation, but the result should be the same.

Connection pool exhausted in Spring Boot with JdbcTemplate

I have an issue with connection pool being exhausted when querying a database using Spring Boot and JdbcNamedTemplate.
This is how it is supposed to work:
Get a request from outside, with some parameters about how the house is supposed to be built.
Based on parameters recieved, use some REST endpoints and two DAOs to gather data.
Use data to create House object and return it.
Rcieve more requests...
How it works as of now:
Request is good.
Data from REST endpoints - OK. Data with DAO -> OK only for first 50 requests with two DAOs, after that NOT OK. When one of the DAOs is disabled, no connections are blocked.
After 50 houses are built OK, rest will take forever to finish and have no windows in the end.
Makes it unusable for more requests as they will simply timeout.
I get this exception when I call endpoint more than 50 times (max pool size):
com.atomikos.jdbc.AtomikosSQLException: Connection pool exhausted - try increasing 'maxPoolSize' and/or 'borrowConnectionTimeout' on the DataSourceBean.
And it will stay like this until I restart the app. It seems like there is something off about my DAO or configuration, but I haven't been able to figure out what, despite searching all day. If anyone can help, I will be thankfull.
Extra info:
No other exceptions are thrown that I am aware of.
All the other data is retrieved correcly.
Send help.
UPDATE:
I did some more experiments:
This app uses another dao that I didnt mention before because I forgot.
It works almost the same, only it connects to a different database, so it has a separate configuration. It also takes advantage of JdbcNamedTemplate and #Qualifier is used to select the correct one.
Now, what I discovered is that disbling one or the other DAO will not eat the connections anymore. So the question is: What can't they coexist in peace?
This is the dao.
#Component
public class WindowsDao {
private static final String PARAM_1 = "param";
private final String SELECT_ALL = ""
+ " SELECT "
+ " STUFF "
+ " FROM TABLE "
+ " WHERE "
+ " THING =:" + PARAM_1
+ " WITH UR";
#Autowired
private NamedParameterJdbcTemplate myTemplate;
public Optional<List<BottomDealerText>> getWindows(
final WindowsCode windowCode {
final MapSqlParameterSource queryParameters = new MapSqlParameterSource()
.addValue(PARAM_1, windowCode.getValue())
final Optional<List<Window>> windows;
try {
windows = Optional.of(myTemplate.query(
SELECT_ALL,
queryParameters,
new WindowsRowMapper()));
}
catch (final EmptyResultDataAccessException e) {
LOG.warn("No results were found.");
return Optional.empty();
}
return windows;
}
}
DAO is called from this service:
#Service
#Transactional
public class WindowsService {
#Autowired
private WindowsDao windowsDao;
public Optional<List<Stuff>> getWindows(
final WindowCode windowCode) {
final Optional<List<Window>> windows = windowsDao.getWindows(
windowCode;
return windows;
}
}
Which is called from this service:
#Service
#Transactional
public class AssembleHouseService {
// some things
#Autowired
private WindowsService windowsService;
public House buildHouse(final SomeParams params) {
// This service will fetch parts of the house
HouseBuilder builder = House.builder();
// call other services and then...
builder.windows(windowsService.getWindows(args).orElse(/*something*/));
//and then some more things...
}
}
This is what I use to configure the datasource:
myDb:
driver: db2
schema: STUFF
unique-resource-name: STUFF
database-name: STUFF1
server-name: myServer
port: 12312
username: hello
password: world
driver-type: 4
min-pool-size: 2
max-pool-size: 50
RowMapper:
public class WindowsRowMapper implements RowMapper<Window> {
#Override
public Windows mapRow(final ResultSet rs, final int rowNum)
throws SQLException {
return new BottomDealerText(
re.getString("WSIZE"),
rs.getString("DESCRIPTION"),
rs.getString("COLOR"));
}
}
If you have two readonly DAOs in the same transaction then you may have hit a known bug in the Atomikos open source edition that manifests itself only in this particular scenario.
It's been fixed in the commercial edition but not (yet) in the open source.
Hope that helps
Just posting here for those who look for a workaround:
If you cant change to different version of atomikos (or just ditch it), what worked for me was adding
Propagation.REQUIRES_NEW
to services that used those different data sources, so it would be:
#Service
#Transactional(propagation = Propagation.REQUIRES_NEW)
It seems like putting this two read operations into separate transactions makes atomikos close the transaction and release connection properly.

How can I intercept JTA transactions events and get a reference to the current EntityManager associated with the transaction

Long story short: We develop and maintain a library that can be used in other projects using JavaEE7/CDI/JPA. Applications will run under Glassfish-4.0 and use Hibernate's JPA implementation for an underlying PostgreSQL persistence. This is part of a long term migration effort to rewrite old applications that were written in Spring/Struts/Hibernate into the new world of JavaEE7/CDI/JTA.
The problem: For audit purposes, our library needs to intercept all database transactions and include custom SQL statements before the user statements are executed. At this point, the current username and IP address need to be inserted into a temporary database variable (vendor specific feature) so that a database trigger can read them to create the audit trail for any row modification. This particular post was very helpful providing alternatives, and our team went down the trigger road due to a previously established legacy.
HOWEVER: We are deeply disappointed at how JTA handles transaction events. There are numerous ways to intercept transactions, but this particular case seems to be down right impossible. In the old architecture, using Spring's transaction manager, we simply used a Hibernate Interceptor implementing Interceptor.afterTransactionBegin(...). Reading up on the official JTA-1.2 spec, we found that it does have support for Synchronization.beforeCompletion and Synchronization.afterCompletion. After several hours of debugging sessions we clearly noted that Hibernate's implementation of JTA is using these facilities. But JTA seems to be lacking events like beforeBegin and afterBegin (which IMHO seems to be a lack of common sense). And since there are no facilities to intercept those, Hibernate complies fully with JTA and it simply won't. Period.
No matter what we do, we can't find a way. We tried, for instance, to intercept #Transactional annotations and run our code just after the container's JTA impl does its job to open the transaction. But we lack the ability to dynamically acquire the EntityManager associated with that particular transaction. Remember: this is a library, not the web application itself. It cannot make any assumptions about which Persistence Units are declared and used by the application. And, as far as we can tell, we need to know which specific Persistent Unit name to inject it into our code. We are trying to provide an audit facility to other temas that is as transparent as possible.
So we humbly ask for help. If anyone out there has a solution, workaround, whatever opinion, we'll be glad to hear it.
This was quickly answered here in this post by myself, but hiding the fact that we spent over two weeks trying different strategies to overcome this. So, here goes our final implementation we decided to use.
Basic idea: Create your own implementation of javax.persistence.spi.PersistenceProvider by extending the one given by Hibernate. For all effects, this is the only point where your code will be tied to Hibernate or any other vendor specific implementation.
public class MyHibernatePersistenceProvider extends org.hibernate.jpa.HibernatePersistenceProvider {
#Override
public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map properties) {
return new EntityManagerFactoryWrapper(super.createContainerEntityManagerFactory(info, properties));
}
}
The idea is to wrap hibernate's versions of EntityManagerFactory and EntityManager with your own implementation. So you need to create classes that implement these interfaces and keep the vendor specific implementation inside.
This is the EntityManagerFactoryWrapper
public class EntityManagerFactoryWrapper implements EntityManagerFactory {
private EntityManagerFactory emf;
public EntityManagerFactoryWrapper(EntityManagerFactory originalEMF) {
emf = originalEMF;
}
public EntityManager createEntityManager() {
return new EntityManagerWrapper(emf.createEntityManager());
}
// Implement all other methods for the interface
// providing a callback to the original emf.
The EntityManagerWrapper is our interception point. You will need to implement all methods from the interface. At every method where an entity can be modified, we include a call to a custom query to set local variables at the database.
public class EntityManagerWrapper implements EntityManager {
private EntityManager em;
private Principal principal;
public EntityManagerWrapper(EntityManager originalEM) {
em = originalEM;
}
public void setAuditVariables() {
String userid = getUserId();
String ipaddr = getUserAddr();
String sql = "SET LOCAL application.userid='"+userid+"'; SET LOCAL application.ipaddr='"+ipaddr+"'";
em.createNativeQuery(sql).executeUpdate();
}
protected String getUserAddr() {
HttpServletRequest httprequest = CDIBeanUtils.getBean(HttpServletRequest.class);
String ipaddr = "";
if ( httprequest != null ) {
ipaddr = httprequest.getRemoteAddr();
}
return ipaddr;
}
protected String getUserId() {
String userid = "";
// Try to look up a contextual reference
if ( principal == null ) {
principal = CDIBeanUtils.getBean(Principal.class);
}
// Try to assert it from CAS authentication
if (principal == null || "anonymous".equalsIgnoreCase(principal.getName())) {
if (AssertionHolder.getAssertion() != null) {
principal = AssertionHolder.getAssertion().getPrincipal();
}
}
if ( principal != null ) {
userid = principal.getName();
}
return userid;
}
#Override
public void persist(Object entity) {
if ( em.isJoinedToTransaction() ) {
setAuditVariables();
}
em.persist(entity);
}
#Override
public <T> T merge(T entity) {
if ( em.isJoinedToTransaction() ) {
setAuditVariables();
}
return em.merge(entity);
}
#Override
public void remove(Object entity) {
if ( em.isJoinedToTransaction() ) {
setAuditVariables();
}
em.remove(entity);
}
// Keep implementing all methods that can change
// entities so you can setAuditVariables() before
// the changes are applied.
#Override
public void createNamedQuery(.....
Downside: Interception queries (SET LOCAL) will likely run several times inside a single transaction, specially if there are several statements made on a single service call. Given the circumstances, we decided to keep it this way due to the fact that it's a simple SET LOCAL in memory call to PostgreSQL. Since there are no tables involved, we can live with the performance hit.
Now just replace Hibernate's persistence provider inside persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="petstore" transaction-type="JTA">
<provider>my.package.HibernatePersistenceProvider</provider>
<jta-data-source>java:app/jdbc/exemplo</jta-data-source>
<properties>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform" />
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
</properties>
</persistence-unit>
As a side note, this is the CDIBeanUtils we have to help with the bean manager on some special occasions. In this case, we are using it to look up a reference to HttpServletRequest and Principal.
public class CDIBeanUtils {
public static <T> T getBean(Class<T> beanClass) {
BeanManager bm = CDI.current().getBeanManager();
Iterator<Bean<?>> ite = bm.getBeans(beanClass).iterator();
if (!ite.hasNext()) {
return null;
}
final Bean<T> bean = (Bean<T>) ite.next();
final CreationalContext<T> ctx = bm.createCreationalContext(bean);
final T t = (T) bm.getReference(bean, beanClass, ctx);
return t;
}
}
To be fair, this is not exactly intercepting Transactions events. But we are able to include the custom queries we need inside the transaction.
Hopefully this can help others avoid the pain we went through.

EJB TransactionRequiredException in GlassFish 2.1

In my Stateful bean, I have the following lines:
#Stateful(mappedName = "ejb/RegistrationBean")
#StatefulTimeout(unit = TimeUnit.MINUTES, value = 30)
#TransactionManagement(value=TransactionManagementType.CONTAINER)
public class RegistrationStateful implements RegistrationStatefulRemote {
#PersistenceContext
EntityManager em;
private List<Event> reservedSessions = new ArrayList<Event>();
private boolean madePayment = false;
...
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private void cancelReservation() {
if (reservedSessions.size() != 0) {
Teacher theTeacher;
for (Event session : reservedSessions) {
if ((theTeacher = session.teacher) == null) theTeacher = bestTeacher.teacher;
theTeacher = em.merge(theTeacher) //The exception is thrown here
//Make changes to theTeacher
em.flush(); //The exception is also thrown here
}
//Clear the reservedSessions list
reservedSessions.clear();
}
}
#Remove
public void endRegistration() {}
#PreDestroy
public void destroy() {
//Cancel outstanding reservations if payment has not been made
if (!madePayment) cancelReservation();
}
}
The line em.merge(someEntity) throws the TransactionRequiredException. Could someone please tell me why it happens? I thought with TransactionAttribute.REQUIRED, a transaction will AUTOMATICALLY be created if there isn't an active one. I tried to use em.joinTransaction() but it throws the same Exception. I'm a beginner at this transaction thing. I'd be very grateful if someone could explain this to me.
UPDATE: I'd like to add a bit more information
The Stateful bean actually also has the following function:
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private void reserveSession(List<Event> sessions) throws ReservationException {
//Reserve the sessions
Teacher theTeacher;
for (Event session : sessions) {
if ((theTeacher = session.teacher) == null) theTeacher = bestTeacher.teacher;
theTeacher = em.merge(theTeacher);
//Make changes to theTeacher
em.flush();
}
}
The flow is as following: the user tells me his free time and I reserve some seats for him. After that, I show him his reserved seats and he can choose to make payment or cancel the reservations.
The reserved() function worked perfectly as expected but the cancelReservation() did not.
UPDATE 2: I have fixed the problem last night by commenting out the lines "#TransactionAttribute(TransactionAttributeType.REQUIRED)", "em.merge(theTeacher)" and "em.flush()" in the "cancelReservation()" function. The result is perfect. Would it be safe if I cut off those lines? I was afraid I would get "detached entity" exception when I used "em.merge()" in the first place.
The only thing that springs to mind (if you'll excuse the pun) is that if you're calling cancelReservation() from another method inside the bean, then i'm not sure the transaction annotation will be observed. The annotation ultimately works by summoning an interceptor, and i believe interceptors are only applied to calls between different classes (this is something i should really check).
So, if you have a non-transactional method on the bean which calls a transactional method, then a transaction won't be started when the transactional method is called.
I could be completely wrong about this. I'll go and have a bit of a read of the spec and get back to you.
EDIT: I had a read of the spec, and it reminded me what a disaster zone the J2EE specs are. Horrific. However, the section on transactions does seem to imply that the transaction attributes only apply to calls made to an EJB's business interface. I believe calls from one method to another inside a bean are not considered to go through the business interface, even when the method being called is part of that interface. Therefore, you wouldn't expect them to attract transactions.
Something you could try would be to route them through the interface; there is no nice way of doing this, but you should be able to inject a business-interface self-reference like this:
public class RegistrationStateful implements RegistrationStatefulRemote {
#EJB
private RegistrationStatefulRemote self;
You can then change your #PreDestroy method to look like this:
#PreDestroy
public void destroy() {
self.cancelReservation();
}
And i believe that should count as a normal business interface call, with transactions and so on.
I have never actually tried this, so this could be complete rubbish. If you try it, let me know how it works out!

How to refresh an entity in a Future?

I am not really sure where my problem lies, as I am experimenting in two areas that I don't have much experience with: JPA and Futures (using Play! Framework's Jobs and Promises).
I have the following bit of code, which I want to return a Meeting object, when one of the fields of this object has been given a value, by another thread from another HTTP request. Here is what I have:
Promise<Meeting> meetingPromise = new Job<Meeting> () {
#Override
public Meeting doJobWithResult() throws Exception {
Meeting meeting = Meeting.findById(id);
while (meeting.bbbMeetingId == null) {
Thread.sleep(1000);
meeting = meeting.refresh(); // I tried each of these
meeting = meeting.merge(); // lines but to no avail; I
meeting = Meeting.findById(id); // get the same result
}
return meeting;
}
}.now();
Meeting meeting = await(meetingPromise);
As I note in the comments, there are three lines in there, any one of which I think should allow me to refresh the contents of my object from the database. From the debugger, it seems that the many-to-one relationships are refreshed by these calls, but the single values are not.
My Meeting object extends Play! Framework's Model, and for convenience, here is the refresh method:
/**
* Refresh the entity state.
*/
public <T extends JPABase> T refresh() {
em().refresh(this);
return (T) this;
}
and the merge method:
/**
* Merge this object to obtain a managed entity (usefull when the object comes from the Cache).
*/
public <T extends JPABase> T merge() {
return (T) em().merge(this);
}
So, how can I refresh my model from the database?
So, I ended up cross-posting this question on the play-framework group, and I got an answer there. So, for the discussion, check out that thread.
In the interest of having the answer come up in a web search to anyone who has this problem in the future, here is what the code snippet that I pasted earlier looks like:
Promise<Meeting> meetingPromise = new Job<Meeting> () {
#Override
public Meeting doJobWithResult() throws Exception {
Meeting meeting = Meeting.findById(id);
while (meeting.bbbMeetingId == null) {
Thread.sleep(1000);
if (JPA.isInsideTransaction()) {
JPAPlugin.closeTx(false);
}
JPAPlugin.startTx(true);
meeting = Meeting.findById(id);
JPAPlugin.closeTx(false);
}
return meeting;
}
}.now();
Meeting meeting = await(meetingPromise);
I am not using the #NoTransaction annotation, because that messes up some other code that checks if the request is coming from a valid user.
I'm not sure about it but JPA transactions are managed automatically by Play in the request/controller context (the JPAPlugin opens a transaction before invocation and closes it after invocation).
But I'm not sure at all what happens within jobs and I don't think transactions are auto-managed (or it's a feature I don't know). So, is your entity attached to an entitymanager or still transient? Is there a transaction somewhere? I don't really know but it may explain some weird behavior if not...

Categories