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

Spring数据CRUD存储库:保存方法不起作用

赵英哲
2023-03-14

这根本不是关于Spring靴的。

我的英语可以更好。

使用下面的Spring Data配置,我正在尝试执行DML请求。

恰好是< code>CrudRepository#save方法。

然而,执行Spring的CrudRepository#保存方法,我接下来要做的是:

  1. 只有选择由hibernate.show_sql功能记录。
  2. 没有执行任何“插入”或“更新”语句来hibernate.show_sql日志记录。
  3. 数据库根本没有变化。

====================================================

不确定,但它看起来像一个交易问题。

当时似乎没有交易,

因此,在事务之外,CRUD Repos无法执行DML请求,包括CrudRepository#sav

也许是配置有问题?请看看,并随时询问任何其他信息。

更新:下一个不良实践解决方法帮助我实现了“更新”语句的执行。

//(autowired, shared entity manager)
entityManager.joinTransaction();
repository.save(user);

然而,这仍然是一种糟糕的做法。在这种情况下,Spring失去了作用。无论如何,我需要使用基于声明性代码的交易管理。问题仍然悬而未决:我的配置有什么问题@事务注释仍然不起作用

用户域实体:

@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@Entity
@Table(name = "users")
public class User
{
    @Id
    @Column(name = "id_pk", length = 11)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int idPk;

    @Column(name = "user_id", length = 25, nullable = false, unique = true)
    private String userId;

    @Column(name = "email_addr", length = 120)
    private String email;
}

特定于域的Spring Data CRUD Repository声明

public interface UserRepository extends CrudRepository<User, Integer> {
  //nothing specific
}

Spring(无启动)基于代码的配置:

@EnableJpaRepositories(basePackages = "***",
        transactionManagerRef = "jpaTransactionManager")
@EnableTransactionManagement
public class DataConfig
{
    @Bean
    public EntityManagerFactory entityManagerFactory()
    {
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setDataSource(dataSource());
        factory.setPackagesToScan(DOMAIN_ENTITY_SCAN_PACKAGE);
        factory.setJpaVendorAdapter(getVendorAdapter());
        factory.afterPropertiesSet();
        return factory.getObject();
    }

    private HibernateJpaVendorAdapter getVendorAdapter()
    {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setShowSql(Boolean.TRUE);
        return vendorAdapter;
    }

    @Bean
    public JpaTransactionManager jpaTransactionManager()
    {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory());
        txManager.afterPropertiesSet();
        return txManager;
    }
}

共有2个答案

聂鹏云
2023-03-14

我不明白,你是如何初始化数据源属性的?我在你给定的代码中看不到。

factory.setDataSource(dataSource());

您应该设计如下配置类。同时使用 :

entityManagerFactoryRef="entityManagerFactory",
transactionManagerRef="jpaTransactionManager"

从 yaml 或属性文件中读取Hibernate属性。

并设置您的数据源

配置类:DataConfig

/**
 * @author Som
 *
 */

@Configuration
@EnableJpaRepositories(basePackages="package-name",
                       entityManagerFactoryRef="entityManagerFactory",
                       transactionManagerRef="jpaTransactionManager")
@EnableTransactionManagement
@PropertySource(value = { "classpath:application.yml" })
public class DataConfig {
    
    @Autowired
    private Environment environment;
    
    @Value("${datasource.myapp.maxPoolSize:10}")
    private int maxPoolSize;
    
    
    /**
     * Populate DataSourceProperties object directly from application.yml 
     *       *
     */
    
