LoginSignup
9
5

More than 5 years have passed since last update.

Spring Data JDBC Preview

Last updated at Posted at 2018-01-06

(2019/01/02追記) この記事は更新されていません

この記事に書いてあるコードの大半はすでに動きません。一応記録用に残しておきますが、更新の予定はありません。
確実な情報が必要な場合は公式のドキュメントをご参照ください。

@kazuki43zooさんが素晴らしい解説を書かれているので、そちらもご一読をおすすめします。
Spring Data JDBC 1.0.0.BUILD-SNAPSHOT(-> 1.0.0.RELEASE)を試してみた

また、Spring Data JDBCはまだまだ成長途中のプロジェクトです。publishされたドキュメントだけでは辿れない情報もあるため、以下のリンクが役に立つかもしれません。


Spring Data JDBCというプロジェクトができていたので、試してみます。

SpringのRDBアクセスといえばJdbcTemplateSpring Data JPAなどがあります。
まだCRUDサポートレベルですが、将来的にSpring Data JDBCもDBアクセスの有力な選択肢となるかもしれません。

今回試したソースはこちらです。

!!!2018年1月現在、Spring Data JDBCはBUILD-SNAPSHOTです。将来的にこの記事中のコードが動かなくなる可能性が十分あります。!!!

環境

  • jdk 1.8
  • Spring Boot 2.0.0.M7
  • Maven 3

pom.xml

Spring Bootプロジェクトを作成したら、pom.xmlにdependencyを追加します。DBはH2 Databaseにします。

pom.xml
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jdbc</artifactId>
            <version>1.0.0.BUILD-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>

テーブル定義

schema.sqlにテーブル定義を書きます。

schema.sql
create table employee (
    employee_number bigint primary key auto_increment,
    firstname varchar NOT NULL,
    lastname varchar NOT NULL,
    age int NOT NULL,
    hired_at date
);

Repositoryの作成

テーブルに対応したエンティティクラスを作成します。IDとなるフィールドには@Idアノテーションをつけます。
(Getter/Setter書くのが面倒だったのでLombokを使っていますw)

Employee.java
@Data
public class Employee {

    @Id
    private Long employeeNumber;
    private String firstname;
    private String lastname;
    private Integer age;
    private LocalDate hiredAt;

}

エンティティを作成したら、CrudRepositoryを継承したRepositoryを作ります。

EmployeeRepository.java
public interface EmployeeRepository extends CrudRepository<Employee, Long> {
}

Bean定義

Spring Data JDBCを動かすには

  • @EnableJdbcRepositories
  • DataAccessStrategyのBean定義

が必要になります。
またカラム名をスネークケースにしたい場合は、エンティティのフィールド名<=>カラム名の変換を行うNamingStrategyを定義します。

SpringDataJdbcDemoApplication.java
@SpringBootApplication
@EnableJdbcRepositories
public class SpringDataJdbcDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringDataJdbcDemoApplication.class, args);
    }

    @Autowired
    JdbcMappingContext context;
    @Autowired
    DataSource datasource;

    @Bean
    DataAccessStrategy dataAccessStrategy() {
        return new DefaultDataAccessStrategy(
                new SqlGeneratorSource(context),
                new NamedParameterJdbcTemplate(datasource),
                context);
    }

    @Bean
    NamingStrategy namingStrategy() {
        return new CustomNamingStrategy();
    }
}
CustomNamingStrategy.java
public class CustomNamingStrategy extends DefaultNamingStrategy {

    @Override
    public String getColumnName(JdbcPersistentProperty property) {
        String propertyName = property.getName();
        return camelToSnake(propertyName);
    }

    @Override
    public String getTableName(Class<?> type) {
        return super.getTableName(type);
    }

    public String camelToSnake(String original) {
        char[] chars = original.toCharArray();
        char[] buff = new char[chars.length + 10];

        int j = 0;
        for(int i = 0; i < chars.length; i++) {
            char c = chars[i];
            if(buff[buff.length - 1] != ' ') {
                buff = Arrays.copyOf(buff, buff.length + 10);
            }
            if (Character.isUpperCase(c)) {
                buff[j++] = '_';
                buff[j++] = Character.toLowerCase(c);
            } else {
                buff[j++] = c;
            }
        }
        return new String(buff).trim();
    }

}

動かしてみる

さっそく動かしてみます。

@ExtendWith(SpringExtension.class)
@SpringBootTest
public class SpringDataJdbcDemoApplicationTests {

    @Autowired
    EmployeeRepository repo;

    @Test
    public void contextLoads() {
    }

    @Test
    public void test1() {
        Employee employee = new Employee();
        employee.setFirstname("John");
        employee.setLastname("Do");
        employee.setAge(30);
        employee.setHiredAt(LocalDate.of(2012, 4, 1));

        // Insert
        employee = repo.save(employee);
        Long employeeNumber = employee.getEmployeeNumber();

        Optional<Employee> insertedOpt = repo.findById(employeeNumber);
        assertTrue(insertedOpt.isPresent());
        Employee inserted = insertedOpt.get();
        assertAll("insert",
                () -> assertEquals(inserted.getEmployeeNumber(), employeeNumber),
                () -> assertEquals(inserted.getFirstname(), "John"),
                () -> assertEquals(inserted.getLastname(), "Do"),
                () -> assertEquals(inserted.getAge(), Integer.valueOf(30)),
                () -> assertEquals(inserted.getHiredAt(), LocalDate.of(2012, 4, 1)));

        // Update
        employee.setAge(31);
        repo.save(employee);

        Optional<Employee> updatedOpt = repo.findById(employeeNumber);
        assertTrue(updatedOpt.isPresent());
        Employee updated = updatedOpt.get();
        assertEquals(updated.getAge(), Integer.valueOf(31));

        // Delete
        repo.delete(employee);

        Optional<Employee> deleted = repo.findById(employeeNumber);
        assertTrue(!deleted.isPresent());
    }
}

MyBatis連携

試してないですが、MyBatisと連携させることも可能らしいです。
Repositoryのメソッドが呼ばれると、対応した名前のMapperのメソッドが実行されるようです。

9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5