首页 > 解决方案 > 如何在包含 spring-session-jdbc 时防止数据库在事务方法之外更新

问题描述

我对弹簧事务如何工作的行为有疑问。我不清楚如何正确实施它。仅当我包含依赖项时才会出现问题spring-session-jdbc

我有一个方法被注释为@Transactional(readonly=true)并返回实体的集合。从该方法接收到集合后,在调度之前,我将一些变量设置为不同的值,以不显示或更改它的表示。问题是,在发送输出后,数据库值会自动更新

总结一下这个问题,我创建了一个基本的 SpringBoot 2.2.6 项目,下面是内容。

客户.java

@Data
@Entity
@Table(name = "customers")
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private Integer age;
    private Integer batch;
    private String secret;

}

CustomerRepository.java

@Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {

    Page<Customer> findByBatch(Integer batchId, Pageable pagaable);
}

CustomerService.java 需要注意的是,在这个服务类中,方法用 注释@Transactional(readOnly = true)

@Service
public class CustomerService {

    @Autowired
    private CustomerRepository repo;

    @Transactional(readOnly = true)
    public Page<Customer> findAllCustomers() {

        Pageable pageable = PageRequest.of(0, 10);

        return repo.findByBatch(4, pageable);
    }
}

客户控制器.java

@Controller
public class CustController {

    @Autowired
    private CustomerService service;

    @GetMapping("/")
    public ResponseEntity<Page<Customer>> indexPath(Model model) {

        Page<Customer> customers = this.service.findAllCustomers();

        model.addAttribute("customers", customers);
        // setting null before sending to client
        // this is for demonstration purpose only
        customers.getContent().forEach(i -> i.setSecret(null));

        return ResponseEntity.ok(customers);
    }
}

pom.xml 中的依赖项

并填充下面的数据库是一些 SQL 插入语句。

CREATE TABLE IF NOT EXISTS `customers` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) DEFAULT NULL,
  `batch` int(11) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `secret` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM; // changed to InnoDB basedon @M.Deinum comment

INSERT INTO `customers` (`id`, `age`, `batch`, `name`, `secret`) VALUES (1, 94, 4, 'Ravi', '23423424234');
INSERT INTO `customers` (`id`, `age`, `batch`, `name`, `secret`) VALUES (2, 32, 4, 'Silva', '3424252432');
INSERT INTO `customers` (`id`, `age`, `batch`, `name`, `secret`) VALUES (3, 18, 4, 'Rahul', '322342424');

Github 中的示例项目

我将其创建为一个简单的项目,它重现了该问题并将其上传到 Github 的此 URL https://github.com/imuneer/sprintboot-db-issue中。

通过简单地注释掉spring-session-jdbcpom.xml 中的内容,使项目按预期工作;我在控制器中更新的任何值都没有修改实际的数据库值。但是当spring-session-jdbc未注释时,它的作用相反。

我在这里很困惑。

  1. 为什么添加spring-session-jdbc更改弹簧事务的行为
  2. 我是否首先遗漏了任何东西,因此程序在两种情况下的行为都不同?
  3. 还是我的理解有误?如果是这样,在修改到客户端之前保持集合与持久性上下文分离的正确方法是什么。

标签: hibernatespring-bootspring-transactionsspring-session

解决方案


推荐阅读