Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 关于弹簧J的一种预防方法——螺纹安全_Java_Multithreading_Hibernate_Spring Data_Spring Data Jpa - Fatal编程技术网

Java 关于弹簧J的一种预防方法——螺纹安全

Java 关于弹簧J的一种预防方法——螺纹安全,java,multithreading,hibernate,spring-data,spring-data-jpa,Java,Multithreading,Hibernate,Spring Data,Spring Data Jpa,我很好奇SpringJParepository方法是否是线程安全的,然后我阅读了stackflow文章()。从那里,我了解到存储库方法是线程安全的,然后我制作了一个POC来测试线程安全性。我让一个存储库说FormRepository来为“form”实体执行CRUD操作,这是对JpaRepository的扩展。从DAO中,我只需调用100个线程来创建表单对象,手动设置其id,然后保存“表单”对象 以下是参考代码:- @Repository public interface FormReposito

我很好奇SpringJParepository方法是否是线程安全的,然后我阅读了stackflow文章()。从那里,我了解到存储库方法是线程安全的,然后我制作了一个POC来测试线程安全性。我让一个存储库说FormRepository来为“form”实体执行CRUD操作,这是对JpaRepository的扩展。从DAO中,我只需调用100个线程来创建表单对象,手动设置其id,然后保存“表单”对象

以下是参考代码:-

@Repository
public interface FormRepository extends JpaRepository<Tbldynamicform, Long>     {

Tbldynamicform save(Tbldynamicform tblform);

@Query("SELECT max(tblform.formid) FROM Tbldynamicform tblform")
Optional<Integer> findMaxId();

}
......End of Repository above and start of DAO below...

