Spring Bootにおけるデータベースアクセスの実装と設定ガイド

JDBCの基本設定と自動構成の仕組み

Spring Bootでは、リレーショナルデータベース(SQL)およびNoSQLへのアクセスをSpring Dataのアーキテクチャを通じて抽象化・統一しています。JDBCを利用する場合、以下の依存関係をプロジェクトに追加します。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

接続情報の設定はapplication.ymlで行います。タイムゾーンや文字コードの指定を含めた標準的な設定例を示します。

spring:
  datasource:
    username: db_admin
    password: secure_password
    url: jdbc:mysql://127.0.0.1:3306/app_db?serverTimezone=Asia/Tokyo&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver

デフォルトでは、Tomcat JDBCプールがデータソースとして採用されます。関連するプロパティはDataSourcePropertiesクラスで管理されています。

自動構成の内部動作

データソースの自動構成はorg.springframework.boot.autoconfigure.jdbc.DataSourceConfigurationクラスで定義されています。条件注釈(@ConditionalOnClass、@ConditionalOnPropertyなど)により、クラスパスに存在するライブラリに応じて最適な接続プールが選択されます。

abstract class DataSourceConfiguration {
    protected <T> T buildDataSource(DataSourceProperties props, Class<? extends DataSource> targetClass) {
        return (T) props.initializeDataSourceBuilder().type(targetClass).build();
    }

    @ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
    @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true)
    static class TomcatPool extends DataSourceConfiguration {
        @Bean
        @ConfigurationProperties(prefix = "spring.datasource.tomcat")
        public org.apache.tomcat.jdbc.pool.DataSource resolveDataSource(DataSourceProperties props) {
            org.apache.tomcat.jdbc.pool.DataSource ds = buildDataSource(props, org.apache.tomcat.jdbc.pool.DataSource.class);
            String validationSql = DatabaseDriver.fromJdbcUrl(props.determineUrl()).getValidationQuery();
            if (validationSql != null) {
                ds.setTestOnBorrow(true);
                ds.setValidationQuery(validationSql);
            }
            return ds;
        }
    }
}

HikariCP、DBCP2、Druidなどの別実装を使用したい場合は、spring.datasource.typeプロパティで完全修飾クラス名を指定することで上書き可能です。指定された型はDataSourceBuilder内のリフレクション処理によってインスタンス化され、プロパティがバインドされます。

Druidコネクションプールの導入と監視機能の有効化

Alibabaが開発したDruidは、高性能なコネクションプールであると同時に、SQL実行状況やプール状態を詳細に監視できる機能を標準搭載しています。Spring Boot 2.x以降のデフォルトはHikariCPですが、typeプロパティでDruidへ切り替えられます。

プロパティ設定

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/app_db?serverTimezone=Asia/Tokyo&characterEncoding=utf-8
    username: db_admin
    password: secure_password
    # プール基本設定
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    # 検証・維持設定
    validationQuery: SELECT 1
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    # 監視・セキュリティフィルター
    filters: stat,wall,log4j
    poolPreparedStatements: true
    maxPoolPreparedStatementPerConnectionSize: 20

監視コンソールとWeb統計の有効化

Druidの管理画面とリクエスト統計を有効化するには、設定クラスでServletとFilterを明示的にBean登録します。

@Configuration
public class DruidMonitorConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }

    @Bean
    public ServletRegistrationBean<StatViewServlet> druidStatViewServlet() {
        ServletRegistrationBean<StatViewServlet> registration = new ServletRegistrationBean<>(new StatViewServlet(), "/sys/druid/*");
        Map<String, String> servletParams = new HashMap<>();
        servletParams.put("loginUsername", "monitor_admin");
        servletParams.put("loginPassword", "monitor_pass");
        servletParams.put("allow", ""); // 全IP許可
        servletParams.put("deny", "192.168.10.99"); // 特定IP拒否
        registration.setInitParameters(servletParams);
        return registration;
    }

    @Bean
    public FilterRegistrationBean<WebStatFilter> druidWebStatFilter() {
        FilterRegistrationBean<WebStatFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new WebStatFilter());
        Map<String, String> filterParams = new HashMap<>();
        filterParams.put("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/sys/druid/*");
        registration.setInitParameters(filterParams);
        registration.addUrlPatterns("/*");
        return registration;
    }
}

設定完了後、http://localhost:8080/sys/druid/login.htmlへアクセスすることで、接続プールの状態や実行されたSQLの統計情報を確認できます。主要な設定項目としては、初期接続数(initialSize)、最大アクティブ数(maxActive)、接続検証クエリ(validationQuery)、および監視用フィルター(filters)などが挙げられます。これらのパラメータを適切に調整することで、本番環境での安定性と可観測性を確保できます。

