休眠 - Table 更新后锁定

Hibernate - Table Locked after update

我正在通过使用 Hibernate 和 EntityManager 的方法执行更新。

多次调用此更新方法(在循环内)。

好像我第一次执行它时,它锁定了 table 而没有释放它。

在关闭应用程序后尝试通过 SQL 开发人员更新 table 时,我看到 table 仍然被锁定,因为更新挂起。

您认为解决此问题的方法是什么?如果您需要更多信息,请告诉我。

Class

@Repository
@Transactional(propagation = REQUIRES_NEW)
public class YirInfoRepository {

    @Autowired
    EntityManager entityManager;

    @Transactional(propagation = REQUIRES_NEW)
    public void setSent(String id) {
        String query = "UPDATE_QUERY";
        Query nativeQuery = entityManager.createNativeQuery(String.format(query, id));
        nativeQuery.executeUpdate();
    }
}

更新

等了一个多小时后,我再次启动应用程序,它曾经运行良好,但现在再次挂起。


更新 2 -- 我将给予帮助我解决此问题的最高赏金

在另一个地方,我使用了应用程序托管实体管理器,它仍然给我相同类型的错误。

public void fillYirInfo() {
    File inputFile = new File("path");
    try (InputStream inputStream = new FileInputStream(inputFile);
         BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
        bufferedReader.lines().skip(1).limit(20).forEach(line -> {
            String[] data = line.split(",");
            String rnr = data[0];
            String linked = data[1];
            String email = data.length > 2 ? data[2] : "";



    String insuredId = insuredPeopleRepository.getInsuredIdFromNationalId(rnr);
            int modifiedCounter = 0;

            if (!isNullOrEmpty(insuredId)) {
                EntityManager entityManager = emf.createEntityManager();
                EntityTransaction transaction = entityManager.getTransaction();
                Query nativeQuery = entityManager.createNativeQuery(
                        "QUERY"
                );
                transaction.begin();
                nativeQuery.executeUpdate();
                entityManager.flush();
                transaction.commit();
                entityManager.close();
            }

            System.out.println(modifiedCounter + " rows modified");
        });
    } catch (IOException e) {
        e.printStackTrace();
    }
}

尝试不使用 update-query:

@Repository
@Transactional(propagation = REQUIRES_NEW)
public class YirInfoRepository {

    @Autowired
    EntityManager entityManager;

    @Transactional(propagation = REQUIRES_NEW)
    public void setSent(String id) {
        //guessing your class name and method..
        final YirInfo yirInfo = entityManager.find(YirInfo.class, id);
        yirInfo.setSent();
    }
}

可能不如单个更新查询快,但可以相当快地获取它,除非数据量很大。这是使用 Hibernate/JPA 的首选方式,而不是根据单个值和 SQL 查询来思考,您可以使用 entities/objects 和(有时)HQL/JPQL 查询。

您必须了解的第一件事是,对于第一个示例,您正在使用本机查询来更新数据库中的行。在这种情况下,您将完全跳过 Hibernate 来为您做任何事情。

在你的第二个例子中,你有同样的事情,你正在通过更新查询进行更新。您不需要刷新实体管理器,因为它只需要在该实体管理器内传输对您的实体对象所做的未决更改。

另外,我不知道您的示例是如何工作的,因为您正在自动装配实体管理器而不使用 @PersistenceContext 注释。确保你正确使用这个,因为你可能错误配置了应用程序。此外,在使用 Spring 时无需手动创建实体管理器,如第二个示例所示。只需使用 @PersistenceContext 即可在您的应用中获取实体管理器。

您还混淆了事务管理。在第一个示例中,如果将 @Transactional 注释放在您的方法或 class.

中就足够了

对于另一个示例,您正在进行手动事务管理,这在这种情况下毫无意义。如果您正在使用 Spring,您可以简单地依赖声明式事务管理。

我在这里要检查的第一件事是将 datasource-proxy 集成到您的连接管理中并注销您的语句是如何执行的。使用此信息,您可以确保查询已发送到数据库端并且数据库执行速度非常慢,或者您的应用程序和数据库之间存在网络问题。

如果您发现查询已正确发送到数据库,您想要分析您的查询,因为它很可能只是执行得非常慢并且需要一些优化。为此,您可以使用“解释计划”功能来了解您的执行计划,然后使其更快。

您正在使用 @Transactional 注释。这意味着您正在使用 Spring 交易。然后在您的更新 2 中,您自己使用事务并由 spring 管理(我猜这是另一个项目或 class 不由 Spring 管理)。

在任何情况下,我都会尝试在单个 spring 事务中更新您的记录,并且我不会在 DAO 层中使用 @Transactional,而是在服务层中使用。像这样:

服务层:

@Service
public class YirInfoService {
    @Autowired
    YirInfoRepository dao;

    @Transactional(propagation = REQUIRES_NEW)
    public void setSent(List < String > ids) {
        dao.setSents(ids);
    }
}

DAO 层:

@Repository
public class YirInfoRepository {

    @Autowired
    EntityManager entityManager;

    //Here you can update by using and IN statement or by doing a cycle
    //Let's suppose a bulk operation
    public void setSents(List < String > ids) {
        String query = "UPDATE_QUERY";
        for (int i = 0; i < ids.size(); i++) {
            String id = ids.get(i);
            Query nativeQuery = entityManager.createNativeQuery(String.format(query, id));
            nativeQuery.executeUpdate();
            if (i % 20 == 0) {
                entityManager.flush();
                entityManager.clear();
            }
        }
    }
}