Trying to query data from legacy database (with different datasource) to current database, but got two exceptions in two scenarios.
I've got an implementation like this:
class A {
#PersistenceContext(unitName = "EPU")
EntityManager schemaEntityManager;
#PersistenceContext(unitName = "ELegacyPU")
EntityManager oldSchemaEntityManager;
void init() {
queryFromDatabase();
// check if it is empty, if true then query from legacy
queryFromLegacyDatabase();
recreateLegacyInCurrentDatabase();
}
List<E> queryFromDatabase() {
// query from schemaEntityManager
}
List<ELegacy> queryFromOldDatabase() {
// query from oldSchemaEntityManager
}
void recreateLegacyInCurrentDatabase() {
// records -> schemaEntityManager.merge()
}
}
While I'm trying to run this with #Translational over recreateLegacyInCurrentDatabase method, then got exception from this method (cannot found any valid info over hibernate's TRACE log-level):
javax.persistence.TransactionRequiredException: WFLYJPA0060: Transaction is required to perform this operation (either use a transaction or extended persistence context)
at org.jboss.as.jpa#24.0.0.Final//org.jboss.as.jpa.container.AbstractEntityManager.transactionIsRequired(AbstractEntityManager.java:880)
at org.jboss.as.jpa#24.0.0.Final//org.jboss.as.jpa.container.AbstractEntityManager.merge(AbstractEntityManager.java:567)
While I'm trying to run this with #Translational over only class or over only queryFromDatabase/queryFromOldDatabase method or over any of this two cases + recreateLegacyInCurrentDatabase, then got exception from queryFromOldDatabase (cannot found any valid info over hibernate's TRACE log-level):
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not prepare statement
at org.hibernate#5.3.20.Final//org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate#5.3.20.Final//org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1575)
at org.hibernate#5.3.20.Final//org.hibernate.query.Query.getResultList(Query.java:132)
at org.hibernate#5.3.20.Final//org.hibernate.query.criteria.internal.compile.CriteriaQueryTypeQueryAdapter.getResultList(CriteriaQueryTypeQueryAdapter.java:74)
...
Caused by: org.hibernate.exception.GenericJDBCException: could not prepare statement
...
Caused by: java.sql.SQLException: IJ031070: Transaction cannot proceed: STATUS_MARKED_ROLLBACK
I use JTA configured under persistence.xml & trying not to use RESOURCE_LOCAL instead of this or there is no option to do this without RESOURCE_LOCAL configuration in persistence.xml?
Related
in updateUser method: If an exception occurs when calling one of the macro services (like : updateUserContact,updateAccountContact), the updateUser operation must be rollback.
How do I perform a transaction operation to create, update and delete manually in Java?
In the creation method, when an event exception occurs, I delete the related records.
But I do not know what to do in the update and delete.
if invoke userContactStub.grpcUpdate has Exception , i must rollback userAcount.
Does anyone have any suggestions about the rollback transaction in the update ?
I use jpa, grpc(To connect micro services),springBoot.
each micro service has a datasource.
//updateUser
AdminUser adminUser = findById();
adminUser.setFirstName(adminUserModel.getFirstName());
adminUser.setLastName(adminUserModel.getLastName());
adminUser.setPassword(PasswordEncoderGenerator.generate(adminUserModel.getPassword()));
adminUser.setUsername(adminUserModel.getUsername());
adminUser.setDateOfBirth(CalendarTools.getDateFromCustomDate(adminUserModel.getDateOfBirth()));
adminUser.setGender(etcItemService.findByIdAndCheckEntity(adminUserModel.getGender_id(), GenderEnum.class,null,true));
adminUser = adminUserRepository.save(adminUser);
//update userAcount For Admin
//call grpcUpdate
this.userAcountStub.grpcUpdate(createRequestModel);
//update UserContact For Admin
//call grpcUpdate
this.userContactStub.grpcUpdate(createRequestModel);
adminUserModel.setId(adminUser.getId());
return adminUserModel;
What framework are you using? Are u using JPA?
Assume you are using JPA, you don't have to worry about it. JPA shell pretty much guarantee your data integrity if exception occurred (usually it rollback manually).
However I am not sure about how to rollback a database translation if one of the micoservice you called has thrown an exception.
if you are using JPa (hibernate?), you can simply add #Transactional annotation for rollback on top of create , update methods etc. İt handles this job and solves the problem.
try(Connection conn = DriverManager.getConnection(dbURL,dbUser,dbPassword);){
conn.setAutoCommit(false);
// perform operations such as insert, update, delete here
// ..
// if everything is OK, commit the transaction
conn.commit();
} catch(SQLException e) {
// in case of exception, rollback the transaction
conn.rollback();
}
I've been asked to write some coded tests for a hibernate-based data access object.
I figure that I'd start with a trivial test: when I save a model, it should be in the collection returned by dao.getTheList(). The problem is, no matter what, when I call dao.getTheList(), it is always an empty collection.
The application code is already working in production, so let's assume that the problem is just with my test code.
#Test
#Transactional("myTransactionManager")
public void trivialTest() throws Exception {
...
// create the model to insert
...
session.save(model);
session.flush();
final Collection<Model> actual = dao.getTheList();
assertEquals(1, actual.size());
}
The test output is expected:<1> but was:<0>
So far, I've tried explicitly committing after the insert, and disabling the cache, but that hasn't worked.
I'm not looking to become a master of Hibernate, and I haven't been given enough time to read the entire documentation. Without really knowing where to start, this seemed like this might be a good question for the community.
What can I do to make sure that my Hibernate insert is flushed/committed/de-cached/or whatever it is, before the verification step of the test executes?
[edit] Some additional info on what I've tried. I tried manually committing the transaction between the insert and the call to dao.getTheList(), but I just get the error Could not roll back Hibernate transaction; nested exception is org.hibernate.TransactionException: Transaction not successfully started
#Test
#Transactional("myTransactionManager")
public void trivialTest() throws Exception {
...
// create the model to insert
...
final Transaction firstTransaction = session.beginTransaction();
session.save(model);
session.flush();
firstTransaction.commit();
final Transaction secondTransaction = session.beginTransaction();
final Collection<SystemConfiguration> actual = dao.getTheList();
secondTransaction.commit();
assertEquals(1, actual.size());
}
I've also tried breaking taking the #Transactional annotation off the test thread and annotating each of 2 helper methods, one for each Hibernate job. For that, though I get the error: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here.
[/edit]
I think the underlying DBMS might hide the change to other transactions as long as the changing transaction is not completed yet. Is getTheList running in an extra transaction? Are you using oracle or postgres?
I'm trying to test my hibernate mapping based on a set of given JUnit tests. The following test however fails.
#Test
public void testEntity3Constraint() {
expectedException.expect(PersistenceException.class);
expectedException.expectCause(isA(ConstraintViolationException.class));
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
// Entity #3
IUplink ent3_1 = daoFactory.getUplinkDAO().findById(testData.entity3_1Id);
ent3_1.setName(TestData.N_ENT3_2);
em.persist(ent3_1);
em.flush();
} finally {
tx.rollback();
}
}
This is the exception I'm getting:
Expected: (an instance of javax.persistence.PersistenceException and exception with cause is an
instance of org.hibernate.exception.ConstraintViolationException)
but: exception with cause is an instance of org.hibernate.exception.ConstraintViolationException cause
<org.hibernate.PersistentObjectException: detached entity passed to persist: dst.ass1.jpa.model.impl.UplinkImpl>
is a org.hibernate.PersistentObjectException
As you can see The Constraint Violations and Persistence Exceptions are swapped in terms of instance and cause. The exception is thrown when I'm calling entitymanager.persist. How can I obtain the expected exception?
I cannot change the expected exception and nor do I want to. I need to find a way to get the exception expected by the test.
Thanks in advance!
You are expecting javax.persistence.PersistenceException
but get a similar yet different org.hibernate.PersistentObjectException.
Just change the Exception you expect in your test.
I spotted an odd behavior in HSQL, it seems when using database transactions database contraints are not checked during SQL inserts but during SQL commits and when a transaction it is rollbacked they are not checked at all.
I have a Spring integration test:
#RunWith(SpringJUnit4ClassRunner.class)
#TransactionConfiguration(defaultRollback=true, transactionManager="transactionManager")
#Transactional
public class IntegrationTest {
with a test that creates a new entity instance and calls Hibernate's persist on it.
It works fine, however when I change defaultRollback to false it fails:
Caught exception while allowing TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener#517a2b0] to process 'after' execution for test: method [public void MyIntegrationTest.test()], instance [MyIntegrationTest#546e61d5], exception [null]
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.springframework.orm.hibernate4.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:161)
at org.springframework.orm.hibernate4.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:681)
at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:563)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
...
Caused by: java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: NOT NULL check constraint; SYS_CT_10120 table: MYTABLE column: MYCOLUMN
This seems to be correct, because indeed my code did not set the mycolumn atttribute in the entity before calling persist on it.
Questions:
why database contraints are not checked during inserts but during commits?
why when doing a rollback database contraints are not checked?
[Posting #a_horse_with_no_name's answer, just to be able to close this question].
My ORM (Hibernate) was not sending queries to the database until a commit. If a transaction ended with a rollback the queries were not sent to the database at all. Making sure flush() is called (FlushMode.ALWAYS) after every persis() fixed the issue.
#Transactional
public void start() {
...
...
int result = entityManager
.createQuery("update Users set name=" + value + " where user.id=5").executeUpdate();
.....
}
Above code gives javax.persistence.TransactionRequiredException exception.
Update database in the middle of the transaction, possible ?
Any suggestions ?
Thanks.
A.
I just wonder if
This is a runtime exception which is thrown by the persistence provider when a transaction is required but is not active. A transaction is required because the start method is annotated as transactional. To get rid of the exception, you'll have to investigate why the line is called out of a transaction context.
A database update may be possible during a (different) transaction. Depends on the tables that are locked by the active transaction and on the transaction strategy. But in this case, it looks like you need to activate a transaction before you enter the start method.
With JPA you'd do something like this:
em = emf.createEntityManager();
tx = em.getTransaction();
tx.begin(); // now a transaction is active
start(); // call your method
// call other methods...
tx.commit(); // now the update is actually done
em.close();
Note - this is close to pseudo code, exception handling is missing in this example.