Spring @ transactional transaction failure scenario? How to solve it?

In project development, if multiple table operations are involved, transaction mechanism will be adopted to ensure the consistency of business data;

However, many small partners may just have a brief understanding. Once they encounter transaction failure, they will have no way to start. This article summarizes the common scenarios of Spring transaction failure, hoping to avoid stepping on the pit in the development process as much as possible, resulting in a waste of time and energy.

catalogue

1. Failure scenario

2. Solution

1. Non public permission modification

2. Non Spring container managed bean s

3. Annotation decorated methods are called by methods inside the class

4. The exception type is not RuntimeException

5. After an exception is caught, no exception is thrown

6. Transaction propagation behavior setting exception

7. The database storage engine does not support transactions

1. Failure scenario

  1. @The method of Transactional configuration is not public permission modification;

  2. @The class of Transactional is not a bean managed by Spring container;

  3. @In the class of Transactional, the annotation modified method is called by the internal method of the class;

  4. The exception type thrown by the business code is not RuntimeException, and the transaction is invalid;

  5. When there are exceptions in the business code, try... Catch... Statement block is used to catch, and the catch statement block has no throw new runtimeException exception; (the most difficult problem to find and easy to ignore)

  6. The value of Propagation attribute in annotation @ Transactional is set incorrectly, i.e. Propagation NOT_ Supported (this kind of Propagation mechanism will not be set generally)

  7. If the mysql relational database and the storage engine is MyISAM instead of InnoDB, the transaction will not work (hidden most, but not encountered in basic development);

2. Solution

2.1. Non public permission modification

When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.

When you apply the visibility of the proxy to the public method, you should only use the @ Transactional method. If protected, private, or package visible methods are annotated with @ Transactional annotations, no errors are raised, but annotated methods do not display the configured transaction settings. If you need to annotate non-public methods, consider using AspectJ (see below).

@Transactional can only be used on public methods, otherwise the transaction will not fail. If it is used on non-public methods, you can turn on AspectJ proxy mode.

2.2 non Spring container managed bean s

Based on this failure scenario, bosses with work experience basically will not have such mistakes@ Service annotation, StudentServiceImpl class will not be managed by Spring container, so even if the method is modified by @ Transactional annotation, the transaction will not take effect.

Examples of errors:

import org.springframework.stereotype.Service;

@Service
public interface AreaService {

    //Add region
	public int addArea(Area area);
}
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

public class AreaServiceImpl implements AreaService {

	@Autowired
	private AreaDao areaDao;

    //Transactions here will not take effect
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public int addArea(Area area) {
		areaDao.insert(area);
	}

}

Correct example:

public interface AreaService {

    //Add region
	public int addArea(Area area);
}


/****************************************Separation line***********************************/


import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service    //Spring container managed bean s
public class AreaServiceImpl implements AreaService {

	@Autowired
	private AreaDao areaDao;

    //The transaction here will take effect
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public int addArea(Area area) {
		areaDao.insert(area);
	}

}

2.3. The annotation modified method is called by the internal method of the class

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service    
public class AreaServiceImpl implements AreaService {

	@Autowired
	private AreaDao areaDao;

    public int check(Area area) {
		addArea(area);
	}

    //Transactions here will not take effect
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public int addArea(Area area) {
		areaDao.insert(area);
	}


}

2.4. Exception type: non RuntimeException

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service    
public class AreaServiceImpl implements AreaService {

	@Autowired
	private AreaDao areaDao;


    //Transactions here will not take effect
    @Transactional(propagation = Propagation.REQUIRED)
	public int addArea(Area area) {
		areaDao.insert(area);

        //Throw non RuntimeException type
        throw new Exception();
	}


}

Solution:

@The method modified by Transactional annotation, plus the value of rollbackfor attribute, specifies the rollback exception type: @ Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)

2.5. After catching the exception, the exception is not thrown

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service    
public class AreaServiceImpl implements AreaService {

	@Autowired
	private AreaDao areaDao;


    //Transactions here will not take effect
    @Transactional(propagation = Propagation.REQUIRED)
	public int addArea(Area area) {
		try {
           areaDao.insert(area);
        } catch (Exception e) {
            e.printStackTrace();
        }
	}


}

2.6. Abnormal setting of transaction propagation behavior

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service    
public class AreaServiceImpl implements AreaService {

	@Autowired
	private AreaDao areaDao;


    //Transactions here will not take effect
    @Transactional(propagation = Propagation.NOT_SUPPORTED,rollbackFor = Exception.class)
	public int addArea(Area area) {
		try {
           areaDao.insert(area);
        } catch (Exception e) {
            e.printStackTrace();
        }
	}


}

2.7. The database storage engine does not support transactions

Take MySQL relational data as an example. If its storage engine is set to MyISAM, the transaction fails because MyISMA engine does not support transaction operations;

Therefore, to make the transaction effective, you need to set the storage engine to InnoDB; At present, MySQL starts from version 5.5.5. The default storage engine is InnoDB;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Keywords: Java Spring

Added by alcoholic1 on Sat, 19 Feb 2022 07:06:20 +0200