Spring Data 配置和 Postgres 数据库集成(无 xml 配置)

Posted

技术标签:

【中文标题】Spring Data 配置和 Postgres 数据库集成(无 xml 配置)【英文标题】:Spring Data config and Postgres database integration (NO xml configuration) 【发布时间】:2016-02-28 10:15:41 【问题描述】:

我有一个基于 Spring Framework 的项目,它仅基于 Java 配置进行初始化。这意味着不需要使用 web.xml 文件。

您可以在下图中看到项目的结构:

使用的技术:

Java 7 Spring框架4.2.1.RELEASE 休眠 ORM 5.0.4.Final Spring Tool Suite IDE 3.6.2 Maven 3 雄猫 7

初始化配置文件

“主”类称为 AppInitializer,它位于 initializer 文件夹下

AppInitializer

public class AppInitializer implements WebApplicationInitializer 

    private static final String CONFIG_LOCATION = "com.project.app.config";
    private static final String MAPPING_URL = "/";

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException 

        // Create the 'root' Spring application context
        WebApplicationContext context = getContext();

        // Manage the lifecycle of the root application context
        servletContext.addListener(new ContextLoaderListener(context));

        // Register and map the dispatcher servlet
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet",
                new DispatcherServlet(context));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping(MAPPING_URL);

    

    private AnnotationConfigWebApplicationContext getContext() 
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.setConfigLocation(CONFIG_LOCATION);

        return context;
    


..而我的配置类驻留在 config 文件夹中

WebMvcConfig

@EnableWebMvc
@Configuration
@ComponentScan(basePackages =  "com.project.app" )
public class WebMvcConfig extends WebMvcConfigurerAdapter 

    @Autowired
    private Environment env;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) 
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    

    @Override
    public void addViewControllers(ViewControllerRegistry registry) 
        registry.addViewController("/").setViewName("hello");
    

    @Bean
    public ApplicationContextProvider applicationContextProvider() 
        return new ApplicationContextProvider();
    


数据库配置文件

此时我想在我的项目中添加一个 postgres 数据库,因此我在 CONFIG_LOCATION 中创建了一个名为 db 的文件夹,这样春天就会“拿起" @Configuration 类。(使用 PGAdmin 创建新数据库后).. 我创建了以下配置类。

数据源

@Component
@PropertySource("classpath:application.properties")
public class DataSources 

    @Autowired
    private Environment env;

    @Bean
    @Primary
    public DataSource dataSource() 
        org.apache.tomcat.jdbc.pool.DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource();

        String url = env.getProperty(SystemSettings.DS_URL);
        String user = env.getProperty(SystemSettings.DS_USERNAME);
        String pass = env.getProperty(SystemSettings.DS_PASSWORD);

        ds.setDriverClassName("org.postgresql.Driver");
        ds.setUrl(url);
        ds.setUsername(user);
        ds.setPassword(pass);

        return ds;
    


SystemSettings 保存数据库的用户名、密码和 url

@Service
@Configuration
public class SystemSettings implements Settings   

    public static final String DS_URL = "datasource.app.url";
    public static final String DS_USERNAME = "datasource.app.username";
    public static final String DS_PASSWORD = "datasource.app.password";

    @Autowired
    private Environment env;

    @Override
    public String get(String key) 
        return env.getProperty(key);
    


这些值是从 application.properties 文件中提取的,如 DataSources 类中所示。

spring.jpa.database=POSTGRESQL spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=更新 datasource.app.type=POSTGRESQL datasource.app.url=jdbc:postgresql://localhost:5432/app datasource.app.username=用户 datasource.app.password=pass

实体和存储库

我继续添加一个实体类,它将代表项目中的一个简单表。 它位于 services/entities 文件夹内

停止JPA

@Entity
@Table(name = "stop")
public class StopJPA 

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    @Column(name = "description")
    private String stopDescription;

    @Column(name = "idStop")
    private String idStop;

    public StopJPA() 
    

    public StopJPA(String stopDescription, String idStop) 
        this.stopDescription = stopDescription;
        this.idStop = idStop;
    

    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    public String getStopDescription() 
        return stopDescription;
    

    public void setStopDescription(String stopDescription) 
        this.stopDescription = stopDescription;
    

    public String getIdStop() 
        return idStop;
    

    public void setIdStop(String idStop) 
        this.idStop = idStop;
    


然后我为这个表创建了一个存储库接口,它扩展了一个 CrudRepository

停止存储库

/**
 * Repository interface for StopJPA entities.
 */
@Repository
@RepositoryRestResource(collectionResourceRel = "stop", path = "stop")
public interface StopRepository extends CrudRepository<StopJPA, Long> 

    StopJPA findById(@Param("id") Long id);


问题

在所有这些设置和配置之后,我设法让项目运行,但表没有在数据库中创建。

