As part of a web app i am trying to build a registration process. after validating the process there are three sql statments to be performed. If any should fail then they should all be rolled back. However If i purposefully write the 3rd sql to fail (use a table name that doesnt exist). I see exception being thrown but the 1st and 2nd swl statments are not rolled back.
Can someone advise me on how this should be done.
from my application-context.xml
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="userDAO" class="com.doyleisgod.golf.database.JdbcUserDao">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="registration" class="com.doyleisgod.golf.services.Registration"/>
<tx:annotation-driven />
My registration service class
public class Registration implements IRegistration {
#Autowired JdbcUserDao userDAO;
#Override
#Transactional (rollbackFor = Exception.class)
public boolean registerUser(Object command) {
return userDAO.registerUser(command);
}
}
my userDAO registration method
public boolean registerUser(Object command) {
try {
setUserCommand(command);
sql = "INSERT INTO users (USERNAME,PASSWORD, ENABLED)VALUES ('"+username+"', '"+EncryptedPassword+"', TRUE);";
getSimpleJdbcTemplate().update(sql);
sql = "INSERT INTO user_roles (USERNAME,AUTHORITY)VALUES ('"+username+"', 'ROLE_USER');";
getSimpleJdbcTemplate().update(sql);
sql = "INSERT INTO users_details (USERNAME,FIRST_NAME, LAST_NAME, EMAIL_ADDRESS, HANDICAP)VALUES ('"+username+"', '"+firstname+"', '"+lastname+"', '"+email+"', '"+handicap+"');";
getSimpleJdbcTemplate().update(sql);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
Exampl of exception being thrown
15-Feb-2012 21:13:48 org.springframework.jdbc.support.SQLErrorCodesFactory <init>
INFO: SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
org.springframework.jdbc.BadSqlGrammarException: StatementCallback; bad SQL grammar [INSERT INTO users_details (USERNAME,FIRST_NAME, LAST_NAME, EMAIL_ADDRESS, HANDICAP)VALUES ('d', 'd', 'd', 'd', '0');]; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'golf.users_details' doesn't exist
Can someone tell me what i have missed. Why when the 3rd sql statment fails do the other 2 transactions not get rolled back?
Because you are catching the exception in your DAO, it is not thrown to the TransactionManager.
Related
I have a class in java with two more methods similar to the one here.
public Object noOfEmployees() {
List<Employee> emp = null;
String u = user.getUserName();
if ("user1".equals(u)) {
Query query = getHibernateTemplate().getSessionFactory().openSession()
.createSQLQuery("select * from employee where job='System Analyst'")
.addEntity(EMPLOYEE.class);
emp = query.list();
getHibernateTemplate().getSessionFactory().openSession().close();
} else if ("user2".equals(u)) {
Query query = getHibernateTemplate().getSessionFactory().openSession()
.createSQLQuery("select * from employee where job='DBA'")
.addEntity(EMPLOYEE.class);
emp = query.list();
getHibernateTemplate().getSessionFactory().openSession().close();
}
return emp.size();
}
When I ran the application, this is how I got the output:
Logged in as 'user2'
Hibernate: select * from employee where job='DBA'
Hibernate: select * from employee where job='DBA' and rank='2'
Hibernate: select * from employee where present='yes'
Logged in as 'user1'
Hibernate: select * from employee where job='System Analyst'
Hibernate: select * from employee where job='System Analyst' and rank='3'
Hibernate: select * from employee where present='yes'
Again, logged in as 'user2', first two methods get executed.
Hibernate: select * from employee where job='DBA'
Hibernate: select * from employee where job='DBA' and rank='2'
When I logged in as any user, this time even the first method did not get executed.
I have noticed that the code gets stuck when query.list() is encountered. I know that using hibernateTemplate is not recommended but the entire application is written using it. I have only started to learn about spring and hibernate. I will start making changes once I get comfortable with those.
Any suggestions related to the performance of query.list() and ways to improve the code are more than welcome.
Thank you!
Your code is flawed on many levels... For starters you shouldn't be using HibernateTemplate unless you are in a very old application, else use a plain SessionFactory. See http://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html#orm-hibernate-straight for more information.
Second when using Spring use Spring to manage your resources, i.e. Session in this case, or if you want to do it yourself at least manage it properly!.
So in short use a SessionFactory and use getCurrentSession instead of openSession. And use a proper query.
#Autowired
private SessionFactory sf;
#Transactional
public Long noOfEmployees() {
final String query = "select count(*) from employee where job=:job";
Query q = sf.getCurrentSession().createSQLQuery(query);
if ("user1".equals(u)) {
q.setParameter("job", "System Analyst");
} else if ("user2".equals(u) ) {
q.setParameter("job", "DBA");
}
return (Long) query.uniqueResult();
}
The #Transactional will make spring manage the resources, assuming you have <tx:annotation-driven /> in your context and properly added the HibernateTransactionManager.
The problem, obviously, with this code
Query query = getHibernateTemplate().getSessionFactory().openSession().
...
getHibernateTemplate().getSessionFactory().openSession().close();
With this getHibernateTemplate().getSessionFactory().openSession().close() you get a new session and close it!
You should use HQL
Query query = session.createQuery("from Employee where job='System Analyst'");
List<Employee> emp = query.list();
And the way you use Hibernate Template is entirely incorrect.
Refer how to use it
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/classic-spring.html
An example
public class ProductDaoImpl {
private HibernateTemplate hibernateTemplate;
public void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
public Collection loadProductsByCategory(final String category) throws DataAccessException {
return this.hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session) {
Criteria criteria = session.createCriteria(Product.class);
criteria.add(Expression.eq("category", category));
criteria.setMaxResults(6);
return criteria.list();
}
};
}
}
I have tried to change my flawed-on-many-levels code to some extent. All thanks to #M.Deinum and #v.ladynev for their swift responses.
Given below are only snippets where changes to move from HibernateTemplate to SessionFactory are mentioned:
//IndexService
#Transactional
public class IndexService {
User user;
SessionFactory sf;
public IndexService(User user, SessionFactory sf) {
this.user = user;
this.sf = sf;
}
//This method is used to get the number of employees based on users.
public Object noOfEmployees() {
String u = user.getUserName();
final String query = "select count(*) from employee where job=:job";
Query q = sf.getCurrentSession().createSQLQuery(query);
if ("user1".equals(u)) {
q.setParameter("job", "System Analyst");
} else if ("user2".equals(u) ) {
q.setParameter("job", "DBA");
}
return q.uniqueResult();
}
--------------------------------------------------------------------------------------
//Index
#Controller
#Transactional
public class Index {
#Autowired
User user;
#Autowired
SessionFactory sf;
#RequestMapping("/index")
public ModelAndView getIndex() {
System.out.println("user.getUserName() In Index = " + user.getUserName());
ModelAndView modelAndView = new ModelAndView("index");
IndexService indexService = new IndexService(user, sf);
modelAndView.addObject("noOfEmployees", indexService.noOfEmployees());
return modelAndView;
}
}
--------------------------------------------------------------------------------------
//spring-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="basicDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url"
value="jdbc:mysql://localhost/database_name"></property>
<property name="username" value="user"></property>
<property name="password" value="password"></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="basicDataSource"></property>
<property name="mappingResources" value="myBeans.hbm.xml" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
Issues that I came across while changing from HibernateTemplate to SessionFactory:
1.NullPointerException for SessionFactory
In index class,
#Autowired
SessionFactory sf;
and passed it as an argument.
IndexService indexService = new IndexService(user, sf);
2.No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
I put #Transactional above Index also. It is the controller in my application.
Thank you once again #M.Deinum and #v.ladynev!
I need in my application to remove all data from a cachable table.
I suposed that to delete all contents, I had to remove the second level cache, then use a truncate.
#Entity
#Table(name = "\"cpf_formacode\"")
#Cacheable
public class CpfRefFormaCode implements Serializable {
.......
}
the Dao method:
public void deleteAll() {
SessionFactory sf = em.unwrap(SessionFactory.class);
sf.getCache().evictEntityRegion(CpfRefFormaCode.class);
em.createNativeQuery("TRUNCATE TABLE cpf_formacode").executeUpdate();
}
persistence file:
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="org.hibernate.FlushMode" value="commit" />
<!-- property name="hibernate.hbm2ddl.auto" value="create-drop" / -->
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="hibernate.cache.infinispan.cachemanager" value="java:jboss/infinispan/hibernate" />
<property name="hibernate.cache.region.factory_class" value="org.jboss.as.jpa.hibernate4.infinispan.InfinispanRegionFactory" />
<property name="hibernate.cache.infinispan.statistics" value="true" />
</properties>
the error i have :
17:50:17,161 ERROR [org.jboss.as.ejb3.tx.CMTTxInterceptor] (http--127.0.0.1-8080-2) javax.ejb.EJBTransactionRolledbackException: Hibernate cannot unwrap interface org.hibernate.SessionFactory
17:50:17,163 ERROR [org.jboss.ejb3.invocation] (http--127.0.0.1-8080-2) JBAS014134: EJB Invocation failed on component CpfRefFormaCodeDao for method public void com.agefos.corp.business.dao.CpfRefFormaCodeDao.deleteAll(): javax.ejb.EJBTransactionRolledbackException: Hibernate cannot unwrap interface org.hibernate.SessionFactory
Caused by: javax.persistence.PersistenceException: Hibernate cannot unwrap interface org.hibernate.SessionFactory
I finished by findig the solution,
The problem that i was trying to clean the cach before deleting the data, and it was not the best practice
public void deleteAll() {
try {
TypedQuery<MyEntity> query = em.createQuery("From MyEntity f", MyEntity.class);
query.setHint("org.hibernate.cacheable", true);
List<MyEntity> result = null;
result = query.getResultList();
if (!result.isEmpty()) {
for (MyEntity f : result) {
em.remove(f);
}
}
em.flush();
} catch (Exception e) {
throw new PersistanceException("An error occurred while attempting to delete an instance of an object : " + entityClass, e);
}
}
the problem was resolved by adding the
em.flush();
In other words, flush tells Hibernate to execute the SQL statements needed to synchronize the JDBC connection's state with the state of objects held in the session-level cache. so i was abel to save other entities without ID problems
I want to test if my Spring Transaction Management using Spring JDBC is working properly when one of the database updates fails. Following is my code to update two DB tables: person and contact_info
public void createWithContactInfo(String username, String name, Date dob,
String contactName, String contactPhone, String contactEmail) {
try {
String sqlStmt = "INSERT INTO person (username, name, dob) VALUES (?, ?, ?)";
jdbcTemplateObject.update(sqlStmt, "paul", "Paul", dob);
sqlStmt = "INSERT INTO contact_info(username, customer_name, contact_name, contact_phone, contact_email) VALUES (?, ?, ?, ?, ?)";
jdbcTemplateObject.update(sqlStmt, username, name, contactName,
contactPhone, contactEmail);
} catch (DataAccessException e) {
e.printStackTrace();
}
}
I use the Spring declarative transaction management to configure the beans:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="createWithContactInfo"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="createOperation"
expression="execution(* com.example.db.CustomerJDBCTemplate.createWithContactInfo(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation" />
</aop:config>
<!-- Initialization for data source -->
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/Customer" />
<property name="username" value="myusername"/>
<property name="password" value="12345"/>
<property name="initialSize" value="10"/>
</bean>
<!-- Definition for customerJDBCTemplate bean -->
<bean id="customerJDBCTemplate" class="com.example.db.CustomerJDBCTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
Then in my test code, I have:
public class JdbcTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
CustomerDAO dao = (CustomerDAO) ctx.getBean("customerJDBCTemplate");
Date dob = new Date(90, 9, 10);
dao.createWithContactInfo("m9087", "Sam", dob, "David", "123456", "a123#example.com");
}
}
After running the main program, I got the Exception saying that Duplicate entry 'm9087' for key 'PRIMARY'. This is expected because m9087 already exists in the contact_info table. But since the second DB insert fails in the transaction, I thought the first jdbcTemplateObject.update(sqlStmt, "paul", "Paul", dob); will not be committed in the transaction. However I checked the person table and it returns valid entry for username=paul:
SELECT * FROM person WHERE username='paul';
This means the first DB insert was successful even though the second DB insert failed due to duplicate key exception.
My understanding is that the transaction should rollback and no commit will be made if any of the DB operation fail. But in this case, even though the second DB update fails due to duplicate key exception, the first DB insert still succeeded. Isn't it wrong behavior of transaction management? Is my setup correct in transaction management?
It's not rolling back because you're catching the exception. Transactions are rolled back when unchecked exception is thrown. And you are swallowing it with your catch block:
catch (DataAccessException e) {
e.printStackTrace();
}
The JdbcTemplate does not create automatically an transaction that envelop your both update statements in one transaction.
#Autowire
PlatformTransactionManager transactionManager;
public void createWithContactInfo(String username, String name, Date dob,
String contactName, String contactPhone, String contactEmail) {
DefaultTransactionDefinition paramTransactionDefinition =
new DefaultTransactionDefinition();
TransactionStatus status =
transactionManager.getTransaction(paramTransactionDefinition);
try{
... your 2 statmenets here ...
platformTransactionManager.commit(status);
}catch (Exception e) {
platformTransactionManager.rollback(status);
}
}
I'm trying to catch a ConstraintViolationException in my service layer and rethrowing a user defined checked exception. I'm catching the exception in my controller and adding an error object to my BindingResult. I'm using declarative transaction management I've tried to make my DAO a Repository and added a PersistenceExceptionTranslationPostProcessor to catch a spring translated exception. I've also added a txAdvice to rollback on all throwables. My exception does get caught but I'm getting an error 500 with:
Hibernate: insert into user (email, password, first_name, last_name, userType) values (?, ?, ?, ?, 1)
[acme]: [WARN ] - 2013-Feb-05 11:12:43 - SqlExceptionHelper:logExceptions(): SQL Error: 1062, SQLState: 23000
[acme]: [ERROR] - 2013-Feb-05 11:12:43 - SqlExceptionHelper:logExceptions(): Duplicate entry 'admin' for key 'email_unique'
[acme]: [DEBUG] - 2013-Feb-05 11:12:43 - HibernateTransactionManager:processCommit(): Initiating transaction commit
[acme]: [DEBUG] - 2013-Feb-05 11:12:43 - HibernateTransactionManager:doCommit(): Committing Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
[acme]: [ERROR] - 2013-Feb-05 11:12:43 - AssertionFailure:<init>(): HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: null id in com.test.model.AdminUser entry (don't flush the Session after an exception occurs)
[acme]: [DEBUG] - 2013-Feb-05 11:12:43 - HibernateTransactionManager:doRollbackOnCommitException(): Initiating transaction rollback after commit exception
org.hibernate.AssertionFailure: null id in com.test.model.AdminUser entry (don't flush the Session after an exception occurs)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:79)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:194)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:156)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:225)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1213)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:402)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:468)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
My Controller:
#RequestMapping (method = RequestMethod.POST)
#Transactional
public String registerAdmin(#Valid #ModelAttribute("user") AdminUser user, BindingResult bindingResult, ModelMap model) {
if (bindingResult.hasErrors()) {
return "admin/admins/form";
}
else if (!user.getPassword().equals(user.getConfirmPassword())) {
bindingResult.addError(new ObjectError("user.confirmPassword", "Passwords don't match"));
return "admin/admins/form";
}
else {
user.setPassword(passwordEncoder.encodePassword(user.getPassword(), null));
try {
userService.save(user);
return "redirect:/admin/admins";
} catch(ApplicationException ce) {
bindingResult.addError(new ObjectError("user.email", "Email already registered"));
return "admin/admins/form";
}
}
}
Part of my Spring config:
<context:component-scan base-package="com.test.dao, com.test.service" />
<context:property-placeholder location="/WEB-INF/spring.properties"/>
<import resource="springapp-security.xml"/>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/testdb?zeroDateTimeBehavior=convertToNull"/>
<property name="username" value="test"/>
<property name="password" value="test"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="mappingLocations" value="classpath*:com/test/model/hbm/**/*.hbm.xml" />
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.show_sql=true
</value>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*" rollback-for="Throwable" />
</tx:attributes>
</tx:advice>
Service layer:
public class UserServiceImpl implements UserDetailsService, UserService {
private UserDAO dao;
#Override
public void save(User c) throws ApplicationException {
try {
dao.save(c);
} catch(DataIntegrityViolationException cve) {
throw new ApplicationException("email already registered");
}
}
If I don't catch the runtime exception I don't get the hibernate exception (don't flush the session..)
You may want to remove the transaction annotation from your controller and add it to the service layer.
The service layer would look like below. If your service layer is throwing a checked exception you can add that to your annotation so that the insert is not even attempted to be committed.
public class UserServiceImpl implements UserDetailsService, UserService {
private UserDAO dao;
#Override
#Transactional(rollbackFor=ApplicationException.class)
public void save(User c) throws ApplicationException {
try {
dao.save(c);
} catch(DataIntegrityViolationException cve) {
throw new ApplicationException("email already registered");
}
}
What is happening currently in your code is that the transaction is not being rolled back but has to rollback because it actually tried to commit the data but because a database constraint the transaction had to be rolled back. By forcing the rollback with the #Transactional(rollbackFor=ApplicationException.class) it will not allow the transaction to perform a commit but it will rollback and your app will still add the error to the BindingResult.
*UPDATE: I found a method which didn't close the session after openning. I think this might be the cause. Will test and report later. *
We are using MyBatis with our GWT Java web application. The problem is that sometimes an exception happens while trying to read or write to the database with MyBatis. What could be the cause? Any subsequent queries will work. It seems like the connection is timed out and needs to be refreshed. This happens sometimes through the day, we don't see any pattern in this. We tried different configurations to no avail.
org.apache.ibatis.exceptions.PersistenceException:
### Error opening session. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Communications link failure during rollback(). Transaction resolution unknown.
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Communications link failure during rollback(). Transaction resolution unknown.
The MyBatis configuration file:
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/project"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
<property name="poolMaximumActiveConnections" value="20"/>
<property name="poolMaximumIdleConnections" value="5"/>
<property name="poolPingEnabled" value="true"/>
<property name="poolPingQuery" value="select 1"/>
</dataSource>
</environment>
</environments>
Update 1
The exception is thrown in different "DAOs", it's not specific to a single method/call.
A general method might look like this:
#Override
public Entity get(String id) throws Exception {
LogHelper.logMethodStart(logger, "get", "id", id);
SqlSession session = null;
try {
session = GenericDao.SESSION_FACTORY.openSession();
EntityDao mapper = session.getMapper(EntityDao.class);
return mapper.get(id);
} catch (Exception e) {
logger.error(e);
throw e;
} finally {
if (session != null) {
session.close();
}
}
}
Where the session factory class consists of:
public static SqlSessionFactory SESSION_FACTORY;
static {
logger.info("SqlSessionFactory init started.");
String aResource = "iBatisConfig.xml";
Reader reader;
try {
reader = Resources.getResourceAsReader(aResource);
} catch (IOException e) {
throw new RuntimeException(e);
}
SESSION_FACTORY = new SqlSessionFactoryBuilder().build(reader);
try {
reader.close();
} catch (IOException e) {
logger.error(e);
}
SESSION_FACTORY.getConfiguration().addMappers("com.example.project.server.dao");
logger.info("SqlSessionFactory init end.");
}
Problem solved for me. I went though all the methods that were opening a session and one session was not being closed - coding error. Thus the connection pool ran out of free connection sometimes.