I am new in Spring-Hibernate and my issue is : a transaction is not saving the data in the table. But not throwing any exception as well. From the line
Long id = logTransactionFileUpload(fileMetdataBean);
in the function "logClientFile" (in the "Transactional" annotated class/service class, listed below), I am seeing a returned id but data did not show up in the table. .
Finding is : this is nested transaction and was rolled back as the parent had exception from "msgProducer.send( message, jmsConnectInfo )" in JobRunnerServiceImpl class , in submitJob method- means after db insertion. Is there a way that hibernate can persist child transacttion when parent fails?
I am not suspecting my spring/hibernate configuration as save from other parts are working fine. Only this part is the problem.
FYI:
if I turn on ( in the DAO impl class, listed below)
//getCurrentSession().flush();
//getCurrentSession().getTransaction().commit();
Then data is showing up in the table.But this commit and flush should not be there when @transactional is used.
My @Transactional annotated class:
@Service("jobRunnerService")
@Transactional
public class JobRunnerServiceImpl implements JobRunnerService
{
private static final Logger LOG = LoggerFactory.getLogger( MethodHandles.lookup().lookupClass() );
@Autowired
@Qualifier("fileLoggerDao")
private IFileLoggerDAO fileLoggerDAO;
@Autowired
@Qualifier("fileMetaDataDao")
private IGenericDAO<FileMetaDataBean,Long> fileMetaDataDAO;
public void submitJob(String serviceName, String filePath, long clientId, long layoutId, String audienceId,
boolean isCA)
{
Map<String, String> parameters = new HashMap<String, String>();
try
{
..... doing something............
LOG.info( "Logging file information in FILE_META_DATA table... " );
String loggedFile = logClientFile( fileName, FACEBOOK_FILE_TYPE, fileExt, clientId, tpList );
..... doing something............
LOG.info( " Submitting job to JMS Q...." );
msgProducer.send( message, jmsConnectInfo );
//test code for the receiver to see if sent messages are received by receiver
//WildFlyJmsQueueReceive receiver = new WildFlyJmsQueueReceive();
//receiver.receiveMessagesFromQueue();
}
catch ( Exception e )
{
String msg = "Error in JobRunnerServiceImpl.submitJob";
LOG.error(msg,e);
throw new RuntimeException(msg,e);
}
}
private String logClientFile( String fileName, String fileType, String fileExt, long clientId, List<ToolkitPropertyBean> tpList )
{
ApplicationEnvironment enviro;
try
{
..... doing something............
//insert record in FILE_META_DATA table
FileMetaDataBean fileMetdataBean = new FileMetaDataBean(fileId, new Long(fileTypeID), fileName, fbFilePickUpDir +java.nio.file.FileSystems.getDefault().getSeparator()+ currentFile.getName(), receivedDate,new Long( FileUtilities.getRecordCount( currentFile ) ).longValue(), clientId);
Long id = logTransactionFileUpload(fileMetdataBean);
return null;
}
catch ( Exception e )
{
String msg = "Inside JobRunnerServiceImpl.logClientFile - Unable to log client file";
LOG.error(msg,e);
throw new RuntimeException(msg,e);
}
}
private Long logTransactionFileUpload(FileMetaDataBean bean)
{
return (Long)fileMetaDataDAO.save(bean);
}
}
My bean :
@Entity
@Table(name="FILE_META_DATA", schema = "OAP_META_OWNER", uniqueConstraints = {
@UniqueConstraint(columnNames = "file_meta_data_id"),
})
//@SequenceGenerator(name="file_meta_seq", sequenceName="file_meta_seq")
public class FileMetaDataBean implements Serializable
{
private long fileMetaDataId;
private Long fileType;
private String fileName;
private String originaFileName;
private Date receivedDt;
private Long recordCount;
private Long clientId;
public FileMetaDataBean(){}
public FileMetaDataBean( long fileMetaDataId, Long fileType, String fileName, String originaFileName, Date receivedDt,
long recordCount, long clientId )
{
super();
this.fileMetaDataId = fileMetaDataId;
this.fileType = fileType;
this.fileName = fileName;
this.originaFileName = originaFileName;
this.receivedDt = receivedDt;
this.recordCount = recordCount;
this.clientId = clientId;
}
@Id
// @GeneratedValue(strategy = GenerationType.AUTO, generator = "file_meta_seq")
@Column(name = "file_meta_data_id", unique = true, nullable = false)
public long getFileMetaDataId()
{
return fileMetaDataId;
}
public void setFileMetaDataId( long fileMetaDataId )
{
this.fileMetaDataId = fileMetaDataId;
}
@Column(name = "file_type_id", unique = false, nullable = false)
public Long getFileType()
{
return fileType;
}
public void setFileType( Long fileType )
{
this.fileType = fileType;
}
@Column(name = "file_name", unique = false, nullable = false)
public String getFileName()
{
return fileName;
}
public void setFileName( String fileName )
{
this.fileName = fileName;
}
@Column(name = "original_file_name", unique = false, nullable = false)
public String getOriginaFileName()
{
return originaFileName;
}
public void setOriginaFileName( String originaFileName )
{
this.originaFileName = originaFileName;
}
@Column(name = "received_dt", unique = false, nullable = false)
public Date getReceivedDt()
{
return receivedDt;
}
public void setReceivedDt( Date receivedDt )
{
this.receivedDt = receivedDt;
}
@Column(name = "record_count", unique = false, nullable = false)
public Long getRecordCount()
{
return recordCount;
}
public void setRecordCount( Long recordCount )
{
this.recordCount = recordCount;
}
@Column(name = "client_id", unique = false, nullable = false)
public Long getClientId()
{
return clientId;
}
public void setClientId( Long clientId )
{
this.clientId = clientId;
}
}
The DAO interface
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.hibernate.SessionFactory;
import org.springframework.transaction.annotation.Transactional;
public interface IGenericDAO< Entity extends Serializable, ID extends Serializable >
{
Entity getById( ID id );
List<Entity> getAll();
List<Entity> getAll( String contraints);
List<Entity> search( Map<String, Object> parms );
ID save( Entity entity );
void saveOrUpdate( Entity entity );
void update( Entity entity );
void delete( Entity entity );
void deleteById( ID id );
void setSessionFactory( SessionFactory sessionFactory );
void setEntity( final Class clazz );
}
The DAO impl:
@SuppressWarnings(value = "unchecked")
public class GenericDAOImpl<Entity extends Serializable, ID extends Serializable>
implements IGenericDAO<Entity, ID> {
protected Class<Entity> clazz;
public GenericDAOImpl(Class<Entity> clazz) {
System.out.println(this.getClass().getSimpleName() + " called");
this.clazz = clazz;
}
@Autowired
@Qualifier("sessionFactory")
protected SessionFactory sessionFactory;
@Override
public Entity getById(ID id) {
System.out.println("GenericHibernateDAO.getById called with id: " + id);
return (Entity) getCurrentSession().get(clazz, id);
}
@Override
public List<Entity> getAll() {
System.out.println("GenericHibernateDAO.getAll called");
return getCurrentSession().createCriteria(clazz.getName()).list();
// return getCurrentSession().createQuery("from " + clazz.getName()).list();
}
@Override
public List<Entity> getAll(String contraints) {
System.out.println("GenericHibernateDAO.getAll called. Constraint : " + contraints);
return getCurrentSession().createQuery("from " + clazz.getName() + " " + contraints ).list();
}
@Override
public List search(Map<String, Object> parms) {
Criteria criteria = getCurrentSession().createCriteria(clazz);
for (String field : parms.keySet()) {
criteria.add(Restrictions.ilike(field, parms.get(field)));
}
return criteria.list();
}
@Override
public ID save(Entity entity) {
Serializable id = null;
try
{
id = getCurrentSession().save(entity);
}
catch(RuntimeException e)
{
throw e;
}
// getCurrentSession().flush();
// getCurrentSession().getTransaction().commit();
return (ID)id;
}
@Override
public void saveOrUpdate(Entity entity) {
getCurrentSession().saveOrUpdate(entity);
getCurrentSession().flush();
getCurrentSession().getTransaction().commit();
}
@Override
public void update(Entity entity) {
getCurrentSession().update(entity);
getCurrentSession().flush();
getCurrentSession().getTransaction().commit();
}
@Override
public void delete(Entity entity) {
getCurrentSession().delete(entity);
getCurrentSession().flush();
getCurrentSession().getTransaction().commit();
}
@Override
public void deleteById(ID id) {
delete(getById(id));
}
protected Session getCurrentSession() {
// return sessionFactory.openSession();
return sessionFactory.getCurrentSession();
}
@Override
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public void setEntity(final Class clazz) {
this.clazz = clazz;
}
}
You can use the
noRollbackFor
property of Transactional annotation something like e.g. @Transactional(noRollbackFor=SendMsgFailureException.class)
. You need to handle the exception of the parent caller method for which you indent not to rollback.