Transaction support for Discriminator model in Muiti-tenancy with Spring + Hibernate - spring

Our current development based on Discriminator model in Multi-tenancy. Following is the technical stack we are currently engage with,
Spring 3.1.1.RELEASE
Hibernate 4.1.6.Final
We are maintain tenant id by keep one column separately in each table. Tenant id filter when session is created.
Example model class.
#Entity
#FilterDef(name = "tenantFilter", parameters = #ParamDef(name = "tenantIdParam", type = "string"))
#Filters(#Filter(name = "tenantFilter", condition = "tenant_id = :tenantIdParam"))
#Table(name = "assessment")
public class Assessment implements java.io.Serializable, Comparable<Assessment> {
private static final long serialVersionUID = -2231966582754667029L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Long id;
#Column(name = "tenant_id", nullable = false, updatable = false)
private String tenantId;
// rest of the code...
}
This is the configuration of session factory
<!-- create database connection pool -->
<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="jdbc:mysql://${jdbc.host}:3306/${jdbc.database}?createDatabaseIfNotExist=true&autoReconnect=true&useUnicode=true&connectionCollation=utf8_general_ci&characterEncoding=UTF-8" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="idleConnectionTestPeriodInMinutes" value="60"/>
<property name="idleMaxAgeInMinutes" value="240"/>
<property name="maxConnectionsPerPartition" value="30"/>
<property name="minConnectionsPerPartition" value="10"/>
<property name="partitionCount" value="3"/>
<property name="acquireIncrement" value="5"/>
<property name="statementsCacheSize" value="100"/>
<property name="releaseHelperThreads" value="3"/>
</bean>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="lk.gov.elg.orm.model"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.hbm2ddl.auto=update
</value>
</property>
</bean>
<bean id="tenantBasedSessionFactory" class="lk.gov.elg.orm.dao.impl.TenantBasedSessionFactoryImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
Tenant base session factory
public class TenantBasedSessionFactoryImpl implements TenantBasedSessionFactory {
private SessionFactory sessionFactory;
#Override
public Session getTenantBasedSession(Object tenantId) {
Session session = sessionFactory.openSession();
session.enableFilter("tenantFilter").setParameter("tenantIdParam", tenantId);
return session;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getAllTenantBasedSession() {
Session session = sessionFactory.openSession();
return session;
}
}
sample Service class
#Service("assessmentService")
public class AssessmentServiceImpl implements AssessmentService {
#Autowired
private AssessmentDao assessmentDao;
public Long saveAssessment(Assessment assessment, Object tenantId) {
return assessmentDao.saveAssessment(assessment, tenantId);
}
}
Sample DAO class
#Repository("assessmentDao")
public class AssessmentDaoImpl implements AssessmentDao {
#Autowired
private TenantBasedSessionFactory tenantBasedSessionFactory;
public Long saveAssessment(Assessment assessment, Object tenantId) {
Session session = tenantBasedSessionFactory.getTenantBasedSession(tenantId);
try {
session.beginTransaction();
session.save(assessment);
session.getTransaction().commit();
return assessment.getId();
} catch (HibernateException e) {
logger.error("Error in persist assessment:", e);
session.getTransaction().rollback();
return null;
} finally {
session.close();
}
}
}
I would like to know is there a way to get the spring transaction support with this Discriminator model for database transactions ?
And the other thing is I would like to know is there any advantage of give transaction handling to spring rather than handling it by our side?
Thanks in advance.

i had similar problem and i have resolved it using aspect instead of customizing sessionfactory, so i can leverage annotation driven transaction support
Below code is for aspect which works on annotation #Tennant
#Aspect
public class TennantAspect {
#Autowired
private SessionFactory sessionFactory;
#Around("#annotation(Tennant)")
public Object enableClientFilter(ProceedingJoinPoint pjp) throws Throwable {
Object obj;
boolean isDAO=(pjp.getTarget() instanceof BaseDAO<?,?>);
try {
if(isDAO){
Authentication auth=SecurityContextHolder.getContext().getAuthentication();
if(auth!=null){
User user=(User) auth.getPrincipal();
this.sessionFactory.getCurrentSession().enableFilter("clientFilter").setParameter("clientId", user.getClientId());
}
}
obj=pjp.proceed();
}finally {
if(isDAO)
this.sessionFactory.getCurrentSession().disableFilter("clientFilter");
}
return obj;
}
}
Hope this solves your problem.
Alternatively you can also look at tenancy support by hiberante & spring
http://docs.jboss.org/hibernate/orm/4.1/devguide/en-US/html/ch16.html
https://github.com/mariofts/spring-multitenancy

Related

Can Spring JdbcTemplate connect to hive?

I am developing a java web project which is based on spring. And I want to use Spring JdbcTemplate to connect to hive. But when I tested my service, it came out this error message
"org.springframework.jdbc.CannotGetJdbcConnectionException: Could not
get JDBC Connection; nested exception is
org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver
class 'org.apache.hadoop.hive.jdbc.HiveDrive'".
The project is created by idea maven, but the hive jdbc driver is a local jar(it is located at WEB-INF/lib). So I am not sure whether the error is caused by the problem that my project still can't recognize the local jdbc driver jar or just because JdbcTemplate does not support hive connection. Can someone help me figure it out? thank you in advance.
Here are my code:
JdbcTemplate definition:
<bean id="dataSourceTDW" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSourceTDW"/>
</bean>
DAO class:
#Repository(value = "tdwQueryImp")
public class QueryDAOImp implements QueryDAO {
#Autowired
JdbcTemplate jdbcTemplate;
public List<Map<String,Object>> execute(String sql) {
return jdbcTemplate.queryForList(sql);
}
}
Kerberos Example:
#Component
public class HiveDataSource extends SimpleDriverDataSource {
private static final Logger logger = LoggerFactory.getLogger(HiveDataSource.class);
private final Subject subject;
#Autowired
HiveDataSource(Subject subject, Driver hiveDriver, String jdbcUrl) {
this.subject = subject;
setUrl(jdbcUrl);
setDriver(hiveDriver);
}
#Override
protected Connection getConnectionFromDriver(final Properties props) throws SQLException {
try {
return Subject.doAs(subject, (PrivilegedExceptionAction<Connection>)() -> getDriver().connect(getUrl(), props));
} catch (Exception e) {
e.printStackTrace();
logger.error("Failed to get Hive JDBC connection.", e);
}
return null;
}
}
Here HiveDriver bean is defined as :
#Bean
HiveDriver hiveDriver() {
HiveDriver impl = new HiveDriver() {
#Override
public Connection connect(String url, Properties info) throws SQLException {
return acceptsURL(url) ? new HiveConnection(url, info) {
#Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
/* do nothing */
};
} : null;
}
};
return impl;
}
I solved my problem by changing the class of datasource from org.apache.commons.dbcp.BasicDataSource to org.springframework.jdbc.datasource.SimpleDriverDataSource.
Here are the beans configuration:
<bean id="hiveDriver" class="org.apache.hadoop.hive.jdbc.HiveDriver"/>
<bean id="dataSourceTDW" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<constructor-arg name="driver" ref="hiveDriver"/>
<constructor-arg name="url" value="${url}"/>
<constructor-arg name="username" value="${username}" />
<constructor-arg name="password" value="${password}" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSourceTDW"/>
</bean>
you can refer bellow link :
http://saurzcode.in/2015/01/connect-hiveserver2-service-jdbc-client/
and more
http://hadooptutorial.info/hive-jdbc-client-example/
https://community.hortonworks.com/articles/53629/writing-a-spring-boot-microservices-to-access-hive.html

