2015/03/09

Start Spring Transaction per request but reduce database connections

In my previous blog post, I explained how to make spring declarative transactions to behave truly transactional. We do not need to do anything special in a Spring MVC project. But if we use any other UI controller then we have to start a dummy transaction at the beginning of a HTTP request and end that transaction at the end of that request.

One concern in this method is, since it starts and end transactions per HTTP request, will it increase the number of database connections and disconnections. Well there is a possibility and it will reduce the overall performance of the system.

As described in Class DataSourceTransactionManager it is a good  idea to create a database connection when it is actually needed for example only when executing a SQL statement. In this way a dummy transaction will be started but it will not create a database connection. The connection will be established only when it is needed during the transaction.

Extract from the class documentation


"Consider defining a LazyConnectionDataSourceProxy for your target DataSource, pointing both this transaction manager and your DAOs to it. This will lead to optimized handling of "empty" transactions, i.e. of transactions without any JDBC statements executed. A LazyConnectionDataSourceProxy will not fetch an actual JDBC Connection from the target DataSource until a Statement gets executed, lazily applying the specified transaction settings to the target Connection."


So we will define LazyConnectionDataSourceProxy based on a usual datasource. Then transaction manager as well as our JdbcTemplate will be pointed to this LazyConnectionDataSource as below.
<!-- Creating TransactionManager Bean, since JDBC we are creating of type
DataSourceTransactionManager -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="lazyConnectionDatasourceProxy" />
</bean>
<!-- Lazy creation of database connections-->
<bean id="lazyConnectionDatasourceProxy" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource" ref="dataSource"/>
</bean>
<!-- JNDI actual datasource -->
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/myDS" expected-type="javax.sql.DataSource"/>
<!-- Definition for JDBCTemplate bean -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="lazyConnectionDatasourceProxy" />
</bean>
view raw context.xml hosted with ❤ by GitHub

Now JdbcTemplate as well as the Transaction manager will grab a database connection only when it is actually needed.

2015/03/06

Use JDBC, Spring transactions and @Transactional

Ever wanted to use spring declarative transaction management with a different UI technology than Spring MVC and found out it does not behave really transactional?

There is a good discussion in stackoverflow Spring transaction internals. This describes how spring expects the transactions to behave. I faced a problem when using Spring declarative transactions with Vaadin UI framework which is described more detailed in stackoverflow. The issue I faced was even though I used @Transactional(propagation = Propagation.PROPAGATION_REQUIRED) in my service methods, when those methods are called from a single method in UI, spring treats each of these calls as different transactions and commits the transaction at the end of each service method. The expected behavior was if service methods, methodA(), methodB() and methodC() is called from a caller() method located in UI, those three methods to participate in a single transaction and caller operation to be an atomic operation.

After investigating the issue closely the reason was, Spring will make the methodA(), methodB() and methodC() participate in a single transaction only if a transaction is already started when calling the first service method which is annotated with @Transactional. If this requirement is not met, then the transaction proxy who calls the methodA() will create a transaction. But this transaction will end after executing methodA() and a new transaction is created by the proxy for executing the methodB() and so on. This leads to the behavior of committing after each method call.

So if we can start a transaction before the caller() method in UI kicks in, then Spring transaction proxy will make the methodA() participate in that transaction, and methodB() and methodC(). In this case lets assume if the methodC() is annotated with @Transactional and the propagation setting is PROPAGATION_REQUIRESNEW, the proxy will create a new transaction. This is the expected behavior.

So in SpringMVC and hibernate environment this is done using an OpenSessionInViewFilter which starts a hibernate session in each http request and commits or rollback that transaction at the end of that request. A similar strategy can also be used in our problem. Simply start a transaction in each request and commit or rollback it at the end of the request. This way a dummy transaction is always available when service methods are called and then Spring will nicely manage to participate, create further new transactions or not support the transactions.