我在配置步骤中遗漏了什么? 如何让 Spring 扫描 JPA 实体并创建数据库?

我的主要意图是配置Spring(通过使用Spring Data JPA)和Hibernate,以使它们在不使用的情况下协同工作xml 配置文件,并且没有 Spring BOOT 依赖项。后者意味着必须“手动”配置环境。



更新

我在 DataSources 类中添加了一些配置,并将其重命名为

PersistenceContext

@Component
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
public class PersistenceContext 

    @Autowired
    private Environment env;

    @Bean
    @Primary
    public DataSource dataSource() throws ClassNotFoundException 
        org.apache.tomcat.jdbc.pool.DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource();

        String url = env.getProperty(SystemSettings.DS_URL);
        String user = env.getProperty(SystemSettings.USERNAME);
        String pass = env.getProperty(SystemSettings.DS_PASSWORD);

        ds.setDriverClassName("org.postgresql.Driver");
        ds.setUrl(url);
        ds.setUsername(user);
        ds.setPassword(pass);

        return ds;
    

    @Bean
    LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) 
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource);
        entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        entityManagerFactoryBean.setPackagesToScan("com.project.app.services.entities");

        Properties jpaProperties = new Properties();

        // Configures the used database dialect. This allows Hibernate to create SQL
        // that is optimized for the used database.
        jpaProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));

        // Specifies the action that is invoked to the database when the Hibernate
        // SessionFactory is created or closed.
        jpaProperties.put("hibernate.hbm2ddl.auto",
                env.getRequiredProperty("hibernate.hbm2ddl.auto"));  

        // If the value of this property is true, Hibernate writes all SQL
        // statements to the console.
        jpaProperties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));

        // If the value of this property is true, Hibernate will format the SQL
        // that is written to the console.
        jpaProperties.put("hibernate.format_sql", env.getRequiredProperty("hibernate.format_sql"));

        entityManagerFactoryBean.setJpaProperties(jpaProperties);

        return entityManagerFactoryBean;
    

    /**
     * Because we are using JPA, we have to create a transaction manager bean that integrates the
     * JPA provider with the Spring transaction mechanism. We can do this by using the
     * JpaTransactionManager class as the transaction manager of our application.
     *
     * We can configure the transaction manager bean by following these steps:
     *
     * -> Create a new JpaTransactionManager object. -> Configure the entity manager factory whose
     * transactions are managed by the created JpaTransactionManager object.
     **/
    @Bean
    JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) 
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory);
        return transactionManager;
    

Ans 还更新了属性文件

hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect hibernate.hbm2ddl.auto=创建-删除 hibernate.show_sql=false hibernate.format_sql=true

datasource.app.type=POSTGRESQL datasource.app.driverClassName=org.postgresql.Driver datasource.app.url=jdbc:postgresql://localhost:5432/app datasource.app.username=user datasource.app.password=pass

不幸的是,我得到了这个错误

严重:无法创建池的初始连接。 java.sql.SQLException: org.postgresql.Driver 在 ...... 引起: java.lang.ClassNotFoundException: org.postgresql.Driver 在......

我不知道为什么它给了我这个例外。 maven 依赖项在那里,驱动程序也在类路径中。 .有什么帮助吗?

【问题讨论】:

据我所知,这在 JPA 中是不可能的。您需要 Hibernate 并对其进行配置。 【参考方案1】:

JPA 没有指定 DDL 生成/迁移。默认情况下,Hibernate 不进行 DDL 生成/迁移,但如果您 configure your persistence.xml properly,则可以这样做。

【讨论】:

如果我正确,属性文件中的以下行应该这样做 > spring.jpa.hibernate.ddl-auto=update JPA 确实在 JPA 2.1 中指定了 DDL GENERATION ...【参考方案2】:

嗯,这都是关于 Classpath 的。我的 pom.xml 中已经有了依赖项,但我需要做的是

    范围添加为提供,然后 在Tomcat的Library下添加jar (..tomcat7_home_path/lib/postgres jar)。

Pom

        <!-- Postgres -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.4-1205-jdbc42</version>
            <scope>provided</scope>
        </dependency>

Why must the JDBC driver be put in TOMCAT_HOME/lib folder?

【讨论】:

以上是关于Spring Data 配置和 Postgres 数据库集成(无 xml 配置)的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data Rest:“日期为空”查询引发 postgres 异常

Spring Data JPA + Postgres - 无法使用一对一映射插入数据

Spring Data JPA 方法或查询以使用 Postgres 列执行算术运算

使用带有 Spring Data 和绑定参数的 Postgres JSONB 查询失败并出现 InvalidDataAccessApiUsageException

Spring Data / Hibernate 使用 Postgres 保存实体,在冲突更新某些字段时使用插入

如何使用 Spring Data / JPA 插入 Postgres Array 类型列?