Connection pool replacement for already implemented Spring Jdbctemplate project

I am a doing a mid size project with spring jdbc and MsSQL server , project is almost 50% done , now when every request doing lots of inserts and updates specially with those tables which contains lots of columns and large datasets is performing very slow , and sometimes showing connection closed.
Now i am thinking to integrate C3p0 or similar connection pooling but i cant change any DAO code which i already done ..
I implemented a DAOHelper class with JDBCTemplate variable and injecting the JDBCTemplate dependency in applicationContext.xml with autowiring of DAOClass in controller class , and i extended this DAOHelper to all DAO classes and using this jdbcTemplate to do JDBC operations.
<bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="jdbc:sqlserver://192.168.1.101:1433;databaseName=OrderManager"/>
<property name="username" value="sa"/>
<property name="password" value="520759"/>
</bean>
<bean id="JdbcDataSource" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="ds"/>
</bean>
<bean id="OrderDAO" class="com.ordermanager.order.dao.OrderDAO" >
<property name="jdbcTemplate" ref="JdbcDataSource"/>
<property name="transactionManager" ref="transactionManager"/>
</bean>
#Controller
public class OrderController {
#Autowired
OrderDAO orderDAO;
#RequestMapping(value = "/addNewItem", method = RequestMethod.GET)
public ModelAndView addItem(#RequestParam("ParamData") JSONObject paramJson) {
ApplicationContext ctx = new FileSystemXmlApplicationContext(ConstantContainer.Application_Context_File_Path);
OrderDAO orderDAO = (OrderDAO) ctx.getBean("OrderDAO");
return new ModelAndView("MakeResponse", "responseValue", orderDAO.addItem(paramJson));
}
public class DAOHelper {
private JdbcTemplate jdbcTemplate;
private PlatformTransactionManager transactionManager;
public PlatformTransactionManager getTransactionManager() {
return transactionManager;
}
public void setTransactionManager(PlatformTransactionManager txManager) {
this.transactionManager = txManager;
}
public JdbcTemplate getJdbcTemplate() /*I am using this Method for all JDBC Task*/ {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
Now with minimal code changes how can i integrate C3p0 or any good connection pooling library with my already written code.
Just change the ds bean in your config xml with following and consider adding other c3p0 properties according to your own. make sure to have c3p0 jar in your classpath.
<bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="jdbcUrl" value="jdbc:sqlserver://192.168.1.101:1433;databaseName=OrderManager" />
<property name="user" value="sa" />
<property name="password" value="520789" />
</bean>

spring querydsl I don't want start a transaction

Entity:
package com.test.entity
#Entity
#Table(name="TEST_TABLE")
public class TestTable implements HasMapping, PrimaryKey<Long>, Serializable {
public static final String TABLE_NAME = "TEST_TABLE";
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="ID", nullable=false)
private Long id;
#Id
#Column(name="Name", nullable=false)
private String name;
#Temporal(value=TemporalType.TIMESTAMP)
#Column(name="CREATE_TIME", nullable=true)
#CreatedDate
private Date createTime;
#Column(name="CREATE_USER", nullable=true, length=32)
#CreatedBy
private String createUser;
#Temporal(value=TemporalType.TIMESTAMP)
#Column(name="LST_UPD_TIME", nullable=true)
#LastModifiedDate
private Date lstUpdTime;
#Column(name="LST_UPD_USER", nullable=true, length=32)
#LastModifiedBy
private String lstUpdUser;
#Column(name="JPA_VERSION", nullable=false)
#Version
private Integer jpaVersion;
......
}
QPath
package com.test.qpath
#Generated("com.mysema.query.codegen.EntitySerializer")
public class QTestTable extends EntityPathBase<TestTable> {
private static final long serialVersionUID = -1751805455;
public static final QTestTable testTable = new QTestTable("testTable");
public final NumberPath<Long> id = createNumber("id", Long.class);
public final DateTimePath<java.util.Date> createTime = createDateTime("createTime", java.util.Date.class);
public final StringPath createUser = createString("createUser");
public final NumberPath<Integer> jpaVersion = createNumber("jpaVersion", Integer.class);
public final DateTimePath<java.util.Date> lstUpdTime = createDateTime("lstUpdTime", java.util.Date.class);
public final StringPath lstUpdUser = createString("lstUpdUser");
public QTestTable(String variable) {
super(TestTable.class, forVariable(variable));
}
#SuppressWarnings("all")
public QTestTable(Path<? extends TestTable> path) {
super((Class)path.getType(), path.getMetadata());
}
public QTestTable(PathMetadata<?> metadata) {
super(TestTable.class, metadata);
}
......
}
Repository
package com.test.repos
public interface RTestTable extends JpaRepository<TestTable, Long>, QueryDslPredicateExecutor<TestTable> {
}
Service
package com.test.service
#Service
public class TestServiceR() {
#Autowired
private RTestTable rTestTable;
public void handler() {
long id = 1;
TestTable t = rTestTable.findone(id);
}
}
package com.test.service
#Service
public class TestServiceQuery() {
#Autowired
private RTestTable rTestTable;
#PersistenceContext
private EntityManager em;
private QTestTable qTestTable = QTestTable.testTable;
public void handler() {
long id = 1;
JPAQuery query = new JPAQuery(em);
TestTable t = query.from(qTestTable).where(qTestTable.id.eq(id)).singleResult(qTestTable);
}
}
spring config
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="#{env.jdbcUrl}" />
<property name="username" value="#{env.jdbcUsername}" />
<property name="password" value="#{env.jdbcPassword}" />
<property name="initialSize" value="1" />
<property name="minIdle" value="#{env['jdbcMinIdle'] ?: 2 }" />
<property name="maxActive" value="#{env['jdbcMaxActive'] ?: 20}" />
<property name="minEvictableIdleTimeMillis" value="#{env['jdbcMinEvictableIdleTimeMillis'] ?: 1800000}" />
<property name="validationQuery" value="#{env['jdbcTestSql']}" />
<property name="testWhileIdle" value="#{env['jdbcTestWhileIdle']?: false}" />
<property name="testOnBorrow" value="#{env['jdbcTestOnBorrow']?: true}" />
<property name="testOnReturn" value="#{env['jdbcTestOnReturn']?: false}" />
<property name="poolPreparedStatements" value="false" />
<property name="maxPoolPreparedStatementPerConnectionSize" value="-1" />
<property name="filters" value="mergeStat,slf4j" />
<property name="connectionProperties" value="druid.stat.slowSqlMillis=1500;druid.stat.logSlowSql=true" />
<property name="timeBetweenLogStatsMillis" value="900000" />
</bean>
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="default" />
<property name="packagesToScan">
<list>
<value>com.sunline.ccs.infrastructure.shared.model</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="#{env['jpaDatabaseType']?:'DEFAULT'}" />
<property name="showSql" value="#{env['jpaShowSql']?:false}" />
</bean>
</property>
</bean>
<bean id="sessionFactory" factory-bean="emf" factory-method="getSessionFactory" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" />
<jpa:repositories base-package="com.test.repos" />
I test TestServiceR.handler() and TestServiceQuery.handler().
I think they don't start a transaction.
but class TestServiceR are start a transaction.
why? how can i set TestServiceR.handler() don't start a transaction.
TestServiceR calls RTestTable.findOne which extends JpaRepository, which is implemented by SimpleJpaRepository, which is annotated with #Transactional(readOnly = true). So, the transaction is started by SimpleJpaRepository.
Is there a particular reason why you are worried about the transaction, given that it does not affect the application adversely (at least not much)? See the comment history for this Spring Data JPA JIRA issue if you are not convinced.
If you still want to override the default behaviour, you can initialise JPA repositories as #EnableJpaRepositories(enableDefaultTransactions = false) (Java configuration) or <jpa:repositories enable-default-transactions="false" ... /> (XML configuration) to prevent the default implementation from creating transactions by default. See this Spring Data JPA JIRA issue for more details.

spring mybatis transaction getting committed

I am trying to use mybatis spring transaction management
My problem is that the transactions are getting committed even if an exception is thrown.
Relatively new to this, anykind of help is much appreciated.
Following are the code snippets
spring xml configuration
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:Config.properties</value>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.user}"/>
<property name="password" value="${db.pass}"/>
<property name="defaultAutoCommit" value="false" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:Configuration.xml" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean class="org.mybatis.spring.SqlSessionTemplate" id="sqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory"/>
</bean>
Service class
#Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRED)
public void insertNotes(String noteTypeId,String confidentialValue,String summaryValue,String notes ,String notesId,String noteTypeValue,
String claimNumber,String notepadId,String mode)
{
NotepadExample notepadExample= new NotepadExample();
//to be moved into dao class marked with transaction boundaries
Notepad notepad = new Notepad();
notepad.setAddDate(new Date());
notepad.setAddUser("DummyUser");
if("true".equalsIgnoreCase(confidentialValue))
confidentialValue="Y";
else
confidentialValue="N";
notepad.setConfidentiality(confidentialValue);
Long coverageId=getCoverageId(claimNumber);
notepad.setCoverageId(coverageId);
notepad.setDescription(summaryValue);
notepad.setEditUser("DmyEditUsr");
//notepad.setNotepadId(new Long(4)); //auto sequencing
System.out.println(notes);
notepad.setNotes(notes);
notepad.setNoteType(noteTypeValue); //Do we really need this?
notepad.setNoteTypeId(Long.parseLong(notesId));
if("update".equalsIgnoreCase(mode))
{
notepad.setNotepadId(new Long(notepadId));
notepad.setEditDate(new Date());
notepadMapper.updateByPrimaryKeyWithBLOBs(notepad);
}
else
notepadMapper.insertSelective(notepad);
throw new java.lang.UnsupportedOperationException();
}
Not sure where I am going wrong...
The current call is from the controller as given below
#Controller
public class NotesController {
private static final Logger logger = LoggerFactory
.getLogger(NotesController.class);
#Autowired
private Utils utility;
#Autowired
NotepadService notepadService;
public #ResponseBody List<? extends Object> insertNotes(HttpServletRequest request,
HttpServletResponse response,#RequestParam("noteTypeValue") String noteTypeId,
#RequestParam("confidentialValue")String confidentialValue,
#RequestParam("summaryValue")String summaryValue,
#RequestParam("notes")String notes ,
#RequestParam("notesId")String notesId,
#RequestParam("noteTypeValue")String noteTypeValue,
#RequestParam("claimNumber")String claimNumber,
#RequestParam("notepadId")String notepadId,
#RequestParam("mode")String mode) {
try {
notepadService.insertNotes(noteTypeId, confidentialValue, summaryValue, notes, notesId, noteTypeValue, claimNumber, notepadId, mode);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
I had the same issue. I am also relatively new to spring. But according to me it depends on how you are calling your insertNotes() method. If you are calling it from another local method then it will not work, because spring has no way of know that it is called and to start the transaction.
If you are calling it from a method of another class by using autowired object of the class which contains insertNotes() method, then it should work.
For example
class ABC
{
#Autowired
NotesClass notes;
public void testMethod() {
notes.insertNotes();
}
}
class NotesClass
{
#Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRED)
public void insertNotes(String noteTypeId,
String confidentialValue,
String summaryValue,String notes ,
String notesId,String noteTypeValue,
String claimNumber,
String notepadId,
String mode) {
//Your code
}
}
You can try using transaction template. Remove #Tranasactional annotation from method and following code to xml file.
<bean id="trTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="timeout" value="30"/>
<property name="transactionManager" ref="transactionManager"/>
</bean>
Create object of Trasactiontemplate and call insertNotes from controller like this
#Autowired
private TransactionTemplate transactionTemplate;
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
insertNotes();
} catch (Exception e) {
transactionStatus.setRollbackOnly();
logger.error("Exception ocurred when calling insertNotes", e);
throw new RuntimeException(e);
}
}
});
Note : You have to make all parameters final before calling insertNotes method

