playframework1.2.3 save data into database without transaction - jpa

I cannot save my entity data into database without transaction.
I know PersistenceContextType.Extend, But I cannot success.
#NoTransaction
public class Application extends Controller {
public static void create(String body) {
// EntityTransaction tm = JPA.em().getTransaction();
if (!JPA.isEnabled()) {
System.out.println("JPA is not initialized");
}
EntityManager manager = JPA.entityManagerFactory.createEntityManager();
//manager.setFlushMode(FlushModeType.COMMIT);
manager.setProperty("org.hibernate.readOnly", false);
//new Customer("001").save();
if (!JPA.isInsideTransaction()) {
// manager.getTransaction().begin();
}
createContext(manager, false);
new Customer("001").save();
//manager.getTransaction().commit();
/*
* if (tm.equals(null)) { System.out.println("success"); }
*/
}
static void createContext(EntityManager entityManager, boolean readonly) {
if (JPA.local.get() != null) {
try {
JPA.local.get().entityManager.close();
} catch (Exception e) {
// Let's it fail
}
JPA.local.remove();
}
JPA context = new JPA();
context.entityManager = entityManager;
// context.readonly = readonly;
JPA.local.set(context);
}
}
I initialed the JPA by myself to prevent play from starting a transaction.
I want to save my data into database, but I get a TransactionRequiredException error.
I known that JPA operation need a transaction, but I want to know whether has a exception.

I am not really sure what you are trying to achieve here. It is best to let Play handle transactions. You will not be able to commit your changes without a transaction.
If you need more control as to when the transaction is commited you could use a utility method like:
public static void commit() {
if (JPA.em().getTransaction().getRollbackOnly()) {
JPA.em().getTransaction().rollback();
} else {
JPA.em().getTransaction().commit();
}
JPA.em().getTransaction().begin();
JPA.em().flush();
JPA.em().clear();
}

Related

The configured execution strategy 'RetryTransactionExecutionStrategy' does not support user initiated transactions

We wrote our own simple execution strategy to retry saving any data using our DbContext when it runs into a table lock timeout.
public class RetryTransactionExecutionStrategy : DbExecutionStrategy
{
public RetryTransactionExecutionStrategy() : base()
{
}
protected override bool ShouldRetryOn(Exception exception)
{
while (exception != null)
{
if (exception is MySqlException ex
&& ex.Number == 1205) // Deadlock error code
{
return true;
}
exception = exception.InnerException;
}
return false;
}
}
We register it by using the DbConfig class, in the same folder as the context class.
public class DbConfig : DbConfiguration
{
public DbConfig()
{
SetExecutionStrategy(MySqlProviderInvariantName.ProviderName, () => new RetryTransactionExecutionStrategy());
}
}
Now most regular usage of the context will use the retry execution strategy. However, transactions are a more special case. Microsoft mentions usage of them in their documentation, and tells the user to manually call the execution strategy, like this:
var executionStrategy = new RetryTransactionExecutionStrategy();
executionStrategy.Execute(() =>
{
using (PigDbAccountEntities pigDbAccountEntities = new PigDbAccountEntities())
{
using (var dbtransaction = pigDbAccountEntities.Database.BeginTransaction())
{
try
{
//work on some data
pigDbAccountEntities.SaveChanges();
//work on some more data
pigDbAccountEntities.SaveChanges();
//work on even more data
pigDbAccountEntities.SaveChanges();
dbtransaction.Commit();
isSaved = true;
}
catch (Exception ex)
{
dbtransaction.Rollback();
Logger.Instance.Log(LogLevel.ERROR, LogSource.DB, "error in AccountEntityManager.SaveApplicationUser", ex);
}
}
}
});
And yet we still get this error message:
The configured execution strategy 'RetryTransactionExecutionStrategy' does not support user initiated transactions. See http://go.microsoft.com/fwlink/?LinkId=309381 for additional information.
Any idea on what to do/check?

roll back all inserts if an exception occured

