Alrighty folks. I've read quite a bit of docs. And at my wits end on why this is happening.
Like many of the other people, we have a service interfacing with a oracle db. This is a pretty standard setup
#Service
public class DaoService {
private JdbcTemplate jdbcTemplate;
private SimpleJdbcInsert insertA;
private SimpleJdbcInsert insertB;
private SimpleJdbcInsert insertC;
#Autowired
public Dao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
// Assume all Inserts are initialized
}
#Transactional(rollbackFor = Exception.class)
public void insertStuff(Stuff stuff) {
insertA.execute(stuff.A);
// Suppose a connection failed here
insertB.executeBatch(stuff.B);
insertC.executeBatch(stuff.C);
}
Now here lies our issue. For 99% of all rollbacks they are a-ok.
When a connection gets closed for unknown reasons is where our problems occur.
The exception message being
TransactionSystemException: Could not roll back JDBC transaction;
nested exception is java.sql.SQLException: "The connection is closed"
See, it tries to rollback as it's supposed to. But the issue is that stuffA lingers in the DB will stuffB and stuffC is not. This happens only like 1% of the time. (aka, sometimes despite the rollback failure, no 'stuff' will be in the DB.
Am I understanding something wrong? I thought spring only commits at the end of a successful transaction? Anyone have an idea on how I can stop these partial commits despite making in #Transactional?
p.s. for what it's worth. autocommit is defaulted to being on. However I read that it's not taken into consideration when something is #Transactional
From the Database JDBC Developer's Guide:
If the auto-commit mode is disabled and you close the connection without explicitly committing or rolling back your last changes, then an implicit COMMIT operation is run.
Maybe this is the case you are running into.
According to this answer, Spring only offers you an interface for transaction manager and the implementation may vary. However, most transaction manager implementations will turn off autocommit during an #Transactional call then return it to the previous state after commit.
That being said, on some databases there are ways to execute autonomous transactions inside an outer transaction that may not be visible to your application or to Spring. I know Oracle allows this. Have you checked all of the triggers on the tables? I worked on one application that had an audit trigger that would force orphaned data into some of the tables in situations like this. Can you tell us which database you are using?
try this :
#Transactional(propagation = Propagation.REQUIRES_NEW)
hope it will work
Related
In my spring application I am facing failed to acquire lock issue and transaction is getting failed. It is not even rollbacking the transaction as database is not providing the lock. How to tell a method to wait until the lock is acquired? I am using hibernate and mysql.
First of all, you have to use #Transactional as method/class annotation in the case of spring.
By default, we have the propagation REQUIRED #Transactional(propagation = Propagation.REQUIRED). Spring checks if there is an active transaction, then it creates a new one if nothing existed.
Here you can find the explanation of spring transaction propagations.
First, you have to take a look and analyze what you need there to use.
Please tell us, where do you face with lock issues?
Probably you have to deal with the Isolation levels; We can deal with them at mySql, hibernate or spring level.
Here we need to know where you have configurations for isolation (mySql, hibernate or spring).
You can check if you need to update the lock timeout, using QueryHints.
#QueryHints({#QueryHint(name = "javax.persistence.lock.timeout", value = "3000")})
public Optional<Customer> findById(Long customerId);
I am having trouble finding information about this issue I am running into. I am interested in implementing row level security on my Postgres db and I am looking for a way to be able to set postgres session variables automatically through some form of an interceptor. Now, I know that with hibernate you are able to do row-level-security using #Filter and #FilterDef, however I would like to additionally set policies on my DB.
A very simple way of doing this would be to execute the SQL statement SET variable=value prior to every query, though I have not been able to find any information on this.
This is being used on a spring-boot application and every request is expected to will have access to a request-specific value of the variable.
Since your application uses spring, you could try accomplishing this in one of a few ways:
Spring AOP
In this approach, you write an advice that you ask spring to apply to specific methods. If your methods use the #Transactional annotation, you could have the advice be applied to those immediately after the transaction has started.
Extended TransactionManager Implementation
Lets assume your transaction is using JpaTransactionManager.
public class SecurityPolicyInjectingJpaTransactionManager extends JpaTransactionManager {
#Autowired
private EntityManager entityManager;
// constructors
#Override
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
super.prepareSynchronization(status, definition);
if (status.isNewTransaction()) {
// Use entityManager to execute your database policy param/values
// I would suggest you also register an after-completion callback synchronization
// This after-completion would clear all the policy param/values
// regardless of whether the transaction succeeded or failed
// since this happens just before it gets returned to the connection pool
}
}
}
Now simply configure your JPA environment to use your custom JpaTransactionManager class.
There are likely others, but these are the two that come to mind that I've explored.
i'm working with spring jdbcTemplate in some desktop aplications.
i'm trying to rollback some database operations, but i don't know how can i manage the transaction with this object(JdbcTemplate). I'm doing multiple inserts and updates through a methods sequence. When any operation fails i need rollback all previous operations.
any idea?
Updated... i tried to use #Transactional, but the rolling back doesn't happend.
Do i need some previous configuration on my JdbcTemplate?
My Example:
#Transactional(rollingbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void Testing(){
jdbcTemplate.exec("Insert into table Acess_Level(IdLevel,Description) values(1,'Admin')");
jdbcTemplate.exec("Insert into table Acess_Level(IdLevel,Description) values(STRING,'Admin')");
}
The IdLevel is a NUMERIC parameter, so... in our second command will occur an exception. When i see the table in database, i can see the first insert... but, i think this operation should be roll back.
what is wrong?
JdbcTemplate doesn't handle transaction by itself. You should use a TransactionTemplate, or #Transactional annotations : with this, you can then group operations within a transaction, and rollback all operations in case of errors.
#Transactional
public void someMethod() {
jdbcTemplate.update(..)
}
In Spring private methods don't get proxied, so the annotation will not work. See this question: Does Spring #Transactional attribute work on a private method?.
Create a service and put #Transactional on the public methods that you want to be transactional. It would be more normal-looking Spring code to have simple DAO objects that each do one job and have several of them injected than it would to have a complicated DAO object that performed multiple SQL calls within its own transaction.
Good day, guys!
If I have non-transactional bean(BannerSizeServiceUntransact), which uses transactional bean(bannerSizeService), will Spring estabilish connection to DB, when I use non-transacional bean?
(I have many refused connections to PostgreSQL in log. I belive my logic does;t create new connection on each request, but may be I wrong.)
#Repository
public class BannerSizeServiceUntransactImpl implements BannerSizeServiceUntransact {
#Resource
BannerSizeService bannerSizeService;
public List<BannerSizeVO> sizesByType(String type) throws BannerServiceException{
return bannerSizeService.sizesByType(type);
} }
#Repository
#Transactional
public class BannerSizeServiceImpl implements BannerSizeService {
....
}
Yes, Spring will establish a database connection even when you're using beans that aren't marked #Transactional, so that's not the cause of your refused connections.
What's going to happen in this scenario is that when you invoke the call to bannerSizeService.sizesByType(type), Spring will start a new transaction, and when control returns to BannerSizeServiceUntransact.sizesByType(), it will end. So if BannerSizeServiceUntransact.sizesByType() did other database calls before or after the call to bannerSizeService.sizesByType(type), those calls would happen in separate transactions, one per DB call. (Not annotating a Service as #Transactional doesn't mean that transactions aren't used, just that they only span a single database call.)
Also note that if the method that calls BannerSizeServiceUntransact.sizesByType() was marked #Transactional, then the transaction started there will carry over all of the code you've shown here, because that transaction will start when that higher-up method is called and will end when it ends, and all of the code here will have executed while it was in effect. Not annotating something as #Transactional doesn't forbid its participation in an existing transaction, it just doesn't require the initiation of a new one.
Also, keep in mind that #Transactional controls transactions. Spring might end up making a new connection for each transaction it opens, or using only one and reusing it for each transaction, or rotating through a pool of connections (resulting in more than one but fewer than N connections for N transactions). It's guaranteed that if Spring talks to the database, there will be a connection in use, but you can't guarantee how many will be used over N calls simply by your #Transactional annotations. (Though of course you can set settings in your Spring config that might impact the number used, e.g. specifying a connection pool with a max size of 1.)
The following test cases are functionally working properly, but one of the test methods having to create a new article in the database doesn't rollback at the end of the test case execution.
I expect it to work that way. For a test case that update article actually rollbacks the update at the end of test case execution.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(value = "/applicationContext-test.xml")
#TransactionConfiguration(transactionManager = "txManager", defaultRollback = true)
#Transactional
public class PriceRepositoryTest {
#Resource(name ="repository")
private PriceRepository repository;
#Test
public void testGetAll() throws Exception {
Assert.assertEquals(8, repository.getAll().size());
}
#Test
#Rollback
public void shouldSaveNewArticle(){
Article article = new Article();
article.setName("Article");
article.setPrice(33);
repository.save(article);
Assert.assertEquals(9, repository.getAll().size());
}
#Test
#Rollback
public void shouldUpdateArticle(){
Article article = repository.getArticle(4);
article.setPrice(33);
repository.update(article);
Assert.assertEquals(String.valueOf(33.0), String.valueOf(repository.getArticle(4).getPrice()));
}
}
Is your DAO perhaps also marked with #Transactional? If it is, that's the problem: the transactionality on a different layer doesn't know about your local transaction configuration.
If repository.update(article) is #Transactional, it may or may not start a new transaction (depending on the value of the propagation attribute), but it will commit the transaction after execution, and there's nothing your test method can do to intercept that.
That's one of the reasons why transactions should be started on the service level, not the DAO level.
(If that's not the case, I humbly apologize)
I also encountered this issue and spent some hours trying to find the root cause. The issue was a variant of the problems described here. In my case, the application calls stored procedures through Spring, and one of these procedures contained a COMMIT statement.
Commits should always be controlled by the app, if there is a stray commit somewhere in a stored procedure, Spring can't control the transaction and tests won't roll back.
I just encountered this with my unit tests all set to rollback and my record was still showing up in the database after the test finished. The reason was there was that in the DAO a call to the entitymanager to flush() was in the method - which forced the transaction to commit.
em.persist(jpaServer);
em.flush(); //commits the record no matter what spring is setup to do
taking the flush out and confirmed no record. Tested the same code with the test annotated to #Rollback(false) and confirmed the record (proving the flush was not needed)
Ben
www.nimbits.com