Why is Spring #Transactional returning old data and how can I get it to return up-to-date data?

I'm using Spring 3.1.0.RELEASE with Hibernate 4.0.1.Final. I'm trying to use the Spring transaction manager but am having an issue where Spring is returning old data for a find method. In my Spring application, I call a save method, and then a find method. After I call save, I can see the changes in the database, but when I call the find, it is returning the old state of the object. Here is the controller methods ...
// method to save
#RequestMapping(method = RequestMethod.POST)
public String saveUserEventFeeds(final HttpServletRequest request,
#ModelAttribute("eventFeeds") final Set<EventFeed> eventFeeds) {
final String nextPage = "user/eventfeeds";
try {
final String[] eventFeedIds = request.getParameterValues("userEventFeeds");
final Set<EventFeed> userEventFeeds = new HashSet<EventFeed>();
if (eventFeedIds != null) {
for (final String eventFeedId : eventFeedIds) {
final EventFeed eventFeed = getEventFeed(eventFeeds, Integer.parseInt(eventFeedId));
userEventFeeds.add(eventFeed);
} // for
} // if
final Registration currentUser = (Registration) securityContextFacade.getContext().getAuthentication().getPrincipal();
userService.saveUserEventFeeds(currentUser.getId(), userEventFeeds);
} catch (Exception exc) {
LOG.error(exc.getMessage(), exc);
} // try
return nextPage;
} // saveUserEventFeeds
// method to retrieve user
#ModelAttribute("user")
public UserDetails getUser() {
final Registration reg = (Registration) securityContextFacade.getContext().getAuthentication().getPrincipal();
final int id = reg.getId();
final Registration foundUser = userService.findUserById(id);
return (UserDetails) foundUser;
} // getUser
and here is the service where i declare everything transactional ...
#Transactional(rollbackFor = Exception.class)
#Component("userService")
public class UserServiceImpl implements UserService {
...
#Override
public void saveUserEventFeeds(Integer userId, Set<EventFeed> eventFeeds) {
final Registration searchUser = new Registration();
searchUser.setId(userId);
final Registration user = usersDao.getUser(searchUser);
if (user != null) {
user.setUserEventFeeds(eventFeeds);
usersDao.saveUser(user);
} else {
throw new RuntimeException("User with id " + userId + " not found.");
} // if
}
#Override
public Registration findUserById(Integer id) {
final Registration searchUser = new Registration();
if (id != null) {
searchUser.setId(id);
} // if
return usersDao.getUser(searchUser);
}
Below is the transaction manager I've declared in my application context file. If you can see how I can configure things differently so that I can get the most current data on my finds, please let me know.
<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/myproj"/>
<property name="username" value="myproj"/>
<property name="password" value="password"/>
<property name="maxActive" value="10"/>
<property name="minIdle" value="5"/>
<!-- SELECT 1 is a simple query that returns 1 row in MySQL -->
<property name="validationQuery" value="SELECT 1"/>
</bean>
<bean class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" id="sessionFactory">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.myco.myproj.domain.Registration</value>
<value>com.myco.myproj.domain.Role</value>
<value>com.myco.myproj.domain.EventFeed</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="show_sql">true</prop>
<prop key="dialect">org.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
<tx:annotation-driven />

Resources