休眠 - 表更新后锁定

时间:2018-03-20 16:05:00

标签: spring oracle hibernate deadlock spring-transactions

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

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

似乎第一次执行它时,它会锁定表并且不会释放它。

在关闭应用程序后尝试通过SQL Developer更新表时,我看到表仍然被锁定,因为更新已挂起。

您认为这个问题的解决方案是什么?如果您需要更多信息,请与我们联系。

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

3 个答案:

答案 0 :(得分:1)

尝试没有更新查询:

@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查询,而是使用实体/对象和(有时)HQL / JPQL查询。

答案 1 :(得分:1)

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

在任何情况下,我要做的是尝试在单弹簧事务中更新您的记录,我不会在DAO层中使用@Transactional但在服务层中使用@Service public class YirInfoService { @Autowired YirInfoRepository dao; @Transactional(propagation = REQUIRES_NEW) public void setSent(List < String > ids) { dao.setSents(ids); } } 。像这样:

服务层:

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

DAO层:

ngOnInit () {
   this.productService.readProducts().subscribe(products => {
      const productIds = Object.keys(products['records']);
      this.products = productIds.map(productId => {
         const product = products['records'][productId];
         product.id = productId;

         return product;
      });
   });
}

答案 2 :(得分:0)

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

在第二个示例中,您有相同的事情,您正在通过更新查询进行更新。您不需要刷新实体管理器,因为它只是转移对该实体管理器中的实体对象所做的挂起更改所必需的。

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

您也在混淆交易管理。在第一个示例中,如果将@Transactional注释放入方法或类中,就足够了。

对于另一个例子,您正在进行手动事务管理,在这种情况下没有任何意义。如果您使用的是Spring,那么您可以简单地依赖声明式事务管理。

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

如果您发现查询已正确发送到数据库,您希望分析您的查询,因为很可能它只是执行得很慢而且需要一些优化。为此,您可以使用说明计划功能,了解执行计划的外观,然后加快执行速度。