i am trying to persist multiple entities to database. but i need to roll back all inserts if one of them faces an exception. how can i do that?
here is what i did:
public class RoleCreationApplyService extends AbstractEntityProxy implements EntityProxy {
#Inject
#Override
public void setEntityManager(EntityManager em) {
super.entityManager = em;
}
#Resource
UserTransaction utx;
public Object acceptAppliedRole(String applyId, Role parentRole, SecurityContext securityContext) throws Exception {
utx.begin();
try {
FilterWrapper filter = FilterWrapper.createWrapperWithFilter("id", Filter.Operator._EQUAL, applyId);
RoleCreationApply roleCreationApply = (RoleCreationApply) getByFilter(RoleCreationApply.class, filter);
Role appliedRole = new Role();
appliedRole.setRoleUniqueName(roleCreationApply.getRoleName());
appliedRole.setRoleName(roleCreationApply.getRoleName());
appliedRole.setRoleDescription(roleCreationApply.getRoleDescription());
appliedRole.setRoleDisplayName(roleCreationApply.getRoleDisplayName());
appliedRole.setCreationTime(new Date());
appliedRole.setCreatedBy(securityContext.getUserPrincipal().getName());
Role childRole = (Role) save(appliedRole);
parentRole.setCreationTime(new Date());
parentRole.setCreatedBy(securityContext.getUserPrincipal().getName());
parentRole = (Role) save(parentRole);
RoleRelation roleRelation = new RoleRelation();
roleRelation.setParentRole(parentRole);
roleRelation.setChildRole(childRole);
RoleRelation savedRoleRelation = (RoleRelation) save(roleRelation);
PostRoleRelation postRoleRelation = new PostRoleRelation();
postRoleRelation.setPost(roleCreationApply.getPost());
postRoleRelation.setRoleRelation(savedRoleRelation);
ir.tamin.framework.domain.Resource result = save(postRoleRelation);
utx.commit();
return result;
} catch (Exception e) {
utx.rollback();
throw new Exception(e.getMessage());
}
}
}
and this is save method in AbstractEntityProxy class:
#Override
#ProxyMethod
public Resource save(Resource clientObject) throws ProxyProcessingException {
checkRelationShips((Entity) clientObject, Method.SAVE, OneToOne.class, ManyToOne.class);
try {
entityManager.persist(clientObject);
} catch (PersistenceException e) {
throw new ResourceAlreadyExistsException(e);
}
return clientObject;
}
but when an exception occures for example Unique Constraint Violated and it goes to catch block, when trying to execute utx.rollback() it complains transaction does not exist and so some entities will persist. but i want all to roll back if one fails.
PS: i don't want to use plain JDBC. what is JPA approach?

Two concurrent request were able to lock the same row in Postgres sql

