Spring Boot 实践折腾记(18):Spring Boot下使用JDBC Template

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mickjoust/article/details/80336876

《荀子·儒效》有云:“不闻不若闻之,闻之不若见之,见之不若知之,知之不若行之。学至于行之而止矣。行之,明也,明之为圣人。”

数据持久化是软件开发中重要的组成部分。目前,大多数软件都会使用关系数据库作为数据存储,虽然NoSQL数据存储(如MongoDB,Redis,Cassandra)越来越流行,但是大家更多的还是把NoSQL当成缓存在使用,而一些更新不是很频繁又很重要的数据,依然还是选择存放在关系型数据库里。

Java本身提供了JDBC API来与数据库进行交互,不过,它是一个低级API,需要大量的模板代码才能使用,于是Java EE平台贬提出了Java持久性API(JPA)规范,这是一个对象关系映射(ORM)框架。 像Hibernate和EclipseLink是最流行的JPA实现。还有其他流行的持久性框架,比如MyBatis和JOOQ,它们更注重SQL本身的实现。

Spring JdbcTemplate就是在JDBC API之上提供了一个很好的模板抽象,并且使用基于注解的方法提供了出色的事务管理功能。 本章会介绍如何在不使用Spring Boot的情况下使用JdbcTemplate,以及Spring Boot如何在不使用太多编码或配置的情况下轻松使用JdbcTemplate。

实战1:直接使用Spring JdbcTemplate

首先,让我们快速回顾一下过去最基础的用法,就是在Spring中,如何注册DataSource,TransactionManager和JdbcTemplate bean来使用JdbcTemplate(没有Spring Boot),并注册DataSourceInitializer bean来初始化数据库,代码如下:

@Configuration
@ComponentScan
@EnableTransactionManagement
@PropertySource(value = { "classpath:applicationNoBoot.properties" })
public class AppConfig {

    @Autowired
    private Environment env;

