Clumsy_Birdgirl 2024-04-11 16:56 采纳率: 0%
浏览 9

java用mybatis插入数据

写了两个方法,分别将同一条数据插入两张表结构不同的表,然后写一个起了事务的方法去同时对这两个方法进行调用,但隔几天查库发现表1数据量比表2多,也没有插入失败的错误日志,百思不得其解

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertData(TblEventPlateInfo tblEventPlateInfo) {
        plateInfo(tblEventPlateInfo);
        parkVehInfo(tblEventPlateInfo);
    }
   public void plateInfo(TblEventPlateInfo tblEventPlateInfo) {
        tblEventPlateInfo.setId(remoteIdProducerService.nextId());
        tblEventPlateInfoMapper.insert(tblEventPlateInfo);
    }
public void parkVehInfo(TblEventPlateInfo tblEventPlateInfo) {
                TblParkingVehicleInfo info;
                info = new TblParkingVehicleInfo();
                info.setId(remoteIdProducerService.nextId());
                info.setVehPlate(tblEventPlateInfo.getSzText());
                info.setVehClass(tblEventPlateInfo.getUiStatType());
                info.setVehColor(tblEventPlateInfo.getUiColor());
                info.setParkingId(1L);
                info.setStatus(0);
                info.setVehClassSub(tblEventPlateInfo.getUiSubType());
                info.setCreateTime(DateUtils.getNowDate());
                tblParkingVehicleInfoMapper.insert(info);
}
  • 写回答

5条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-04-11 16:56
    关注

    引自免费微信小程序:皆我百晓生

    根据您提供的信息,看起来像是在使用Spring框架的@Transactional注解来处理数据库事务,但是似乎存在并发问题导致数据不一致。首先,我们需要检查事务隔离级别是否设置正确,并且确保在插入操作之间没有其他并发修改。

    Spring默认的事务隔离级别是READ_COMMITTED,这可能导致在高并发场景下的幻读(Phantom Read)或不可重复读(Non-repeatable read)。在这种情况下,建议将事务隔离级别设置为SERIALIZABLE,虽然这可能会降低性能,但能确保数据一致性。

    以下是修改事务配置的示例:

    在您的Spring Boot应用的application.properties文件中添加以下内容:

    spring.jpa.properties.hibernate.default_batch_fetch_size=1
    spring.jpa.properties.hibernate.order_inserts=true
    spring.jpa.properties.hibernate.order_updates=true
    spring.jpa.properties.hibernate.jdbc.batch_size=50
    spring.jpa.open-in-view=false
    spring.datasource.isolation-level-read-committed=true
    

    或者,如果您使用的是Java配置类,可以这样设置:

    @Configuration
    @EnableTransactionManagement
    public class AppConfig {
    
        @Bean
        public DataSource dataSource() {
            // Your data source configuration here
        }
    
        @Bean
        public JdbcTemplate jdbcTemplate(DataSource dataSource) {
            return new JdbcTemplate(dataSource);
        }
    
        @Bean
        public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
            HibernateTransactionManager htm = new HibernateTransactionManager(entityManagerFactory);
            htm.setHibernateProperties(hibernateProperties());
            return htm;
        }
    
        Properties hibernateProperties() {
            Properties properties = new Properties();
            properties.setProperty("hibernate.default_batch_fetch_size", "1");
            properties.setProperty("hibernate.order_inserts", "true");
            properties.setProperty("hibernate.order_updates", "true");
            properties.setProperty("hibernate.jdbc.batch_size", "50");
            properties.setProperty("hibernate.isolation", "Serializable");
            return properties;
        }
    }
    

    接下来,确认一下plateInfo()parkVehInfo()方法中的逻辑是否有并发风险。从目前的代码来看,它们各自独立地创建了新的实体对象并插入到数据库,看起来应该是安全的,除非有其他地方也访问这些数据。

    为了进一步排查,您可以考虑以下几个步骤:

    1. 检查是否有其他地方并发修改这两张表的数据。
    2. 在插入操作前后打印日志,查看是否所有插入操作都成功执行,例如:
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertData(TblEventPlateInfo tblEventPlateInfo) {
        log.info("Starting to insert data...");
        plateInfo(tblEventPlateInfo);
        log.info("Inserted into plate table successfully.");
        parkVehInfo(tblEventPlateInfo);
        log.info("Inserted into parking vehicle table successfully.");
        log.info("Finished inserting data.");
    }
    
    1. 如果仍然无法确定问题所在,您可以尝试在insertData()方法中使用显式保存点(Savepoint),以便在其中一个操作失败时回滚到特定点。但这可能增加复杂性,因为您需要捕获异常并在回滚后处理它。
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertData(TblEventPlateInfo tblEventPlateInfo) {
        try (Connection conn = yourEntityManager.unwrap(Connection.class)) {
            conn.setAutoCommit(false);
            
            // ... 之前的代码
            
            String savePointName = "save_point";
            Savepoint savePoint = conn.setSavepoint(savePointName);
    
            plateInfo(conn, tblEventPlateInfo); // Pass the connection explicitly
            if (!conn.getAutoCommit()) {
                conn.commit(); // Commit after each operation
            }
    
            log.info("Inserted into plate table successfully.");
    
            parkVehInfo(conn, tblEventPlateInfo); // Pass the connection explicitly
            if (!conn.getAutoCommit()) {
                conn.commit(); // Commit after each operation
            }
    
            log.info("Inserted into parking vehicle table successfully.");
            log.info("Finished inserting data.");
        } catch (Exception e) {
            log.error("Error occurred during insertion.", e);
            try {
                if (!conn.getAutoCommit()) {
                    conn.rollback(savePoint); // Rollback to the save point if there's an exception
                }
            } catch (SQLException sqlEx) {
                log.error("Failed to rollback transaction.", sqlEx);
            }
        } finally {
            try {
                if (!conn.getAutoCommit()) {
                    conn.setAutoCommit(true);
                }
            } catch (SQLException ex) {
                log.error("Failed to set auto-commit back to true.", ex);
            }
        }
    }
    
    private void plateInfo(Connection conn, TblEventPlateInfo tblEventPlateInfo) {
        // Use the passed connection in the query
        tblEventPlateInfo.setId(remoteIdProducerService.nextId());
        tblEventPlateInfoMapper.insert(conn, tblEventPlateInfo);
    }
    
    private void parkVehInfo(Connection conn, TblEventPlateInfo tblEventPlateInfo) {
        // Use the passed connection in the query
        TblParkingVehicleInfo info = new TblParkingVehicleInfo();
        // ...
        tblParkingVehicleInfoMapper.insert(conn, info);
    }
    

    请尝试上述建议,如果还有问题,请提供更详细的日志输出,以便更好地分析问题。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 4月11日

悬赏问题

  • ¥15 linux的gcc命令报错
  • ¥20 如何再GIS用海岸线建立缓冲区
  • ¥15 codeblock遇到问题了,求帮助😭
  • ¥15 Qt6.8.0加载网页MSVC2022
  • ¥15 360浏览器m2的这个值
  • ¥15 国内有哪些厂商做automlops的?
  • ¥15 skynet pb mysql
  • ¥15 笔记本外接显示器分辨率太低各种方法都用过了调不高
  • ¥15 Redstone R0697-F00 D2020 交换机 OS
  • ¥50 H5+js 动态数字画廊怎么做?