如果我开始事务但由于条件原因,我不应该这样做,我应该使用提交还是可以立即调用回滚?

Posted

技术标签:

【中文标题】如果我开始事务但由于条件原因,我不应该这样做,我应该使用提交还是可以立即调用回滚?【英文标题】:If I started transaction but because of the condition, I shouldn't do this, should I use commit or can I call rollback right away? 【发布时间】:2021-08-17 11:12:41 【问题描述】:

我有提供订单的 Dao Service,如果我没有找到汽车,我不需要提交

 @Override
    public String makeOrder(String[] stingNumbers, String[] categories, String userAddress, String userDestination, String login) 
        int[] numbers = Stream.of(stingNumbers).mapToInt(Integer::parseInt).toArray();
        Car[] foundCars = new Car[categories.length];
        String messageTakenTime = null;
        mysqlDAOFactory.createConnectionScope();
        MySQLDAOFactory.createTransaction();
        User foundUser = userDao.findUser(login);
        for (int i = 0; i < foundCars.length; i++) 
            foundCars[i] = carDao.findCar(numbers[i], categories[i]);
            if (foundCars[i] == null) 
                MySQLDAOFactory.endTransaction();
                MySQLDAOFactory.abortTransaction();
                MySQLDAOFactory.endConnectionScope();
                return String.format("false %s %d", categories[i], numbers[i]);
            
            carDao.updateCar(foundCars[i].getCarId(), "on Order");
            double distance = DistanceUtil.getDistance(userAddress, userDestination);
            CarCategory foundCarCategory = categoryDao.findCarCategory(categories[i]);
            double discount = foundCarCategory.getDiscount();
            double costPerKilo = foundCarCategory.getCostPerOneKilometer();
            int scale = (int) Math.pow(10, 1);
            double orderCost = (double) Math.round((distance * costPerKilo) - ((distance * costPerKilo) * discount) * scale) / scale;
            Order order = new Order();
            order.setUserId(foundUser.getUserId());
            order.setCarId(foundCars[i].getCarId());
            order.setOrderDate(LocalDateTime.now());
            order.setUserAddress(userAddress);
            order.setUserDestination(userDestination);
            order.setOrderCost(orderCost);
            orderDao.insertOrder(order);
            if (messageTakenTime == null) 
                messageTakenTime = DistanceUtil.takenTime(distance);
            
        
        MySQLDAOFactory.endTransaction();
        MySQLDAOFactory.endConnectionScope();
        return messageTakenTime;
    

我在 DaoFactory 中有使用连接的方法(打开连接、启动事务、关闭连接、关闭事务并进行回滚)

public static void createTransaction() 
        isTransaction = true;
        try 
            connection.setAutoCommit(false);
         catch (SQLException throwables) 
            LOGGER.error(throwables);
        
    

    public static void endTransaction() 
        try 
            connection.commit();
         catch (SQLException throwables) 
            LOGGER.error(throwables);
        
    

    public static void abortTransaction() 
        try 
            connection.rollback();
         catch (SQLException throwables) 
            LOGGER.error(throwables);
        
    

    public static void createConnectionScope() 
        isConnectionScope = true;
        try 
            connection = DATA_SOURCE.getConnection();
         catch (SQLException e) 
            LOGGER.error(e);
        
    

    public static void endConnectionScope() 
        isConnectionScope = false;
        try 
            connection.close();
         catch (SQLException throwables) 
            LOGGER.error(throwables);
        
    

在我的示例中,如果我不想提交我的事务,我应该怎么做?调用回滚?或者调用 commit 并在回滚之后?另外,如果您能告诉我如何在这些方法中捕获异常,或者让方法将它们抛出并直接在服务层中捕获它们,因为我不太了解它是如何完成的。谢谢回复。

【问题讨论】:

仅供参考:connection.setAutoCommit(false) 不会创建事务,它只是禁用自动提交模式。 【参考方案1】:

如果您不想提交事务,则需要使用ROLLBACK

如果你COMMIT的事务没有剩下ROLLBACK,这些操作是互斥的。

无论您的应用程序的逻辑在哪里,都应该捕获这些发生的操作。发生异常后的某些时候,您需要做的事情比ROLLBACK 还要多。如果您在 DAO 类中捕获异常,您将无法准确判断发生了什么并生成更好的消息或特定逻辑。

【讨论】:

感谢您的回复。你能告诉我如何做到线程安全吗? 这是一个技巧问题。事务与连接绑定,只要您使用相同的连接,您就处于同一个事务中。如果该连接结束,所有内容都会回滚。注意使用池的连接对象。但是,除此之外,我不知道如何指导您。

以上是关于如果我开始事务但由于条件原因,我不应该这样做,我应该使用提交还是可以立即调用回滚?的主要内容,如果未能解决你的问题,请参考以下文章

POSTGRES Group BY中的聚合函数

我应该处理 WSASend() 可能不会发送所有数据的事实吗?

我应该在数据库连接字符串中设置最大池大小吗?如果我不这样做会怎样?

是否应该有一个读取查询的事务?

SalesForce DML基于集合的操作和原子事务

在 EF Core 中使用 IsolationLevel 开始事务