** Most of the code in this article doesn't work anymore. I will keep it for the record, but there are no plans to update it. ** ** Please refer to the Official Document if you need reliable information.
@ kazuki43zoo has written a wonderful commentary, so I recommend you to read that as well. I tried Spring Data JDBC 1.0.0.BUILD-SNAPSHOT (-> 1.0.0.RELEASE)
Also, Spring Data JDBC is still a growing project. The following links may be useful, as some information cannot be traced by the published document alone.
I have a project called Spring Data JDBC, so I will try it.
Speaking of RDB access of Spring, JdbcTemplate and [Spring Data JPA](https://projects.spring.io/spring-data- There are jpa /) and so on. Although still at CRUD support level, Spring Data JDBC may also be a viable option for DB access in the future.
The source I tried this time is here.
!!! As of January 2018, Spring Data JDBC is BUILD-SNAPSHOT. There is a good chance that the code in this article will get stuck in the future. !!!
pom.xml
After creating the Spring Boot project, add the dependency to pom.xml. DB should be 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>
Write the table definition in 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
);
Create the entity class corresponding to the table. Annotate the ID field with @Id
.
(I use Lombok because it was troublesome to write Getter / Setter w)
Employee.java
@Data
public class Employee {
@Id
private Long employeeNumber;
private String firstname;
private String lastname;
private Integer age;
private LocalDate hiredAt;
}
After creating the entity, create a Repository that inherits CrudRepository
.
EmployeeRepository.java
public interface EmployeeRepository extends CrudRepository<Employee, Long> {
}
How to run Spring Data JDBC
@EnableJdbcRepositories
DataAccessStrategy
will become necessary. If you want the column name to be a snake case, define a NamingStrategy that converts the field name <=> column name of the entity.
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();
}
}
I will move it at once.
@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());
}
}
I haven't tried it, but it seems possible to link it with MyBatis. When the Repository method is called, it seems that the Mapper method with the corresponding name is executed.
Recommended Posts