当前位置: 首页 > 知识库问答 >
问题:

在spring data jpa中,同一事务中的修改是不可见的,为什么我在同一事务中修改后得到null?

孙弘博
2023-03-14

首先显示代码,这是我的代码,如下所示:

   public void saveTestTx() {
        Lock lock = new Lock();
        lock.setName("ABCDEFG");
        lock.setDeviceId("22dfgdfgdftrtg");
        lock.setCreateTime((new Date()));
        Lock lock1 = lockDao.saveAndFlush(lock);
        System.out.println("lock1 = " + lock1);
        Lock lock2 = lockDao.findByDeviceId(lock.getDeviceId());
        System.out.println("lock2 = " + lock2);  // got null here
    }

在此处输入图像描述(这是屏幕截图)

我确信方法“saveTestTx()”是一个完整的事务,因为如果我调用print(22/0),它可以回滚。我的意思是从192行到199行的代码在同一个事务中。根据我的java开发经验,我认为lock2是lock1的结果,我知道在打印lock2之前,事务还没有提交,但它们在同一个事务中,同一事务中的修改是可见的,所以在提交事务之前,可以从调用“saveAndFlush()”方法后选择,并在控制台打印insert语句,但事实上,为什么lock2打印为null?

我的交易配置如下:

@Configuration
public class TxConfig {
    @Bean("txSource")
    public TransactionAttributeSource transactionAttributeSource() {
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
        readOnlyTx.setReadOnly(true);
        readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
        RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED,
                Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        int isolationLevel = requiredTx.getIsolationLevel();
        // requiredTx.setTimeout(90);
        Map<String, TransactionAttribute> txMap = new HashMap<>();
        txMap.put("init*", requiredTx);
        txMap.put("add*", requiredTx);
        txMap.put("save*", requiredTx);
        txMap.put("insert*", requiredTx);
        txMap.put("create*", requiredTx);
        txMap.put("persist*", requiredTx);
        txMap.put("update*", requiredTx);
        txMap.put("modify*", requiredTx);
        txMap.put("merge*", requiredTx);
        txMap.put("bind*", requiredTx);
        txMap.put("delete*", requiredTx);
        txMap.put("del*", requiredTx);
        txMap.put("drop*", requiredTx);
        txMap.put("remove*", requiredTx);
        txMap.put("reset*", requiredTx);
        txMap.put("cancel*", requiredTx);
        txMap.put("login*", requiredTx);
        txMap.put("*", readOnlyTx);
        source.setNameMap(txMap);
        return source;
    }


    @Bean
    public AspectJExpressionPointcutAdvisor pointcutAdvisor(TransactionInterceptor txInterceptor) {
        AspectJExpressionPointcutAdvisor pointcutAdvisor = new AspectJExpressionPointcutAdvisor();
        pointcutAdvisor.setAdvice(txInterceptor);
//    pointcutAdvisor.setExpression("execution (* com.hl..service..*.*(..))");
        pointcutAdvisor.setExpression("execution (* com..service..*.*(..)) || execution (* com..dao..*.*(..))");
        return pointcutAdvisor;
    }

    @Bean("txInterceptor")
    TransactionInterceptor getTransactionInterceptor(PlatformTransactionManager tx) {
        return new TransactionInterceptor(tx, transactionAttributeSource());
    }

}

我的实体代码如下:

@Data
@ToString(callSuper = true)
@Entity
@Table(name = "police_lock")
@SQLDelete(sql = "update lock set is_deleted = 1 where id = ?")
@Where(clause = "is_deleted = 0")
@DynamicInsert
@DynamicUpdate
public class Lock extends LongBaseEntity {
    public static interface AddGroup {};
    public static interface UpdateGroup {};

    private static final long serialVersionUID = 1L;

    public Lock() {
        super();
    }

    public Lock(Long id) {
        this.id = id;
    }
    public Lock(boolean isInit) {
        super(isInit);
    }
    @NotBlank(groups = {AddGroup.class,UpdateGroup.class})
    private String deviceId;

    @NotBlank(groups = {AddGroup.class,UpdateGroup.class})
    private String name;
}

我的表格如下:

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for police_lock
-- ----------------------------
DROP TABLE IF EXISTS `police_lock`;
CREATE TABLE `police_lock` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `device_id` varchar(36) NOT NULL COMMENT 'device_id',
  `name` varchar(40) NOT NULL COMMENT 'name',
  `create_time` datetime NOT NULL COMMENT 'create_time',
 `is_deleted` bit(1) DEFAULT b'0' COMMENT 'is_deleted',  
  PRIMARY KEY (`id`),
  UNIQUE KEY `device_id` (`device_id`)
) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8mb4 COMMENT='lock';

