这篇文章用来系统的介绍SpringBoot如何与数据库进行交互。之前写过一篇文章 springBoot整合jdbc进行数据访问,当时由于做项目,并没有深入了解具体原理,最近刚好时间充足,来探讨一下SpringBoot进行数据访问的几种方式。主要用一个小demo展示用法。
1. 整合原生的jdbc
创建一个项目:
如下所示: 我们选中 jdbc 和mysql ,下面讲解jpa和mybatis的时候,再分别选中不同的。
项目创建完成之后,在application.yml中配置数据源,注意:不管是跟什么类型的数据库进行交互,都需要配置下数据源或者采用注解的方式。
spring:
datasource: # 配置数据源
username: root # 注意: 冒号后面需要跟一个空格
password: 123456
url: jdbc:mysql://localhost:3306/jdbc
driver-class-name: com.mysql.jdbc.Driver
至此已经配置好了,我们可以通过自动创建的测试类,进行测试,如下所示:
@Autowired
DataSource dataSource ;
@Test
public void contextLoads() throws Exception{
System.out.println(dataSource.getClass());
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
我这里将打印输出的结果放在这里进行分析:
class com.zaxxer.hikari.HikariDataSource // dataSource.getClass()
HikariProxyConnection@694329275 wrapping com.mysql.jdbc.JDBC4Connection@681adc8f // connection
请看,默认使用的是 com.zaxxer.hikari.HikariDataSource 作为数据源,我当前springboot的版本为 2.0.5.RELEASE,
低版本如Spring Boot 1.5 默认使用 org.apache.tomcat.jdbc.pool.DataSource 作为数据源,HikariDataSource 号称 Java WEB 当前速度最快的数据源,相比于传统的 C3P0 、DBCP、Tomcat jdbc 等连接池更加优秀 ,这里并不对此继续延伸。
有关数据源的配置都在DataSourceProperties里面。
让我们了解一下 自动配置原理:
org.springframework.boot.autoconfigure.jdbc 包下 // spring-boot-autoconfigure-2.0.5.RELEASE.jar
1). DataSourceConfiguration 数据源的配置 ,打开该类,可以看到作用给容器中添加组件,根据判断添加各种的dataSource,
eg:
@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
static class Hikari {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariDataSource dataSource(DataSourceProperties properties) {
HikariDataSource dataSource = createDataSource(properties,
HikariDataSource.class);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
}
表示,如果导入了 HikariDataSource ,并且 spring.datasource.type为com.zaxxer.hikari.HikariDataSource数据源,那么就为程序注入 HikariDataSource的数据源。否则就根据判断导入其他的数据源 。 默认使用 HikariDataSource,可以使用 spring.datasource.type指定自定义的数据源 。
2). SpringBoot 默认可以支持
- org.apache.tomcat.jdbc.pool.DataSource
- HikariDataSource
- org.apache.commons.dbcp2.BasicDataSource
4. 自定义数据源
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {
@Bean
public DataSource dataSource(DataSourceProperties properties) {
// 使用 DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性
return properties.initializeDataSourceBuilder().build();
}
}
5. jdbcTemplate: 自动配置,已经在容器中自动注入了JdbcTemplate ,我们可以使用该bean操作数据库
@Autowired
private JdbcTemplate jdbcTemplate ;
@RequestMapping("query")
@ResponseBody
public Map<String,Object> getResult(){
List<Map<String, Object>> list = jdbcTemplate.queryForList("select *from department;");
return list.get(0);
}
浏览器输入: localhost:8080/query
2. 整合druid数据源
1) 引入 druid
<!-- 引入 druid数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
2) 配置druid ,将spring.datasource.type指定为 com.alibaba.druid.pool.DruidDataSource
测试结果打印如下:
class com.alibaba.druid.pool.DruidDataSource
com.mysql.jdbc.JDBC4Connection@39e67516
注意:如果要配置druid连接池的其他属性,可以将application.yml中追加配置信息,
然后自定义一个配置类,绑定配置信息
在debug下启动测试类 ,就会发现定义的连接池属性全部被注入了。
3. 整合mybatis
1) 添加maven依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
其自动引入的其他依赖如下:
在MybatisAutoConfiguration.java(mybatis自动配置类)中,我们可以看到自动配置了SqlSessionFactory,于是我们可以很方便的使用mybatis,而不需要另外配置。
使用mybatis ,有两种方式:注解版和配置版。
使用注解版如下: 定义一个mapper接口,全注解的方式。
// 指定这是一个操作数据库的mapper
@Mapper
public interface DepartmentMapper {
@Select("select * from department where id=#{id}")
public Department getDeptById(Integer id);
@Delete("delete from department where id=#{id}")
public int deleteById(Integer id);
@Options(useGeneratedKeys = true,keyProperty = "id") // @Options注解会自动为表对应的对象的主键字段设置上自增的值,直接从这个对象中获取即可。
@Insert("insert into department(departmentName) values(#{departmentName})")
public int inseretDept(Department department);
@Update("update department set departmentName=#{departmentName} where id=#{id}")
public int updateDept(Department department);
}
然后再controller中直接使用 该接口,就能操作数据库。
@RestController
public class DeptController {
@Autowired
private DepartmentMapper departmentMapper;
@GetMapping("/dept/{id}")
public Department getDepartment(@PathVariable("id") Integer id) {
return departmentMapper.getDeptById(id);
}
}
查询结果如下:
注意: 当我们将数据库的某个字段,如departmentName改为department_name(驼峰命名法)之后,再去查询某条数据,就发现departmentName值为空,如下图: 也即,mybatis自动配置的规则里面并没有自动开启驼峰命名法的映射规则。
那怎么来修改mybatis的规则呢? 事实上,在mybatis自动配置类MybatisAutoConfiguration.java中,关于SqlSessionFactory的配置中,有这样几行代码 : ConfigurationCustomizer定制,
if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
customizer.customize(configuration);
}
}
所以,如果要改变 mybatis自动配置的规则, 我们可以自定义一个 ConfigurationCustomizer配置类,将其注入到bean中。
@Configuration
public class MyBatisConfig { // 自定义MyBatis的配置规则
@Bean
public ConfigurationCustomizer configurationCustomizer(){
return new ConfigurationCustomizer() {
@Override
public void customize(org.apache.ibatis.session.Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true); // 开启驼峰命名法、
}
};
}
}
重启程序,并查询:就会发现,值已经被查出来了
注意:当mapper接口过多时,可以在主启动类上添加 @MapperScan用来替代每个mapper接口上的@Mapper
4. 整合JPA
1) 编写一个实体类(bean)和数据表进行映射,并且配置好映射关系。
import javax.persistence.*;
// 使用jpa注解配置映射关系
@Entity //告诉jpa这是一个实体类型(和数据表映射的类)
@Table(name = "tbl_user") //@Table来指定和哪个数据表对应,如果省略,默认表名就是user ,如果没有表, 也会自动创建。
public class User {
@Id //表明这是一个主键,
@GeneratedValue(strategy = GenerationType.IDENTITY) //自增主键
private Integer id;
@Column(name = "last_name",length = 50) //这是和数据表对应的一个列
private String lastName;
@Column //省略 默认列名就是属性名
private String email;
// ..... Getter和Setter
}
2)编写一个Dao接口来操作实体类对应的数据表(Repository)。JpaRepository已经具备基本的增删改查功能,同时,还具有分页和排序的功能 ,所以,直接定义一个接口去继承JpaRepository即可,在controller直接可以使用。
// 继承JpaRepository来完成对数据库的操作。
public interface UserRepository extends JpaRepository<User,Integer> {//第一个泛型指定实体类,第二个泛型指定主键的类型
}
3) 基本配置 ,与jpa相关的配置,都在JpaProperties下,如果需要配置什么,可以在application.yml中修改。
jpa:
hibernate:
# 更新或者创建数据表结构
ddl-auto: update
# 控制台显示sql
show-sql: true
4) 使用: 可以直接自动引入,并使用。
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
private UserRepository userRepository;
@GetMapping("get/{id}")
public User getUser(@PathVariable Integer id){
return userRepository.getOne(id);
}
@GetMapping("insert")
public User insertUser(User user){
User save = userRepository.save(user);
return save ;
}
}
浏览器访问如下: