Patty Patty - 18 days ago 13
Java Question

@Transactional : Is there a way that hibernate can persist child transacttion when parent fails

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;
}

}

Answer

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.

Comments