相关代码及笔记于 https://github.com/AganRun/SpringInAction
第三章 使用数据
JDBC
初始化/预置 SQL
如果在应用的根类路径下存在明为schema.sql的文件,那么在应用启动的时候将会基于数据库执行这个文件中的SQL
放在src/main/resources下即可。
可能还希望预加载一些数据,可以把SQL命名为data.sql同样放到此目录下
注:SpringBoot2.0之后,需要加入
spring.datasource.initialization-mode=always
JDBC save获得ID
- 可以使用带有preparedStatementCreator和KeyHolder的update方法
public int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder);
使用步骤:
- 先创建一个PreparedStatementCreatorFactory
- SQL 传递给它,包含参数的类型
- 调用工厂的newPreparedStatementCreator()
- 传入对象以及KeyHolder
PreparedStatementCreator psc = new PreparedStatementCreatorFactory(
"insert into taco (name, createAt) values (?, ?)", Types.CHAR, Types.DATE
).newPreparedStatementCreator(
Arrays.asList(taco.getName(), new Timestamp(taco.getCreateAt().getTime()))
);
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(psc, keyHolder);
- 使用SimpleJdbcInsert(相比上一种,极大得简化的代码逻辑)
它有两个很重要的插入方法,execute()和executeAndReturnKey()
参数就是一个Map,key为列名,value为值。可以使用Jackson的ObjectMapper的convertValue()方法直接构建出一个Map
// 初始化
this.orderTacoInserter = new SimpleJdbcInsert(jdbcTemplate)
.withTableName("Taco_Order_Tacos");
//使用
@SuppressWarnings("unchecked")
Map values = objectMapper.convertValue(order, Map.class);
values.put("placeAt", order.getPlaceAt()); //因为时间会默认转为Long
long orderId = orderInserter.executeAndReturnKey(values).longValue();
JPA
JPA需要实体有一个无参的构造器
@PrePersist
createdAt()添加了PrePersist注解,作为了一个回调方法
在持久化之前,会使用这个方法将createdAt方法设置为当前的日期和时间
@Data
@NoArgsConstructor
@Entity
public class Taco {
private Date createdAt;
...
@PrePersist
void createAt() {
this.createdAt = new Date();
}
}
JPA方法命名查询
JPA在进行查询方法命名时,会将get、read和find视为同义词,都是用来获取一个或多个实体的
SpringData会忽略主体中大部分的单词,你尽可以将方法命名为readPuppiesBy...
SpringBoot启动任务
可以注入CommandLineRunner类及其实现类的Bean,Spring启动时会扫描到这些类,并执行其中的run方法
最简单的Demo,在启动类中加个注入
@SpringBootApplication
public class TacoCloudApplication {
public static void main(String[] args) {
SpringApplication.run(TacoCloudApplication.class, args);
}
@Bean
public CommandLineRunner dataLoader(IngredientRepository repo) {
return new CommandLineRunner() {
@Override
public void run(String... args) throws Exception {
repo.save(new Ingredient("FLTO", "Flour Tortilla", Type.WRAP));
}
};
}
}
如果有多个启动任务,可以创建多个CommandLineRunner的子类
执行顺序由@Order指定,优先级是按value值从小到大顺序
第三章小结
- JdbcTemplate可以简化JDBC的使用
- 当需要知道新生成的ID的值时,可以使用PreparedStatementCreator和KeyHolder
- 简化数据插入===>SimpleJdbcInsert
- JPA极大简化持久化操作,只需编写Repository接口