我很好奇spring jparepository方法是否是线程安全的,然后阅读了stackflow文章(Spring Data(JPA)Repository线程安全吗?(又名SimpleJpaRepository线程安全))。从那里,我了解到存储库方法是线程安全的,然后我制作了一个POC来测试线程安全。我让一个存储库说FormRepository来对“表单”实体进行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;
}
}
当我这样做时,我以为一切都可以正常工作,因为表单存储库方法是线程安全的,但是以某种方式我在日志中多次获取了sql dataintegrityviolationexception,从而导致插入多个记录失败。以下错误供参考:
org.springframework.dao.DataIntegrityViolationException:无法执行语句;SQL [n / a];约束[“ PUBLIC.TBLDYNAMICFORM(FORMID)上的主键”;SQL语句:插入到Tbldynamicform(clientid,copyfromexisting,creatationdate,formdesc,formmode,formname,formtemplate,formtitle,procutype,status,formid)值(?,?,?,?,...)
这使我开始思考这是线程安全问题还是其他问题?据我了解,我在dao中创建的所有“ tbldynamicform”对象都将保留在线程堆栈中。只有formRepository将位于堆存储中,并且如果formrepository方法是线程安全的,则必须在数据库中插入100条记录,而不会出现任何问题。
如果我执行setId并保存在同步块中,则一切正常,但这不是我的意图,并且如果存储库方法是线程安全的,则不是必需的。
专家,有什么帮助吗?
您的保存任务不是原子的-两个线程可能会在其中一个保存新实体之前获取相同的最大id。
然后,即使存储库的save方法是线程安全的,也无济于事。
maxId是线程安全的,save是线程安全的,但是每个线程的可运行内部的方法都不是线程安全的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句