when two concurrent request were made for the below code, both of the requests were able to acquire lock simultaneously and hence were able to execute the block of code
Sample code running in production:
Sample Code for reference :
//Starting point for the request
#Override
public void receiveTransferItems(String argumet1, String refernceId, List<Item> items, long messageId)
throws Exception {
ParentDTO parent = DAO.lockByReferenceid(referenceId);
if (parent == null) {
throw new Exception(referenceId + "does not exist");
}
updateData(parent);
for (Item item : items) {
receiveItem(td, td.getWarehouseId(), item.getItemSKU(), item.getItemStatus(), item.getQtyReceived(), messageId);
}
}
private void updateData(ParentDTO td) throws DropShipException {
//perform some logical processing and then execute update
DAO.update(td);
}
private void receiveItem(ParentDTO td, String warehouseId, String asin, String itemStatus, int quantity, long messageId)
throws Exception {
/**
* perform some logical processing
*
**/
//call is being made to another class to do the rest of the processing
service.receive(td, asin, quantity, condition, container, messageId);
}
#Override
public void receive(
ParentDTO parentDTO,
String asin,
int quantity,
Condition condition,
Container container,
long messageId,
DataAccessor accessor) throws Exception {
List<ChildDTO> childDTOs =
DAO.lockChildDTOItems(parentDTO.getReferenceId(), asin, condition,
CostInfoSource.MANIFEST);
List<ChildDTO> filterItems = DAO
.loadChildDTOItems(parentDTO.getReferenceId(), asin, condition.name());
long totalExpectedQuantity = getTotalExpectedQuantity(filterItems);
long totalReceivedQuantity = getTotalReceivedQuantity(filterItems);
int quantityNormalReceived = 0;
for (ChildDTO tdi : childDTOs) {
int quantityReceived = 0;
if (asinDropShipMsgAction != null) {
quantity -= asinDropShipMsgAction.getInitialQuantity();
quantityNormalReceived += asinDropShipMsgAction.getInitialQuantity();
} else {
quantityReceived = new DBOperationRunner<Integer>(accessor.getSessionManager()) {
#Override
protected Integer doWorkAndReturn() throws Exception {
return normalReceive(tdi, quantityLeft, container, MessageActionType.TS_IN, messageId);
}
}.execute();
}
}
}
private int normalReceive(final ChildDTO childDTO,
int quantity,
final Container container,
final MessageActionType type,
long messageId)
throws Exception {
/**
* perform some business logic
*
* */
DAO.update(childDTO);
return someQuantity;
}
Implementation for lockByReferenceId function:
#Override
public ParentDTO lockByReferenceId(String referenceId) {
Criteria criteria = getCurrentSession().createCriteria(ParentDTO.class)
.add(Restrictions.eq("referenceId", referenceId)).setLockMode(LockMode.UPGRADE_NOWAIT);
return (ParentDTO) criteria.uniqueResult();
}
Implementation of DBOperationRunner class :
public T execute() throws Exception {
T t = null;
Session originalSession = (Session) ThreadLocalContext.get(ThreadLocalContext.CURRENT_SESSION);
try {
ThreadLocalContext.put(ThreadLocalContext.CURRENT_SESSION, sessionManager.getCurrentSession());
sessionManager.beginTransaction();
t = doWorkAndReturn();
sessionManager.commit();
} catch (Exception e) {
try {
sessionManager.rollback();
} catch (Throwable t1) {
logger.error("failed to rollback", t1);
}
throw e;
} finally {
ThreadLocalContext.put(ThreadLocalContext.CURRENT_SESSION, originalSession);
}
return t;
}
Recently i observed one issue in production code in which two or more simultaneous requests were able to acquire lock on the same data at same time.
I am using hibernate and criteria as a DB framework and c3p0 as a connection pooling framework and Postgres as DB.
Note : This issue is intermittent and only observed for some random concurrent requests which is making it hard to debug.
I am unable to understand how two concurrent request were able to lock the same rows simultaneously. Can you please help me in identifying what is going wrong in this case?
Thanks in advance!!!!

Revert DbContext.Savechanges in case a second DbContext.Savechanges fail

I have the following code, which stores information in two different tables in the same method
public static async Task<Response> AddStockTransaction(StockTransactionsHeader header, List<StockTransactionsDetails> details)
{
using (DataContext dbContext = new DataContext())
{
try
{
dbContext.StockTransactionsHeader.Add(header);
await dbContext.SaveChangesAsync();
int hearderID = header.TransactionHeaderID;
foreach (var item in details)
{
item.TransactionHeaderID = hearderID;
}
dbContext.StockTransactionsDetails.AddRange(details);
await dbContext.SaveChangesAsync();
return new Response
{
IsSuccess = true
};
}
catch (Exception ex)
{
return new Response
{
IsSuccess = false,
Message = ex.Message
};
}
}
}
How can I do, in case there is an exception in the second SaveChanges () to revert the first one?
Once SaveChanges has been called, your datat is stored on your database. You should not call SaveChanges more than once in a call, unless you are willingly to persist the intermediate steps.
You can use a transaction scope to create managed transactions :
using (TransactionScope scope = CreateTransactionScope())
{
DoSomthing(context);
scope.Complete();
}
however, if the failure of the second part involves rolling back the first one, this means that both parts belong to the same transaction, therefore simply omitting the first SaveChanges would turn your code into a single transaction.
From my another awnser: You could use DbTransaction class.
private void TestTransaction()
{
var context = new MyContext(connectionString);
using (var transaction = context.Database.BeginTransaction())
{
try
{
// do your stuff
// commit changes
transaction.Commit();
}
catch
{
// 'undo' all changes
transaction.Rollback();
}
}
}

