服务端开发(3) Spring Data JDBC、JPA
2023-08-09 14:53:19
# NJU
# 服务端开发
1. 使用原始JDBC访问数据库
1 2 3 4 5 6 7 8 9 10 11
| Connection connection = dataSource.getConnection(); String sql = "select id, name, type from Ingredient"; PreparedStatement statement = connection.prepareStatement(sql); ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { Ingredient ingredient = new Ingredient( resultSet.getString("id"), resultSet.getString("name"), Ingredient.Type.valueOf(resultSet.getString("type"))); ingredients.add(ingredient); }
|
问题:样板式代码、SQLException
2. 使用JdbcTemplate
2.1 引入依赖
1 2 3 4 5 6 7 8 9
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency>
|
2.2 H2配置与访问
1 2 3 4
| spring: datasource: generate-unique-name: false name: tacocloud
|
http://localhost:8080/h2-console
驱动:org.h2.Driver
JDBC URL:jdbc:h2:mem:tacocloud
用户名:sa
2.3 IngredientRepository的实现
注入JdbcTemplate
1 2 3 4 5
| private JdbcTemplate jdbcTemplate;
public JdbcIngredientRepository(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; }
|
@Repository
接口:RowMapper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| jdbcTemplate.query( "select id, name, type from Ingredient", this::mapRowToIngredient);
jdbcTemplate.update( "insert into Ingredient (id, name, type) values (?, ?, ?)", ingredient.getId(), ingredient.getName(), ingredient.getType().toString());
private Ingredient mapRowToIngredient(ResultSet row, int rowNum) throws SQLException { return new Ingredient( row.getString("id"), row.getString("name"), Ingredient.Type.valueOf(row.getString("type"))); }
jdbcTemplate.queryForObject( "select id, name, type from Ingredient where id=?", new RowMapper<Ingredient>() { public Ingredient mapRow(ResultSet rs, int rowNum) throws SQLException { return new Ingredient( rs.getString("id"), rs.getString("name"), Ingredient.Type.valueOf(rs.getString("type"))); }; }, id);
|
2.4 数据库表创建与数据初始化
在resource目录下放置,名称固定
2.5 save(TacoOrder order)的实现
JdbcOrderRepository
获取返回的ID,GeneratedKeyHolder
3. 使用 Spring Data JDBC
3.1 Spring Data项目
- Spring Data JDBC
- Spring Data JPA
- Spring Data MongoDB
- Spring Data Neo4j
- Spring Data Redis
- Spring Data Cassandra
3.2 引入依赖
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency>
|
用spring boot编译出支持不同版本的jdk
如果当前安装的jdk是17,则编译出的版本支持:1.8、11、17
1 2 3
| <properties> <java.version>11</java.version> </properties>
|
3.3 定义持久化接口
1 2
| public interface IngredientRepository extends CrudRepository<Ingredient, String> {}
|
3.4 为领域类添加持久化的注解
@Table
@Id
@Column
3.5 提高程序健壮性
JVM 断言
开启debug模式
使用spring boot的Assert类
3.6 程序预加载
org.springframework.boot.CommandLineRunner
1 2 3 4 5 6 7 8 9 10
| @Bean public CommandLineRunner dataLoader(IngredientRepository repo) { return args -> { repo.deleteAll(); repo.save(new Ingredient("FLTO", "Flour Tortilla", Type.WRAP)); repo.save(new Ingredient("COTO", "Corn Tortilla", Type.WRAP)); repo.save(new Ingredient("GRBF", "Ground Beef", Type.PROTEIN)); ... }; }
|
org.springframework.boot.ApplicationRunner
4. 使用 Spring Data JPA
JPA:Java Persistence API
JPA的宗旨是为POJO提供持久化标准规范
依赖:
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
|
4.1 Jpa、Hibernate、Spring Data Jpa三者之间的关系
4.2 @Entity
4.3 自动生成的数据库表
4.4 自定义的查询方法
定义查询方法,无需实现
- 领域特定语言(domain-specific language,DSL),spring data的命名约定
- 查询动词 + 主题 + 断言
- 查询动词:get、read、find、count
- 例子:
List findByDeliveryZip(String deliveryZip);
声明自定义查询