java - 捕获事务方法内的异常后超出锁等待超时

标签 java mysql hibernate exception transactional

您好,我在异常后的恢复过程中遇到查询问题。 这是代码(主要部分)

@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!");
    }
}

为了尝试在 unSetEditingFleet 期间发生异常时会发生什么,我抛出一个新的异常:

@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);
    }
}

Exception catch 后的指令 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 

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);   
}

这会将操作的进度状态设置到数据库中,以便用户可以了解进度状态。 为什么只有在 catch 之后我才会收到此异常?你知道我该如何解决它吗?

最佳答案

根据我的发现,我可以看出数据库上的事务超时,因为另一个线程在某些记录上保持记录锁的时间太长。检查哪些其他线程同时对该表进行操作。有不同的方法可以找出阻止事务的原因,如图 here 所示。

如果您运行繁忙的数据库,请使用:

SET GLOBAL innodb_lock_wait_timeout = 5000; 

然后:

SET innodb_lock_wait_timeout = 5000; 

作为一种解决方法,但您的查询需要优化。

关于java - 捕获事务方法内的异常后超出锁等待超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47886413/

相关文章:

java - 使用 pom.xml 加载属性文件和在 applicationContext.xml 中创建占位符的区别

java - 如何反转音频文件?

mysql - 字段列表中的列 'loginAttempts' 不明确 - 我在这里缺少什么区别?

java - 数据库中的表不与外键连接

具有更多数据源的 spring jpa hibernate

java - 使 JavaFX 应用程序非静态

java - 如何测试一个只有很小 API 但有很多私有(private)函数的类?

mysql - 戈达迪 : How to add a database to an addon domain

php - Prestashop 产品功能 PHP SQL

java - 在 hibernate 启动时启动脚本 hql 或 sql