    @Bean
    @Primary
    @ConfigurationProperties(prefix = "datasource.myapp")
    public DataSourceProperties dataSourceProperties(){
        return new DataSourceProperties();
    }
    
    
    /**
     * Configure HikariCP pooled DataSource.
     * 
     */
    @Bean
    public DataSource dataSource() {
        DataSourceProperties dataSourceProperties = dataSourceProperties();
        HikariDataSource dataSource = (HikariDataSource) DataSourceBuilder
                .create(dataSourceProperties.getClassLoader())
                .driverClassName(dataSourceProperties.getDriverClassName())
                .url(dataSourceProperties.getUrl())
                .username(dataSourceProperties.getUsername())
                .password(dataSourceProperties.getPassword())
                .type(HikariDataSource.class)
                .build();
        
        dataSource.setMaximumPoolSize(maxPoolSize);
        return dataSource;
    }
    
    
    /**
     * Entity Manager Factory setup.
     * 
     */
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException {
        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        factoryBean.setDataSource(dataSource());
        factoryBean.setPackagesToScan(new String[] { "package-name" });
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter());
        factoryBean.setJpaProperties(jpaProperties());
        return factoryBean;
    }
    
    
    
    /**
     * Provider specific adapter.
     * 
     */
    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
        return hibernateJpaVendorAdapter;
    }
 
    /**
     * Hibernate properties.
     * 
     */
    private Properties jpaProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("datasource.myapp.hibernate.dialect"));
        properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("datasource.myapp.hibernate.hbm2ddl.method"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("datasource.myapp.hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("datasource.myapp.hibernate.format_sql"));
        if(StringUtils.isNotEmpty(environment.getRequiredProperty("datasource.myapp.defaultSchema"))){
            properties.put("hibernate.default_schema", environment.getRequiredProperty("datasource.myapp.defaultSchema"));
        }
        return properties;
    }
 
    @Bean
    @Autowired
    public PlatformTransactionManager jpaTransactionManager(EntityManagerFactory emf) {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(emf);
        return txManager;
    }

}

应用程序.yaml

server:
  port: 8081
  servlet:
    context-path: /CRUDApp
---
spring:
  profiles: local,default
datasource:
  myapp:
    url: jdbc:h2:~/test
    username: SA
    password:
    driverClassName: org.h2.Driver
    defaultSchema:
    maxPoolSize: 10
    hibernate:
      hbm2ddl.method: create-drop
      show_sql: true
      format_sql: true
      dialect: org.hibernate.dialect.H2Dialect
---
方飞翼
2023-03-14

终于,我找到了解决我的问题的办法。

因为我使用的Spring没有启动部分,所以我必须配置定制的WebApplicationInitializer来让Spring管理应用程序入口点:

public class MainWebAppInitializer implements WebApplicationInitializer
{
    @Override
    public void onStartup(final ServletContext sc)
    {
        AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
        root.register(WebAppConfiguration.class, DataConfig.class);
        sc.addListener(new ContextLoaderListener(root));
        
        ...other not related code ommited
    }
}

因此,由于我已经使用注释配置Web应用程序#注册了两个配置类(WebApp配置.class,数据配置.class),所以我认为用@Configuration注释配置将是Redundand。

当时我错了。

要正确注册事务管理器,您应该使用@Configuration来注释您的 Jpa 配置类。

因此,我设法用@Configuration注释了我的配置类,这解决了我的问题。

现在,SpringCRUDRepositories能够对数据库运行DML查询(借助#save方法)。确切地说:现在存储库能够打开自己的事务并根据这些事务运行所需的查询。

 类似资料:
  • 我试图创建一些切入点和之前的建议为存储库,以便能够在Spring启动的Spring数据中过滤一些存储库的实体管理器。我在项目中也有Web和服务层,AounLogging适用于两者。但是我不能为存储库做同样的事情。我已经挣扎了2天,我尝试了很多东西来修复它。我几乎阅读了关于此的每个文档、问题和线程(代理问题CGlib和JDK代理等)。我使用jhipster创建项目。 除了@Pointcut和Crud

  • 我需要使用spring@Cacheable注释缓存对MongoDB的调用: 不幸的是,使用@Cacheable注释接口中的任何方法都会导致以下异常: 我正在寻找一种方法来缓存对DB的调用(这相当昂贵)。有什么想法吗?

  • 我在使用JPA时遇到了一些困难。我没有得到任何异常,但我不能保存任何东西到数据库。我从Hibernate到Jpa,在那里一切都工作得很好。下面是我的文件 Application.Properties: 存储库: 服务: 我在提交表单时得到了200的响应,但在数据库中找不到数据

  • 我正在使用Spring Batch和JPA处理一个批处理作业并执行更新。我正在使用默认的存储库实现。 并且我正在使用一个repository.save将修改后的对象保存在处理器中。而且,我没有在处理器或编写器中指定任何@Transactional注释。 下面是我的步骤,读取器和写入器配置:另外,我的config类是用EnableBatchProcessing注释的 在writer中,这就是我使用的

  • 我有一个数据已经保存在我的数据库基于我的存储库和服务。我想保存另一个数据与邮递员只改变播放器id。但它不是创建一个新的实体数据。它更新现有的实体数据。我的问题是如何更新一个数据由我的服务当它找到一个现有的id。但当它找到一个新的id将保存一个新的数据到数据库。 这是我的回购: 这是我的服务: