使用存储库的异步方法中的Spring InvalidDataAccessApiUsageException

时间:2016-02-10 13:25:59

标签: java spring hibernate spring-mvc asynchronous

在RestController中:

@RestController
@RequestMapping("/apks")
public class ApkController {
    @Inject
    DecompiledApkRepository decompiledApkRepository;

    @Autowired
    DecompileService decompileService;

    @RequestMapping(method = RequestMethod.POST)
    public ResponseEntity<?> createFromJson(@RequestBody Apk apk) {
        ....
        DecompiledApk decompiledApk = new DecompiledApk(apk, apkFile, apk.getMd5Hash());
        decompileService.decompile(decompiledApk, apk.getMd5Hash(), decompiledApkRepository);

    } catch (IOException |InterruptedException e) {
        e.printStackTrace();
    }

    return new ResponseEntity<>(null, responseHeaders, HttpStatus.CREATED);
}

DecompiledApk实体:

@Entity
@Table(name = "decompiled_apks")
public class DecompiledApk {

    @Id
    @GeneratedValue
    @JsonIgnore
    private Long id;

    @MapsId
    @OneToOne(optional=false)
    private Apk apk;

    @Column(unique = true)
    private URI decompiledFolder;

    @Transient
    @JsonIgnore
    private File inputApk;

 // all public getters/setters, package empty constructor and public full constructor

DecompiledApkRepository:

@Repository
public interface DecompiledApkRepository extends CrudRepository<DecompiledApk, Long> {
    DecompiledApk findByApk_md5Hash(String md5Hash);
}

在这里,问题在于DecompileService中的异步方法:

@Service
public class DecompileService {
    private static final String DEC_FOLDER = "/tmp/decompiled/";


    @Async
    public Future<Void> decompile(DecompiledApk decompiledApk, String md5Hash, DecompiledApkRepository decompiledApkRepository) throws InterruptedException {
        /*
       ...
       */
        decompiledApk.setDecompiledFolder(URI.create(outputFolder));
        System.err.println("---start-->"+Thread.currentThread().getName());
        decompiledApkRepository.save(decompiledApk);
        System.err.println("---end-->"+Thread.currentThread().getName());
        return new AsyncResult<>(null);
    }

指示:

decompiledApkRepository.save(decompiledApk);

掷:

org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: com.xxx.domain.Apk; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.xxx.domain.Apk

但是,如果我删除@Async注释,它的工作没有问题! 有任何想法吗? 你需要更多细节吗?

2 个答案:

答案 0 :(得分:0)

虽然该方法已被标记为异步,但没有弹出事务标记,怀疑是导致问题。 尝试添加Spring事务:

org.springframework.transaction.annotation  


@Transactional

希望这能解决问题。

答案 1 :(得分:0)

  

使用ThreadLocals保留Spring的事务上下文。这意味着您的SessionFactory仅可用于调度您的请求的线程,因此,如果您创建新线程,您将获得null和相应的异常。   您的@Async方法的作用是使用TaskExecutor在另一个线程中运行您的方法。因此,您的服务就会出现上述问题。

根据link