简体   繁体   English

在Transactional方法中捕获异常后超过了锁定等待超时

[英]Lock wait timeout exceeded after catch of exception inside Transactional method

Hi I have a problem with query insiede a restore procedure after Exception. 嗨,我有一个查询异常后的恢复过程的问题。 This is the code (the main part of it) 这是代码(它的主要部分)

@Override
@Async
@Transactional(rollbackFor=Exception.class)
public void modifyFleet(User currentUser, FleetForm fleetForm) throws Exception {
    //Keep the progress status on DB
    fleetServices.setEditingProgress(fleetForm.getIdFleet(), "Start editing fleet");
    Fleet oldFleet = fleetServices.findById(fleetForm.getIdFleet());
    //some INSTRUCTIONS
    if (!(backupFolderFile.mkdirs()))
        throw new FileSystemException("Error making the folder backup");
    try{
        //Keep the progress status on DB
        fleetServices.setEditingProgress(fleetForm.getIdFleet(), "Backup...");
        FileUtils.copyDirectory(fleetFile, new File(backupFolder));

        //Create fleet with new value
        Fleet newFleet = newFleetConstructor(fleetForm, oldFleet);
        //Change operation for all cars of the application
        int i = 0;
        for (Car car:oldFleet.getCars()){
            //some INSTRUCTIONS

            //Keep the progress status on DB
            fleetServices.setEditingProgress(fleetForm.getIdFleet(), "Work on car "+ car.getCarType().getIdCarType() + car.getId()+ " (" + i +" of " + oldFleet.getCars().size() +"): Editing acquisitions file"  );

        }

        fleetServices.setEditingProgress(oldFleet.getIdFleet(), "Updating file system fleet path");
        utils.unSetEditingFleet(oldFleet.getIdFleet());
//          throw new Exception("fleet has been restored Exception");
    }catch(Exception e){
        //Keep the progress status on DB
        fleetServices.setEditingProgress(oldFleet.getIdFleet(), "Sorry an error occured during the procedure, wait until restore is ended!");
        //Restore the file system procedure
        restoreProcedure(oldFleet.getIdFleet(), fleetFile, backupFolderFile);       
        //Keep the progress status on DB
        fleetServices.setEditingProgress(oldFleet.getIdFleet(), "");
        utils.unSetEditingFleet(oldFleet.getIdFleet());
        //Even with this exception set the fleet as not in editing
        throw new EditingException("fleet has been restored!");
    }
}

To try what happen when excepton occures during unSetEditingFleet I throw a new exception : 为了尝试在unSetEditingFleet期间exception发生时发生的情况,我抛出了一个新异常:

@Transactional
public void unSetEditingFleet(Integer idFleet) throws QueryException {
    try {
        fleetServices.setEditingFleet(idFleet, false);  
        throw new Exception();
//          for(Car car : carServices.findByFleetIdFleet(idFleet)){
//              carServices.setEditingCar(car.getIdCar(), false);   //Unset cars associated with the fleet 
//          }    
    }catch(Exception e){
        throw new QueryException(e);
    }
}

The instruction fleetServices.setEditingProgress after the Exception catch generates the exception: 异常捕获后的指令fleetServices.setEditingProgress会生成异常:

Caused by: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:998)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3847)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3783)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2447)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2594)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2545)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1901)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2113)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2049)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2034)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208)
    ... 54 more 

the code of setEditinProgress is the following: setEditinProgress的代码如下:

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW) //necessary to set immediately the text into the database inside a transactional method. This annotation create a new transaction
public void setEditingProgress(Integer idFleet, String editingProgress) {
    fleetRepository.setEditingProgress(idFleet, editingProgress);   
}

This set into database the progress status of the operation so the user can know the progress status. 这会将操作的进度状态设置到数据库中,以便用户可以知道进度状态。 Why only after the catch I receive this exception? 为什么仅在捕获后才收到此异常? Do you know how can I fix it? 你知道我该怎么解决吗?

From what I've found out I can tell that your transaction on the database times out because another thread keeps a record lock on some record for too long. 从我发现的信息可以看出,您在数据库上的事务已超时,因为另一个线程将某个记录的记录锁定时间过长。 Check which other threads do operations on that table at the same time. 检查哪些其他线程同时在该表上执行操作。 There are different ways to figure out what blocks the transaction as shown here 有不同的方式来弄清楚什么块事务如图所示这里

if your running a busy db use: 如果您正在运行繁忙的数据库,请使用:

SET GLOBAL innodb_lock_wait_timeout = 5000; 

then: 然后:

SET innodb_lock_wait_timeout = 5000; 

works as a workaround but your queries need to be optimized. 可以作为一种解决方法,但是您的查询需要进行优化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM