Transaction annotation in Spring@Transactional

Keywords: Database Attribute IntelliJ IDEA jvm

@Transactional attribute

  1. The @Transactional annotation can only be applied to public modifiers and will not work with other modifiers without error.
  2. @Transactional ly is typically added to an implementation class or implementation class method, not to an interface or interface method.
  3. @Transactional only rolls back transaction exceptions for unchecked exceptions; if checked exceptions do not roll back exceptions.
    • unchecked exceptions are typically errors or runtime exceptions
      • Error: A subclass of Throwable.The well-known VirtualMachineError is one of Error's subclasses, including StackOverflowError, OutOfMemoryError, and so on.
      • RuntimeException: A subclass of Exception, which is also a subclass of Throwable.Below RuntimeException are exceptions such as NPE, ClassCastException, and ArithmaticException, which are typically avoided by developers by carefully examining the code without being explicitly thrown or caught.
    • A checked exception is an exception in the compilation process
      • Other Exceptions: Subclasses of Exceptions other than RuntimeException, including FileNotFoundException, IOException, SQLException, etc. These exceptions are characterized by having to be thrown or caught by code or failing compilation.

@Transactional Valid Scenarios

  1. Write normally

    @Override
    @Transactional
    public int updateById(Employee employee, Integer empId) {
        return employeeMapper.updateById(employee, empId);
    }
    
  2. unchecked exception

    • RuntimeException

      @Override
      @Transactional
      public int updateByIdRuntimeException(Employee employee, Integer empId) {
          int effect = employeeMapper.updateById(employee, empId);
          System.out.println(1 / 0);
          return effect;
      }
      

      This method is called to execute the statement System.out.println (1/0); the arithmetic exception in the runtime exception (ArithmaticException) is thrown, the transaction is rolled back, and the data in the database is not changed.

    • OutOfMemoryError

      Write a class to make heap memory overflow

      public class HeapOOM {
      
          static class OOMObject {
          }
      
          public static void mockHeapOOM() {
              List<Object> objects = new ArrayList<>();
      
              while (true) {
                  objects.add(new OOMObject());
              }
          }
      }
      

      This class of static method, mockHeapOOM, can be called to continuously create and add OOMObject objects to an array. Objects that are strongly referenced by the array cannot be reclaimed by the GC, and the heap memory is quickly exhausted.

      @Override
      @Transactional
      public int updateByIdOOM(Employee employee, Integer empId) {
          int effect = employeeMapper.updateById(employee, empId);
          HeapOOM.mockHeapOOM();
          return effect;
      }
      

      Open the Edit Configuration for IntelliJ IDEA and configure the JVM parameters in the VM Options column for unit tests that call the updateByIdOOM method.

      -ea -Xmx10m -Xms5m  -XX:+HeapDumpOnOutOfMemoryError
      
      • -ea can turn on the assertion mechanism
      • -Xmx10m-Xms5m indicates that the maximum heap available value is 10M and the initial heap value is 5M
      • -XX:+HeapDumpOnOutOfMemoryError Print Heap Overflow Error Information

      Run the unit test method and the following error message is reported in the console:

      java.lang.OutOfMemoryError: GC overhead limit exceeded
      

      Looking at the database, the data was not changed, so the transaction rolled back normally at this time.

@Transactional Invalid Scenario

  1. checked exception

    @Override
    @Transactional
    public void updateByIdException(Employee employee, Integer empId) throws IOException {
        employeeMapper.updateById(employee, empId);
        throw new IOException("simulation IO error");
    }
    

    Calling this method throws a simulated error when throwing a new IOException (Simulated IO Error), but the transaction does not roll back and the data in the database changes.This is because IOException is a checked exception and @Transactional does not roll back transactions for checked exceptions by default.At this point, to roll back a transaction when a checked exception is thrown, you need to configure the rollBackFor property after @Transactionals:

    @Override
    @Transactional(rollbackFor = IOException.class)
    public void updateByIdException(Employee employee, Integer empId) throws IOException {
        employeeMapper.updateById(employee, empId);
        throw new IOException("simulation IO error");
    }
    

    This configuration is rollbackFor = Exception.class.

  2. Called by a method without transaction control

    If method A with @Transactionalis called by another method B without @Transactionally, A's @Transactionals will also fail when B is called.

    @Override
    @Transactional
    public int updateByIdRuntimeException(Employee employee, Integer empId) {
        int effect = employeeMapper.updateById(employee, empId);
        System.out.println(1 / 0);
        return effect;
    }
    
    @Override
    public int updateByIdWithoutTransactional(Employee employee, Integer empId) {
        return updateByIdRuntimeException(employee, empId);
    }
    
    

    At this point, when updateByIdWithoutTransactional is called, the data in the database will be changed because the transaction will not be rolled back because ArithmaticException is thrown in updateByIdRuntimeException.

81 original articles published. 326 won. 90,000 visits+
Private letter follow

Posted by The Wise One on Sat, 01 Feb 2020 18:12:33 -0800