MyBatisとの連携設定

Spring Boot公式のスターターは提供されていませんが、MyBatisコミュニティが提供するmybatis-spring-boot-starterを利用することで簡単に統合できます。

<dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis-spring-boot-starter</artifactId>
   <version>2.3.1</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

application.ymlでは、データソース情報に加え、型エイリアスのパッケージスキャン、Mapper XMLの配置場所、およびキャメルケース変換の有効化などを定義します。

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/app_db?serverTimezone=Asia/Tokyo
    username: db_admin
    password: secure_password
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  type-aliases-package: com.example.domain.model
  mapper-locations: classpath:mappings/**/*.xml
  config-location: classpath:mybatis/custom-config.xml
  configuration:
    map-underscore-to-camel-case: true

Mapperインターフェースは、アノテーションベースでSQLを直接記述する方法と、XMLファイルに分離する方法の両方をサポートしています。以下の例ではアノテーションを用いたCRUD操作を示しています。

@Mapper
public interface EmployeeMapper {

    @Select("SELECT * FROM employee WHERE id = #{id}")
    Employee selectById(Integer id);

    @Delete("DELETE FROM employee WHERE id = #{id}")
    int deleteById(Integer id);

    @Insert("INSERT INTO employee(name, department) VALUES(#{name}, #{department})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insertRecord(Employee emp);

    @Update("UPDATE employee SET name = #{name}, department = #{department} WHERE id = #{id}")
    int updateRecord(Employee emp);
}

インターフェースをSpringコンテナに認識させるには、各インターフェースに@Mapperを付与するか、起動クラスで@MapperScan("com.example.persistence")のようにパッケージを指定します。実装の流れは、依存関係の追加、YAMLでのパス設定、Mapperインターフェースの作成、そしてサービス層からの呼び出しという標準的な手順で完了します。

Spring Data JPAの活用とエンティティマッピング

Spring Data JPAは、JPA仕様に基づいたリポジトリパターンを簡潔に実装できるモジュールです。複雑なデータアクセスロジックを大幅に削減できます。

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

エンティティ定義と主鍵戦略

エンティティクラスでは、@Entityや@Tableでテーブルマッピングを定義し、@Idと@GeneratedValueで主鍵戦略を設定します。JPAが標準で提供する生成戦略には、IDENTITY(DBの自動インクリメント)、SEQUENCE、TABLE、AUTOなどがあります。

@Entity
@Table(name = "sys_account")
public class Account {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "login_id", length = 50, nullable = false)
    private String loginId;
    
    @Column
    private String emailAddress;

    // getters and setters
}

要件に応じてカスタムIDジェネレーターを実装することも可能です。IdentifierGeneratorインターフェースを実装し、エンティティ側で@GenericGeneratorと紐付けることで、独自の採番ロジックを適用できます。

public class TimestampIdGenerator implements IdentifierGenerator {
    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object object) {
        return System.currentTimeMillis();
    }
}

@Entity
public class Member {
    @Id
    @GenericGenerator(name = "tsGenerator", strategy = "com.example.infra.TimestampIdGenerator")
    @GeneratedValue(generator = "tsGenerator")
    private Long memberId;
    // other fields...
}

リポジトリインターフェースと自動クエリ生成

データアクセス層はJpaRepositoryを継承するだけで、基本的なCRUDメソッドが自動実装されます。さらに、メソッド名からクエリを自動生成する機能により、SQLを記述せずに複雑な検索も実現できます。

public interface AccountRepository extends JpaRepository<Account, Long> {
    List<Account> findByLoginIdContainingAndEmailAddress(String loginPart, String email);
}

JPA動作設定と検証

動作確認用の設定では、ddl-autoでスキーマの自動更新を制御し、show-sqlで実行されるクエリをログ出力します。

spring:
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    properties:
      hibernate:
        format_sql: true

テストコードでは、リポジトリを通じてデータの登録、検索、削除を簡潔に実行できます。主キーが存在する場合は更新、不存在の場合は挿入というsave()メソッドの挙動も確認できます。

@SpringBootTest
class JpaIntegrationTest {

    @Autowired
    private AccountRepository accountRepo;

    @Test
    void verifyCrudOperations() {
        List<Account> allRecords = accountRepo.findAll();
        Optional<Account> target = accountRepo.findById(1L);
        
        accountRepo.deleteById(1L);
        
        Account newAcc = new Account();
        newAcc.setLoginId("test_user");
        newAcc.setEmailAddress("test@example.com");
        accountRepo.save(newAcc);

        List<Account> filtered = accountRepo.findByLoginIdContainingAndEmailAddress("test", "example.com");
    }
}

タグ: SpringBoot JDBC Druid MyBatis SpringDataJPA

9月20日 02:39 投稿