background
Recently, a project in the company, using the SPRINGMVC framework, the database with MySQL, just started and did not join the transaction, after the business needs to be transacted.
problem Generation and resolution
Using transactions, directly asked Baidu, I chose the way of annotations.
Configure the transaction manager and driver in the configuration file:
<tx:annotation-driven transaction-manager= "TransactionManager"/> <bean id= "TransactionManager" class= "Org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name= " DataSource "> <ref bean=" DataSource "/> </property> </bean>
Then add annotations directly to the service layer
Package Com.my.service.impl;import Java.sql.sqlexception;import Org.springframework.beans.factory.annotation.autowired;import Org.springframework.stereotype.service;import Org.springframework.transaction.annotation.propagation;import Org.springframework.transaction.annotation.transactional;import Com.my.constants.serviceexception;import Com.my.dao.testdao;import Com.my.service.TestService; @Servicepublic class Testserviceimpl implements testservice{ @Autowired private Testdao Testdao; @Override @Transactional (readOnly = false, propagation = propagation.required, rollbackfor = { Serviceexception.class}) public int Insertuser (String userName) throws serviceexception { int id = 0; try { id = testdao.insertuser (userName), } catch (SQLException e) { throw new serviceexception (); } return ID; } }
Naturally, the rollback exception will be rolled back just as the service throws an exception.
Then I think the code is certainly not a problem, but many times after the debug to the database does not rollback, so directly in the code to add the error code int i = 5/0, and the capture of exception modified
Package Com.my.service.impl;import Java.sql.sqlexception;import Org.springframework.beans.factory.annotation.autowired;import Org.springframework.stereotype.service;import Org.springframework.transaction.annotation.propagation;import Org.springframework.transaction.annotation.transactional;import Com.my.constants.serviceexception;import Com.my.dao.testdao;import Com.my.service.TestService; @Servicepublic class Testserviceimpl implements testservice{ @Autowired private Testdao Testdao; @Override @Transactional (readOnly = false, propagation = propagation.required, rollbackfor = { Serviceexception.class}) public int Insertuser (String userName) throws serviceexception { int id = 0; try { id = testdao.insertuser (userName); int i = 5/0; } catch (Exception e) { throw new serviceexception ();
} return ID; } }
Debug multiple times with the code above and never roll back.
Then naturally think, maybe the DAO layer has a problem, then go to see the DAO layer code, there seems to really be a problem:
Package Com.my.dao.impl;import Java.sql.connection;import Java.sql.preparedstatement;import java.sql.SQLException; Import Org.springframework.beans.factory.annotation.autowired;import org.springframework.jdbc.core.JdbcTemplate; Import Org.springframework.jdbc.core.preparedstatementcreator;import Org.springframework.jdbc.support.generatedkeyholder;import Org.springframework.jdbc.support.keyholder;import Org.springframework.stereotype.repository;import Com.my.dao.TestDao; @Repositorypublic class Testdaoimpl implements Testdao {@Autowired private jdbctemplate jdbctemplate; @Override public int Insertuser (final string userName) throws SQLException {final String sql = "INSERT to use R (NAME) VALUES (?); "; Keyholder keyholder = new generatedKeyHolder (); Jdbctemplate.update (New PreparedStatementCreator () {public PreparedStatement createpreparedstatement (Connectio N con) throws SQLException {PreparedStatement PS = Jdbctem-plate.getdatasOurce (). getconnection (). preparestatement (SQL); Ps.setstring (1, userName); return PS; }}, Keyholder); Return Keyholder.getkey (). Intvalue (); }}
The error may be in the code yellow block. So debug in, see Connectioncon in the Autocommit attribute is false, obviously is the service layer of transaction management to, and Jdbctemplate.getdatasource (). Getconnection () is a re-acquired connection to the link pool, which is obviously not managed by the transaction, and its Autocommit property is obviously true, so this makes the service layer transaction not rollback, it is simple to change the code in the yellow block directly to the PreparedStatement PS = con.preparestatement (sql); it's ready.
Summary
Steps to resolve if you encounter a SPRINGMVC transaction that cannot be rolled back:
1. Check that the configuration file has not joined the transaction management configuration and driver;
2. Check whether the database supports transactions (such as MySql4.0 support transactions, ENGINE:INNODB);
3. Checks whether the code block throws an exception, and the rollback exception of the transaction is the parent class that throws an exception or throws an exception;
4. Check that all connection in the code block covered by the transaction are overwritten by this transaction (debug checks that all connection autocommit properties are changed to False by transaction).
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Spring @Transaction Configuration example and no rollback reason depth analysis