@Component
public class DynamicFormDAO implements DynamicFormDAO {

@Inject
private FormRepository formRepository;

public void testThreadSafety() throws Exception {
    List<Callable<Integer>> tasks = new ArrayList<>(100);
    for (int i = 0; i < 100; i++) {

        tasks.add(() -> {
            try {

                Tbldynamicform tbldynamicform = new Tbldynamicform();//Set  all the required fields for form
                if (tbldynamicform.getFormid() == null)
                    tbldynamicform.setFormid(findFormID());
                Tbldynamicform form = formRepository.save(tbldynamicform);
                return form.getFormid();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        });
    }
    ExecutorService executor = Executors.newFixedThreadPool(100);
    executor.invokeAll(tasks);

}

private int findFormID() throws Exception {
    Optional<Integer> id = formRepository.findMaxId();
    if (id != null && id.isPresent() && id.get() != null) {
        int generatedId = id.get().intValue();
        return ++generatedId;
    }
    return 0;
}
}
@存储库
公共接口FormRepository扩展了JpaRepository{
Tbldynamicform保存(Tbldynamicform tblform);
@查询(“从Tbldynamicform tblform中选择最大值(tblform.formid))
可选的findMaxId();
}
……上面的存储库结束,下面的DAO开始。。。
@组成部分
公共类DynamicFormDAO实现DynamicFormDAO{
@注入
私有表单存储库表单存储库;
public void testThreadSafety()引发异常{
列表任务=新阵列列表(100);
对于(int i=0;i<100;i++){
任务。添加(()->{
试一试{
Tbldynamicform Tbldynamicform=新建Tbldynamicform();//设置表单的所有必需字段
if(tbldynamicform.getFormid()==null)
tbldynamicform.setFormid(findFormID());
Tbldynamicform form=formRepository.save(Tbldynamicform);
返回form.getFormid();
}捕获(例外e){
e、 printStackTrace();
}
返回null;
});
}
ExecutorService executor=Executors.newFixedThreadPool(100);
执行人。调用所有(任务);
}
private int findFormID()引发异常{
可选id=formRepository.findMaxId();
if(id!=null&&id.isPresent()&&id.get()!=null){
int generatedId=id.get().intValue();
return++generateId;
}
返回0;
}
}
当我这样做时,我假设事情必须正常工作,因为表单存储库方法是线程安全的,但不知何故,我在日志中多次遇到sql dataintegrityviolationexception,导致插入多条记录失败。以下错误供参考:-

@Repository
public interface FormRepository extends JpaRepository<Tbldynamicform, Long>     {

Tbldynamicform save(Tbldynamicform tblform);

@Query("SELECT max(tblform.formid) FROM Tbldynamicform tblform")
Optional<Integer> findMaxId();

}
......End of Repository above and start of DAO below...

@Component
public class DynamicFormDAO implements DynamicFormDAO {

@Inject
private FormRepository formRepository;

public void testThreadSafety() throws Exception {
    List<Callable<Integer>> tasks = new ArrayList<>(100);
    for (int i = 0; i < 100; i++) {

        tasks.add(() -> {
            try {

                Tbldynamicform tbldynamicform = new Tbldynamicform();//Set  all the required fields for form
                if (tbldynamicform.getFormid() == null)
                    tbldynamicform.setFormid(findFormID());
                Tbldynamicform form = formRepository.save(tbldynamicform);
                return form.getFormid();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        });
    }
    ExecutorService executor = Executors.newFixedThreadPool(100);
    executor.invokeAll(tasks);

}

private int findFormID() throws Exception {
    Optional<Integer> id = formRepository.findMaxId();
    if (id != null && id.isPresent() && id.get() != null) {
        int generatedId = id.get().intValue();
        return ++generatedId;
    }
    return 0;
}
}
org.springframework.dao.DataIntegrityViolationException:无法执行语句;SQL[n/a];约束[“PUBLIC.TBLDYNAMICFORM(FORMID)上的主键];SQL语句: 插入Tbldynamicform(clientid、copyfromexisting、creationdate、formdesc、formmode、formname、formtemplate、formtitle、procutype、status、formid)值(?、?、?、

这让我思考这是线程安全问题还是其他问题?据我所知,我在dao中创建的所有“tbldynamicform”对象都将保留在线程堆栈上。只有formRepository将位于堆存储上,如果formRepository方法是线程安全的,则必须在数据库中插入100条记录,而无需任何更改没问题

如果我执行setId并保存在synchronized块中,一切正常,但这不是我的意图,如果存储库方法是线程安全的,也不是必需的


专家们,有什么帮助吗?

您的保存任务不是原子的-两个线程可能在其中一个保存新实体之前获取相同的最大id

然后,即使存储库的save方法是线程安全的,也不会有帮助


maxId是线程安全的,save是线程安全的,但是每个线程的runnable中的方法不是线程安全的。

您的保存任务不是原子的-两个线程可能在其中一个保存新实体之前获取相同的最大id

然后,即使存储库的save方法是线程安全的,也不会有帮助


maxId是线程安全的,save是线程安全的,但是每个线程的runnable中的方法不是线程安全的。

问题在于如何使用findFormID()检索最后一个ID,它在并发上下文中不起作用


如果两个线程同时请求一个ID怎么办?它们将检索相同的ID并创建两个具有相同ID的对象。这是您的问题


一些针对生成的ID的集成解决方案已经存在,除非您知道自己在做什么,否则不应该尝试实现自己的解决方案。

问题在于如何使用findFormID()检索最后一个ID,它在并发上下文中不起作用


如果两个线程同时请求一个ID怎么办?它们将检索相同的ID并创建两个具有相同ID的对象。这是您的问题


一些用于生成ID的集成解决方案已经存在,除非您知道自己在做什么,否则您不应该尝试实现自己的解决方案。

简单地说,是的,它是线程安全的,但您的数据库也是有状态的(显然),为了维护完整性,您可能需要锁定策略之类的东西(保持锁以使事情同步,或者使用乐观策略并在需要时重试)。正如有人在另一个答案中指出的那样,如果您只是使用不同的方法生成ID(检查SUID),您的代码将运行良好。

简单地说,是的,它是线程安全的,但您的数据库也是有状态的(显然)为了保持完整性,您可能需要锁定策略(保持锁定以使事情同步,或者使用乐观策略并在需要时重试)。正如有人在另一个答案中指出的那样,如果您只是使用不同的方法生成ID(签出SUID),您的代码就可以正常工作

“如果两个线程同时请求ID怎么办”因为findFormID是同步的,所以只有一个线程能够获取ID。但问题是save和setformid不是原子的。“如果两个线程同时请求ID怎么办?”“因为findFormID是同步的,所以只有一个线程能够获取id。但问题是save和setformid不是原子的。是的,我也这么认为,因为我在问题中也提到,如果我将save和findFormID放在syncronized块中,一切都会正常工作……是的,我