findByDeviceId()方法是spring数据jpa接口方法,仅定义一个方法就足够了。这是spring data jpa的特性,在调用saveAndFlush()方法后,它发送如下sql:

Hibernate: insert into police_lock (create_time, is_deleted, device_id, name) values (?, ?, ?, ?)

该方法执行后,提交事务,数据库生成新记录。当然,它不是在方法执行之前生成的。但我的问题是:虽然它没有提交,但修改应该通过同一事务中的以下代码看到,即使它没有提交。但我的不是。我不知道为什么。。我错过什么了吗?

我的代码在Spring boot、Spring data jpa、mysql下。

共有1个答案

慕容念
2023-03-14

我现在修复了,我的事务配置有问题,我修改如下:

@Configuration
public class TxConfig2 {
    @Autowired
    private PlatformTransactionManager transactionManager;

    @Bean(name = "txAdvice")
    public TransactionInterceptor getAdvisor() throws Exception {
        System.out.println("transactionManager = " + transactionManager);
        Properties properties = new Properties();
        properties.setProperty("init*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("add*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("insert*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("create*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("persist*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("update*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("modify*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("merge*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("bind*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("del*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("drop*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("remove*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("reset*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("cancel*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("login*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("save*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("update*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("delete*", "PROPAGATION_REQUIRED,-Exception");
        properties.setProperty("*", "PROPAGATION_REQUIRED,-Exception,readOnly");
        TransactionInterceptor tsi = new TransactionInterceptor(transactionManager, properties);
        return tsi;
    }
    @Bean
    public BeanNameAutoProxyCreator txProxy() {
        BeanNameAutoProxyCreator creator = new BeanNameAutoProxyCreator();
        creator.setInterceptorNames("txAdvice");
        creator.setBeanNames("*Service","*Dao");
        creator.setProxyTargetClass(true);
        return creator;
    }
}

那么它工作得很好!!!

 类似资料:
  • 我面临一个场景,我需要更新参数,并希望在同一事务中检索修改后的值 例如: 我的问题是,我们不能在同一事务中从bean本身检索修改后的值,而不是提交内部事务(即新事务)并从DB中检索它吗?

  • 由于在所述实体不可用的情况下返回,因此需要进行如上所示的条件测试,以避免可能的,否则很可能发生。在任何地方重复这个琐碎的条件测试都是非常不可接受和不鼓励的,这使得业务逻辑应该尽可能简单,几乎不可读。 为了防止这种条件检查到处重复,我在一个单独的EJB中有一个通用方法, 从另一个EJB内部调用此方法,如下所示, 在这里,尽管所有事情都发生在同一个事务中,返回,即返回的实体由两个EJB中的管理。 虽然

  • 问题内容: 我有一张交易表: 并且我希望选择所有特定类型(’R’)的商品,但不要立即(按照date_time字段的顺序)针对同一帐户提交另一种其他类型(’A’)交易的商品… 因此,在给出前面的示例的情况下,查询应引发以下行: (如您所见,第2行未显示,因为第3行“取消了” …第4行也被“第6行“取消了”;第7行出现了(即使帐户003属于已取消的第2行) ,这一次在第7行中不会被任何“ A”行取消;

  • 块将被拒绝 块中的第一个事务将成功,但其余事务将失败 请帮助我了解这个角落的情况。

  • 我试图创建一个环境,在这个环境中设置一个图形用户界面,当用户通过监听器修改它的组件时,另一个线程每隔X秒就向它添加新元素。(这是一个游戏,是的) 我希望游戏在一个类中,而“元素加法器”线程在另一个类中——但Java当然抱怨我无法从另一个线程修改JavaFX GUI。 我见过使用Platform.run稍后()的解决方案,但就我所知,所有这些解决方案都使用匿名内部类。我真的希望我的加法器在另一个(命

  • (这里的新手垂涎三尺)我一直在寻找将对象(事实)加载到工作内存并通过规则修改它们的方法。根据我目前的发现,我认为我应该在规则结果中使用“修改”指令,但找不到太多关于它的信息。我还遇到了一个使用modifyObject的链接,该链接假定包含2个参数,将旧对象替换为新对象[http://legacy.drools.codehaus.org/Working内存]。 考虑到我使用的是Scala对象(即不可