当前位置: 首页 > 知识库问答 >
问题:

带线程池的Spring JPA事务

周健
2023-03-14

我试图理解为什么下面的代码片段不能像预期的那样工作。

我已经有id=1234和name=A1的客户,我正在创建2个可调用的任务,并要求他们执行跨国更新方法

这两个事务一起运行(在从数据库中读取客户副本(如代码所示)后,我引入了1秒的延迟),并使用id=1234和name=A1读取原始客户

一个尝试从A1-更新名称-

我期望至少有一个事务抛出提交冲突/陈旧的数据异常,但在下面的情况下,两个都成功了。

你能帮我理解一下吗?我在概念上遗漏了什么吗?

主要的JAVA

    @Autowired
    CustomerService service;

    // Update address from A1 to A2
    Callable<String> t1 = new Callable<String>() {

        @Override
        public String call() throws Exception {
            service.updateCustomer("1234", "A2");
            return "T1 Done";
        }
    };

    // Update address from A1 to A3
    Callable<String> t2 = new Callable<String>() {

        @Override
        public String call() throws Exception {
            service.updateCustomer("1234", "A3");
            return "T2 Done";
        }
    };

    ExecutorService executorService = Executors.newFixedThreadPool(2);
    executorService.invokeAll((Collection) Arrays.asList(t1, t2));

客户ervice.java

@Transactional
public void updateCustomer(String customerId, String customerName) {
    try {
        Optional<Customer> currentCopyHandle = repo.findById(customerId);
        Customer currentCopy = currentCopyHandle.get();

        Thread.sleep(1000);

        ObjectMapper mapper = new ObjectMapper();

        String customerDetails = currentCopy.getDetails();

        ObjectNode writableDetails = (ObjectNode) mapper.readTree(customerDetails);
        writableDetails.put("name", customerName);

        currentCopy.setDetails(mapper.writeValueAsString(writableDetails));

        repo.save(currentCopy);

    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

编辑-1客户。JAVA

这是一个与Oracle 12c兼容的POJO,其中名为details的字段标记为@Lob,oracle12c表具有json约束

@Entity
public class Customer {

@Id
@javax.persistence.Id
private String cid;

@Lob
private String details;

public Customer() {
}

@PersistenceConstructor
public Customer(String cid, String details) {
    super();
    this.cid = cid;
    this.details = details;
}

public String getCid() {
    return cid;
}

public void setCid(String cid) {
    this.cid = cid;
}

public String getDetails() {
    return details;
}

public void setDetails(String details) {
    this.details = details;
}
}

在我开始这个练习之前,我做了以下活动。

String json = "{ \"cid\" : \"1234\", \"name\" : \"A1\", \"address\" : \"India\"}";

service.saveCustomer1(new Customer("1234", json));

共有1个答案

席乐童
2023-03-14

谢谢你JBNizet!

通过在我的模型中添加@Version属性来使用乐观锁定解决了我的问题。

 类似资料:
  • 我正在尝试使用线程池开发一个java聊天服务器,但我不知道如何处理来自客户端的传入消息。我想将每个套接字连接保存在哈希图中,并将任务添加到线程池的队列中。但是,服务器如何知道何时从客户端接收消息而不实例化缓冲区读取器?

  • 接收到数据时回调此函数,发生在worker进程中。函数原型: function onReceive(swoole_server $server, int $fd, int $reactor_id, string $data); $server,swoole_server对象 $fd,TCP客户端连接的唯一标识符 $reactor_id,TCP连接所在的Reactor线程ID $data,收到的数

  • 本文向大家介绍JAVA 创建线程池的注意事项,包括了JAVA 创建线程池的注意事项的使用技巧和注意事项,需要的朋友参考一下 1、创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。创建线程池的时候请使用带ThreadFactory的构造函数,并且提供自定义ThreadFactory实现或者使用第三方实现。 2、线程池不允许使用Executors去创建,而是通过ThreadPoolExecut

  • 主要内容:一、MySql中的线程,二、主要方式,三、源码流程,四、总结一、MySql中的线程 在mysql中,每一个连接上来,就会分配给一个相关的THD数据类。在前面的分析中可以看到,连接器(Connectors)连接到的直接就是连接池,在连接池的线程处理中分为三部分,即一对一(一个连接对应一个线程),多对一(多个连接对应一个线程)和线程池(多对多)。 线程池和线程可以针对不同的具体场景来处理具体的事务,这样既兼顾了效率又提高了适应性,对于新手来说,这就是设计的一个

  • 本文向大家介绍jdk自带线程池实例详解,包括了jdk自带线程池实例详解的使用技巧和注意事项,需要的朋友参考一下 二、简介 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力,但频繁的创建线程的开销是很大的,那么如何来减少这部分的开销了,那么就要考虑使用线程池了。线程池就是一个线程的容器,每次只执行额定数量的线程,线程池就是用来管理这些额定

  • 主要内容:1 什么是Java 线程池,2 Java 线程池的优势,3 Java 线程池的应用场景,4 Java 线程池的例子1 什么是Java 线程池 Java线程池 表示一组正在等待作业并多次重复使用的工作线程。 如果是线程池,则会创建一组固定大小的线程。服务提供商从线程池中拉出一个线程并为其分配作业。作业完成后,线程再次包含在线程池中。 2 Java 线程池的优势 由于无需创建新线程,因此拥有更好的性能,可以节省时间。 3 Java 线程池的应用场景 在用户请求Servlet和JSP时,其中