    @Bean
    public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer()
    {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Value("${init-db:false}")
    private String initDatabase;

    @Bean //JdbcTemplate模板
    public JdbcTemplate jdbcTemplate(DataSource dataSource)
    {
        return new JdbcTemplate(dataSource);
    }

    @Bean //配置事物管理器
    public PlatformTransactionManager transactionManager(DataSource dataSource)
    {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean //配置连接池属性
    public DataSource dataSource()
    {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
        dataSource.setUrl(env.getProperty("jdbc.url"));
        dataSource.setUsername(env.getProperty("jdbc.username"));
        dataSource.setPassword(env.getProperty("jdbc.password"));
        return dataSource;
    }

    @Bean //初始化数据库
    public DataSourceInitializer dataSourceInitializer(DataSource dataSource)
    {
        DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
        dataSourceInitializer.setDataSource(dataSource);
        ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
        databasePopulator.addScript(new ClassPathResource("dataNoBoot.sql"));
        dataSourceInitializer.setDatabasePopulator(databasePopulator);
        dataSourceInitializer.setEnabled(Boolean.parseBoolean(initDatabase));
        return dataSourceInitializer;
    }

}

此时,还需要在src / main / resources / applicationNoBoot.properties中配置JDBC连接参数。 属性如下:

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=hjf123456

然后,在src / main / resources中创建名为dataNoBoot.sql的数据库设置脚本,如下所示:

DROP TABLE IF EXISTS mans;

CREATE TABLE mans (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(100) NOT NULL,
email varchar(100) DEFAULT NULL,
PRIMARY KEY (id)
);

insert into mans(id, name, email) values(1,'mickjoust','[email protected]');
insert into mans(id, name, email) values(2,'mia','[email protected]');
insert into mans(id, name, email) values(3,'max','[email protected]');

如果希望将架构生成脚本和数据生成脚本分开,我们可以将它们分别放在单独的文件中并按如下方式添加它们:

databasePopulator.addScripts(new ClassPathResource("schema.sql"),
new ClassPathResource("seed-data.sql") );

通过这种配置,我们可以将JdbcTemplate注入到数据访问DAO组件与数据库进行交互了。

比如,我们创建一个示例Bean和服务类,如下代码:

public class Man {

    private Integer id;
    private String name;
    private String email;
//省略构造函数、get、set
}
@Repository
public class ManRepository {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional(readOnly=true)
    public List<Man> findAll() {
        return jdbcTemplate.query("select * from mans", new ManRowMapper());
    }
}
public class ManRowMapper implements RowMapper<Man> {

    @Override
    public Man mapRow(ResultSet rs, int rowNum) throws SQLException {
        Man man = new Man();
        man.setId(rs.getInt("id"));
        man.setName(rs.getString("name"));
        man.setEmail(rs.getString("email"));
        return man;
    }
}

我们会发现,大多数情况下,很多连接数据库的应用程序中都有使用上面这种类似的配置。

实战2:在Spring Boot中使用JdbcTemplate

本节,我们将尝试在Spring Boot中使用JdbcTemplate,而使用Spring Boot的自动配置功能,则不必手动配置Bean。

第一步,创建一个基于Maven的Spring Boot项目并添加spring-boot-starter-jdbc模块,如下POM:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

通过添加spring-boot-starter-jdbc模块,我们便可以获得以下自动配置功能:

  • 可以传递tomcat-jdbc- {version}.jar,用于配置DataSource bean;
  • 如果尚未明确定义DataSource bean,并且在类路径中有任何嵌入式数据库驱动程序(例如H2,HSQL或Derby),则Spring Boot将使用内存数据库设置自动注册的DataSource bean。
  • 如果尚未注册以下任何bean,则Spring Boot也将自动注册:
    • PlatformTransactionManager(DataSourceTransactionManager)
    • JdbcTemplate
    • NamedParameterJdbcTemplate
  • 可以在根类路径中配置schema.sql和data.sql文件,Spring Boot将自动使用它来初始化数据库。

第二步,初始化数据库。

在Spring Boot中,可以使用spring.datasource.initialize=属性值(默认情况下为true)来确定是否初始化数据库。 如果spring.datasource.initialize属性设置为true,则Spring Boot将使用根类路径中的schema.sql和data.sql文件来自动初始化数据库。

除了schema.sql和data.sql之外,Spring Boot将在根类路径中可用时加载schema-$ {platform} .sql和data - $ {platform} .sql文件。 这里的值是spring.datasource.platform属性的值,可以是hsqldb,h2,oracle,mysql,postgresql等,比如:

spring.datasource.schema=create-db.sql
spring.datasource.data=seed-data.sql

如果我们想关闭数据库初始化操作,则可以设置spring.datasource.initialize = false。 如果在执行脚本时出现错误,应用程序就将无法启动。 如果又想继续,可以设置spring.datasource.continueOnError = true

第三步,我们将H2数据库添加到pom.xml文件中,如下:

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
<version>1.4.197<version>
</dependency>

并在src / main / resources中创建schema.sql,如下所示:

CREATE TABLE mans
(
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(100) NOT NULL,
email varchar(100) DEFAULT NULL,
PRIMARY KEY (id)
);

创建data.sql,如下:

insert into mans(id, name, email) values(1,'mickjoust','[email protected]');
insert into mans(id, name, email) values(2,'mia','[email protected]');
insert into mans(id, name, email) values(3,'max','[email protected]');

第四步,就可以将JdbcTemplate注入到UserRepository服务中,如下所示:

@Repository
public class ManRepository {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional(readOnly=true)
    public List<Man> findAll() {
        return jdbcTemplate.query("select * from mans",
                new ManRowMapper());
    }

    @Transactional(readOnly=true)
    public Man findUserById(int id) {
        return jdbcTemplate.queryForObject("select * mans users where id=?",
                new Object[]{id}, new ManRowMapper());
    }

    public Man create(final Man man) {
        final String sql = "insert into users(name,email) values(?,?)";
        KeyHolder holder = new GeneratedKeyHolder();
        jdbcTemplate.update(new PreparedStatementCreator() {
            @Override
            public PreparedStatement createPreparedStatement(Connection connection)
                    throws SQLException {
                PreparedStatement ps = connection
                        .prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
                ps.setString(1, man.getName());
                ps.setString(2, man.getEmail());
                return ps;
            }
        }, holder);
        int newUserId = holder.getKey().intValue();
        man.setId(newUserId);
        return man;
    }
}

这里,ManRowMapper使用前一小节里的类。

到这里,我们已经学会了如何快速开始使用嵌入式数据库。 但是如果我们是想使用一些正式的数据库,比如如MySQL,Oracle和PostgreSQL呢?

很简单!在application.properties文件中配置数据库属性即可,Spring Boot同样会将使用这些JDBC参数来配置给DataSource bean,比如添加mysql访问,如下:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=hjf123456

如果我们还想拥有更多的控制权,并自己配置DataSource bean,则可以在配置类中进行配置。 因为只要手动注册了DataSource bean,Spring Boot将不会使用自动去配置它。

在默认情况下,Spring Boot会引入tomcat-jdbc- {version} .jar中的org.apache.tomcat.jdbc.pool.DataSource来配置DataSource bean。除此之外,Spring Boot一下检查以下连接池的可用性,并使用第一个可用的类的类路径。

  • org.apache.tomcat.jdbc.pool.DataSource
  • com.zaxxer.hikari.HikariDataSource
  • org.apache.commons.dbcp.BasicDataSource
  • org.apache.commons.dbcp2.BasicDataSource

比如,使用HikariDataSource,首先,需要排除Tomcat的JDBC,并添加HikariCP依赖,如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jdbc</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
</dependency>

然后,按如下方式设置HikariCP连接池设置:

spring.datasource.hikari.allow-pool-suspension=true
spring.datasource.hikari.connection-test-query=SELECT 1
spring.datasource.hikari.transaction-isolation=TRANSACTION_READ_COMMITTED
spring.datasource.hikari.connection-timeout=45000

Spring Boot中常见的配置方式前缀如下:

spring.datasource.tomcat.*= # Tomcat Datasource specific settings
spring.datasource.hikari.*= # Hikari DataSource specific settings
spring.datasource.dbcp2.*= # Commons DBCP2 specific setting

代码示例:boot-database/jdbc

小结

在本章中,您学习了如何在Spring Boot中轻松使用JdbcTemplate,以及如何连接到H2和MySQL等数据库。 本章还介绍了如何使用SQL脚本初始化数据库。 您还了解了如何使用各种连接池库。

参考资源

1、Spring jdbc
2、Spring Boot


持续践行,我们一路同行。

猜你喜欢

转载自blog.csdn.net/mickjoust/article/details/80336876
今日推荐