Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transactional annotation not working in Spring Boot with jpa

I'm using Spring boot with jpa, mysql in my project. But @Transaction not working. It does not rollback all data if have any error Code given below. Any suggestions? Thanks.

Application:

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Entity Product:

@Entity
public class Product extends BaseModel<Long> {

    @Id
    @GeneratedValue
    private Long id;
    private String description;
    @OneToMany(mappedBy = "productId", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Speed> speeds;

    //geter and seter
}

Entity Speed:

@Entity
public class Speed extends BaseModel<Long> {

    @Id
    @GeneratedValue
    private Long id;
    private Long productId;
    private Long productSpeed;
    //Getter and setter
}

Repository:

public interface SpeedRepository extends JpaRepository<Speed, Long> {

}

public interface ProductRepository extends JpaRepository<Product, Long> {

}

Service:

@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private speedRepository speedRepository;

    @Transactional(rollbackFor = TestException.class)
    void saveProduct(Product product) throws TestException {
        try{
            productRepository.save(product);
            for (Speed speed : product.getSpeeds()) {
                speedRepository.save(speed);
            }
        } catch (TestException e) {
            throw new TestException("error", "error message");
        }
    }
}

Controller:

@RestController
@RequestMapping("/product")
public class ProductRestController {

    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private MachineSpeedRepository machineSpeedRepository;
    @Autowired
    private ProductService productService;

    @RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    Object addListProduct(OAuth2Authentication auth, @RequestBody Product product) throws TestException {
        productService.saveProduct(product);
        return product;
    }

}

application.properties:

spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=jdbc:mysql://192.168.1.111/test?useSSL=false
spring.datasource.username=root
spring.datasource.password=123456

build.gradle:

buildscript {
    ext {
        springBootVersion = '1.5.6.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'

version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}


dependencies {
    compile("org.springframework.security.oauth:spring-security-oauth2")
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.hibernate:hibernate-validator")
    compile 'org.springframework.boot:spring-boot-starter-data-jpa'
    compile 'mysql:mysql-connector-java'
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

Database:

CREATE TABLE `product` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `description` text NOT NULL COMMENT 'product name',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8


CREATE TABLE `speed` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `product_id` bigint(20) DEFAULT NULL,
  `product_speed` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8

How can i use transaction or configure correctly

like image 368
daivph Avatar asked Oct 18 '25 10:10

daivph


2 Answers

As @Kenny Tai Huynh said i suggest you to move the transaction to service layer (it's up to you though). Anyway it's possible that @Transactional is not being picked up because of the method visibility... try to change it to public and check if it works

like image 142
Zeromus Avatar answered Oct 19 '25 22:10

Zeromus


Thanks all, I set method saveProduct to public. It's working. There is no requirement for whether the @Transactional(rollbackFor = TestException.class) annotation should go on a Controller or on a Service

Service:

@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private speedRepository speedRepository;

    @Transactional(rollbackFor = TestException.class)
    public void saveProduct(Product product) throws TestException {
        try{
            productRepository.save(product);
            for (Speed speed : product.getSpeeds()) {
                speedRepository.save(speed);
            }
        } catch (TestException e) {
            throw new TestException("error", "error message");
        }
    }
}

Controller:

@RestController
@RequestMapping("/product")
public class ProductRestController {

    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private MachineSpeedRepository machineSpeedRepository;
    @Autowired
    private ProductService productService;

    @RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    Object addListProduct(OAuth2Authentication auth, @RequestBody Product product) throws TestException {
        productService.saveProduct(product);
        return product;
    }

}
like image 26
daivph Avatar answered Oct 20 '25 00:10

daivph



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!