A sample servlet filter I came up with is listed below
public class TransactionFilter implements Filter {
@Autowired
PlatformTransactionManager transactionManager;
TransactionDefinition transactionDefinition;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
transactionDefinition = new DefaultTransactionDefinition();
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
TransactionStatus status = transactionManager.getTransaction(transactionDefinition);
try {
filterChain.doFilter(servletRequest, servletResponse);
transactionManager.commit(status);
}catch(Throwable ex){
if(!status.isCompleted()){
transactionManager.rollback(status);
}
throw new ServletException(ex);
}
}
@Override
public void destroy() {
}
}
What this does is get the default transaction manager and starts a new transaction and commit the transaction at the end of the filter chain. As this filter uses spring transaction libraries, the filter should be registered with org.springframework.web.filter.DelegatingFilterProxy as below.
<!--Filter to create transaction per request -->
<filter>
<filter-name>transactionFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
view raw web.xml hosted with ❤ by GitHub
Then define a bean in spring context.xml that points to the filter class as below.
<bean id="transactionFilter" class="com.xyz.ui.TransactionFilter"/>
Now all set except for the fact that it creates a transaction per request as well as a database connection per request. This can be improved and it will be discussed in the next post.

EDIT: Lazy creation of database connections

2015/03/02

Use Vaadin, Apache shiro and "Remember-me"

While there are numerous solutions to use apache shiro and vaadin, Mike Pilones this solution works well except the "Remember-me" functionality. The reason for this is when using this method, we have to refrain from using a servlet filter that initializes the security manager. Thus shiro is unable to get hold of the servlet response and set the "Remember-me" cookie.

To overcome this, we have to subclass the CookieRememberMeManager and override few methods to include ServletRequest and ServletResponse to be obtained from VaadinServletService.

public class VaadinShiroRememberMeManager extends org.apache.shiro.web.mgt.CookieRememberMeManager {
@Override
protected void rememberSerializedIdentity(Subject subject, byte[] serialized) {
//base 64 encode it and store as a cookie:
String base64 = Base64.encodeToString(serialized);
Cookie template = getCookie(); //the class attribute is really a template for the outgoing cookies
Cookie cookie = new SimpleCookie(template);
cookie.setValue(base64);
cookie.saveTo(VaadinServletService.getCurrentServletRequest(),
VaadinServletService.getCurrentResponse().getHttpServletResponse());
}
@Override
protected byte[] getRememberedSerializedIdentity(SubjectContext subjectContext) {
String base64 = getCookie().readValue(VaadinServletService.getCurrentServletRequest(), VaadinServletService.getCurrentResponse().getHttpServletResponse());
// Browsers do not always remove cookies immediately (SHIRO-183)
// ignore cookies that are scheduled for removal
if (Cookie.DELETED_COOKIE_VALUE.equals(base64)) return null;
if (base64 != null) {
base64 = ensurePadding(base64);
byte[] decoded = Base64.decode(base64);
return decoded;
} else {
//no cookie set - new site visitor?
return null;
}
}
@Override
protected void forgetIdentity(Subject subject) {
forgetIdentity(VaadinServletService.getCurrentServletRequest(),
VaadinServletService.getCurrentResponse().getHttpServletResponse());
}
@Override
public void forgetIdentity(SubjectContext subjectContext) {
forgetIdentity(VaadinServletService.getCurrentServletRequest(),
VaadinServletService.getCurrentResponse().getHttpServletResponse());
}
private void forgetIdentity(HttpServletRequest request, HttpServletResponse response) {
getCookie().removeFrom(request, response);
}
private String ensurePadding(String base64) {
int length = base64.length();
if (length % 4 != 0) {
StringBuilder sb = new StringBuilder(base64);
for (int i = 0; i < length % 4; ++i) {
sb.append('=');
}
base64 = sb.toString();
}
return base64;
}
}
Now we have to set our custom remember me manager in the shiro Security manager as follows.
<bean id="rememberMeManager" class="com.xyz.VaadinShiroRememberMeManager"/>
<bean id="securityManager" class="org.apache.shiro.mgt.DefaultSecurityManager">
<property name="realms">
<list>
<ref bean="ldapRealm"/>
<ref bean="x509CertificateRealm"/>
<ref bean="jdbcAuthRealm"/>
</list>
</property>
<property name="sessionManager" ref="sessionManager"/>
<property name="authenticator.authenticationStrategy" ref="authcStrategy"/>
<!--<property name="sessionManager.sessionIdCookie.domain" value="${security.cookie.domain}"/>-->
<property name="rememberMeManager" ref="rememberMeManager"/>
<property name="rememberMeManager.cookie.name" value="Remember-me"/>
<property name="rememberMeManager.cookie.maxAge" value="500"/>
</bean>
view raw context.xml hosted with ❤ by GitHub

Now shiro security manager can set and retrieve any remember-me cookie using the VaadinServletService provided request and response objects.