Migrating EJB 2.0 to EJB 3.x Web app forgets lower tier value

I'm currently trying to migrate an EAR Project
-The old Project-
EJB 2.0
Jboss 5.0.1
-New Project-
EJB 3.0
Wildfly 13.0.0Final
Its session beans which I have managed to create and I can call upon it. the logic in it self seems to work. The issues I'm having is one of the follow ups seems to forget what it was doing.
the current issue I'm seeing is the following:
In the Web application in an class we are creating an object of Another class which we then trigger its parent method. this parent method then calls upon a class with it self as an argument which then checks which type it is and then stars a session bean depending on what type. which then calls on the arguments function performExecute() in this function we call upon a Query and actually get the correct results, we then add the resultsets values to a private dto member. and then performExecute is done. and we are back at the web applications class and we then try to access the same dto member with a get function. this returns a nullpointer. I'm wondering if I've forgotten something in my session beans?
Old sessionbean:
public class TxNotSupportedCommandServerBean implements SessionBean {
SessionContext sessionContext;
public void ejbCreate() throws CreateException {}
public void ejbRemove() {
sessionContext = null;
}
public void ejbActivate() {}
public void ejbPassivate() {}
public void setSessionContext(SessionContext sessionContext) {
this.sessionContext = sessionContext;
}
public void executeCommand(TargetableCommand cmd) throws CommandException {
try {
cmd.performExecute();
}
catch (CommandException ex) {
throw ex;
}
}
}
The new one:
#Stateless
#Remote
#TransactionManagement(value=TransactionManagementType.CONTAINER)
#TransactionAttribute(value=REQUIRED)
public class TxNotSupportedCmdServerBean implements TxNotSupportedCmdServerRemote{
/**
* Default constructor.
*/
public TxNotSupportedCmdServerBean() {
// TODO Auto-generated constructor stub
}
public void executeCommand(TargetableCommand cmd) throws CommandException {
try {
cmd.performExecute();
}
catch (CommandException ex) {
throw ex;
}
}
}
Both these are in the EJB.Jar
the interface is implemented in the EJBClient.jar
The old Interface:
public interface TxNotSupportedCommandServerLocal extends EJBLocalObject {
public void executeCommand(TargetableCommand cmd) throws CommandException;
}
The new Interface:
public interface TxNotSupportedCmdServerRemote {
public void executeCommand(TargetableCommand cmd) throws CommandException;
}
Now here come s the next set of files that is also in the EJBClient.jar
TargetableCommand:
public abstract class TargetableCommand implements Command {
private boolean constraintViolated;
protected RequestContext requestContext;
protected String dataSourceName;
public TargetableCommand(RequestContext requestContext, String dataSourceName) {
this.requestContext = requestContext;
this.dataSourceName = dataSourceName;
}
public TargetableCommand(RequestContext requestContext) {
this.requestContext = requestContext;
}
public TargetableCommand(String dataSourceName) {
this.dataSourceName = dataSourceName;
}
public TargetableCommand() {
}
public void setConstraintViolated(boolean constraintViolated) {
this.constraintViolated = constraintViolated;
}
public boolean isConstraintViolated() {
return constraintViolated;
}
public abstract void performExecute() throws CommandException;
public void execute() throws CommandException {
CommandTarget.executeCommand(this);
}
}
Command:
public interface Command extends Serializable {
public void execute() throws CommandException;
}
The commented code is the old session beans.
CommandTarget:
public class CommandTarget {
public CommandTarget() {
}
/**
* Exekverar ett kommando i rätt miljö, t.ex. med eller utan transaktionshantering
* #param cmd TargetableCommand Kommandot som ska utföras
* #throws CommandException
*/
public static void executeCommand(TargetableCommand cmd) throws CommandException {
Context context = null;
try {
ServiceLocator sl = ServiceLocator.getInstance();
// if (cmd instanceof TxRequired) {
// TxRequiredCommandServerLocalHome cmdSrvHome = (TxRequiredCommandServerLocalHome) sl.getEJBLocalHome("TxRequiredCommandServer");
// TxRequiredCommandServerLocal cmdSrv = cmdSrvHome.create();
// cmdSrv.executeCommand(cmd);
// }
// else if(cmd instanceof TxNotSupported) {
// TxNotSupportedCommandServerLocalHome cmdSrvHome = (TxNotSupportedCommandServerLocalHome) sl.getEJBLocalHome("TxNotSupportedCommandServer");
// TxNotSupportedCommandServerLocal cmdSrv = cmdSrvHome.create();
// cmdSrv.executeCommand(cmd);
// }
// else {
// throw new CommandException("Cannot instanciate command server");
// }
//
System.out.println("CT: Inside commandTarget. about to diffrientate what instance");
context = JNDILookupClass.getInitialContext();
if (cmd instanceof TxRequired) {
System.out.println("CT: TxRequired");
TxRequiredCmdServerRemote cmdSrv = (TxRequiredCmdServerRemote)context.lookup(JNDILookupClass.getLookupName("TxRequiredCmdServerRemoteBean", TxRequiredCmdServerRemote.class.getName()));
cmdSrv.executeCommand(cmd);
}
else if(cmd instanceof TxNotSupported) {
System.out.println("CT: TxNotSupported");
System.out.println("CT: cmd: " + cmd.getClass());
TxNotSupportedCmdServerRemote cmdSrv = (TxNotSupportedCmdServerRemote)context.lookup(JNDILookupClass.getLookupName("TxNotSupportedCmdServerBean", TxNotSupportedCmdServerRemote.class.getName()));
cmdSrv.executeCommand(cmd);
}
else {
throw new CommandException("Cannot instanciate command server");
}
}
catch (CommandException ex) {
throw ex;
}
// catch (CreateException ex) {
// throw new CommandException(ex);
// }
//new catch
catch(NamingException ex) {
throw new CommandException(ex);
}
catch (ServiceLocatorException ex) {
throw new CommandException(ex);
}
}
}
Phew ...
Ok now that's the important parts from EJBClient. now onwards to the Web.war
I'm only pasting the part that actually runs and were it returns a nullpoint
public class ActionIdentitetKonsultCommand implements Command {
private static Logger logger = Logger.getLogger(ActionIdentitetKonsultCommand.class);
public ActionIdentitetKonsultCommand() {
}
public String execute(RequestContext requestContext) throws CommandException {
GetPersonByPersnrEJBCommand personCmd;
logger.info("execute()");
try {
UserBean user = (UserBean) requestContext.getSession().getAttribute("user");
String kstnr = requestContext.getParameter("kstnr");
//Tilldela konsultuppgifter
personCmd = new GetPersonByPersnrEJBCommand();
personCmd.setPersnr(user.getPersnr());
System.out.println("AI: Before execute DTO " + personCmd.dto);
personCmd.execute();
System.out.println("AI: After execute DTO " + personCmd.dto);
logger.info("person hamtad med personnummer (EJB):");
logger.info(personCmd.getPerson().toString());
So the personCmd.getPerson().tostring() is what causes the nullpointer. GetPersonByPersnrEJBCommand():
public class GetPersonByPersnrEJBCommand extends TargetableCommand implements TxNotSupported {
public PersonDTO dto;
private long persnr;
public GetPersonByPersnrEJBCommand() {
}
public void setPersnr(long persnr) {
this.persnr = persnr;
}
public PersonDTO getPerson() {
return this.dto;
}
public void performExecute() throws CommandException {
try {
QueryPersonByPersnrCommand cmd = new QueryPersonByPersnrCommand();
cmd.setPersnr(persnr);
cmd.execute();
if(cmd.next()){
this.dto = new PersonDTO();
System.out.println("GP: inside PerformExecute DTO: " + dto);
dto.setPersnr(cmd.getPersnr());
dto.setEfternamn(cmd.getEfternamn());
dto.setFornamn(cmd.getFornamn());
dto.setEpostAdress(cmd.getEpostAdress());
dto.setKonsult((cmd.getKonsult() == 1));
dto.setAnsvarig((cmd.getAnsvarig() == 1));
System.out.println("GP: Inside Perform Execute DTO: " + dto);
}
}
catch (DataAccessCommandException ex) {
System.out.println("GetPersonByPersnrEJBCommand.performExecute misslyckades " + ex.getMessage());
throw new CommandException(ex);
}
}
}
So that's it; I don't understand why it forgets it. when we do sysouts inside the last class we see that both the dto and the cmd has data in them, but once the function ends and we are back in the class that called on this the data is empty.
I'm suspecting its something to do with my session beans, I'm missing an property or something. because this code works with the old beans in the old JBOSS server. Hopefully someone can help me and others can learn from this as well as me.
I managed to solve this issue. Since the scope of the project is to get this to work. Its not a beautiful solution and with more time rewriting this would have been better. so onwards to the solution:
We need to change in both the bean, targetableCommand, CommandTarget and in the GetPersonByPersnrEJBCommand
TargetableCommand - add method:
public TargetableCommand execute(TargetableCommand cmd) throws CommandException
{
return CommandTarget.executeCommand(cmd);
}
CommandTarget - We change the method executeCommand to return a TargetableCommand, and make sure that after the bean is done we return that cmd.
public static TargetableCommand executeCommand(TargetableCommand cmd) throws CommandException {
Context context = null;
try {
context = JNDILookupClass.getInitialContext();
if (cmd instanceof TxRequired) {
TxRequiredCmdServerRemote cmdSrv = (TxRequiredCmdServerRemote)context.lookup(JNDILookupClass.getLookupName("TxRequiredCmdServerRemoteBean", TxRequiredCmdServerRemote.class.getName()));
cmd = cmdSrv.executeCommand(cmd);
}
else if(cmd instanceof TxNotSupported) {
TxNotSupportedCmdServerRemote cmdSrv = (TxNotSupportedCmdServerRemote)context.lookup(JNDILookupClass.getLookupName("TxNotSupportedCmdServerBean", TxNotSupportedCmdServerRemote.class.getName()));
cmd = cmdSrv.executeCommand(cmd);
}
else {
throw new CommandException("Cannot instanciate command server");
}
}
catch (CommandException ex) {
throw ex;
}
catch(NamingException ex) {
throw new CommandException(ex);
}
}
return cmd;
}
The bean - cange the method Execute command to return Targetablecommand
public TargetableCommand executeCommand(TargetableCommand cmd) throws CommandException {
try {
cmd = cmd.performExecute();
}
catch (CommandException ex) {
throw ex;
}
return cmd;
}
Then lastly to get it all to work I had to create a new method in the classes that needed to do the perform execute so in the GetPersonByPersnrEJBCommand class i created the method wf13Layer(); wich is a just an extra step:
public void wf13Layer() throws CommandException
{
GetPersonByPersnrEJBCommand tmp;
try{
tmp = (GetPersonByPersnrEJBCommand) execute(this);
dto = tmp.getPerson();
} catch (Exception ex) {
throw new CommandException(ex);
}
}
This is what i did to make it work. as i said its not a beautiful solution but it works. IT seems to be a combination that once we cross between the projects the scope vanishes. and to obtain it futher we need to layer it like this. I really hope this helps someone at some point since theres till alot of old code running around out there.
Kind regards
VeryTired