一、引言
大部分系統(tǒng)都離不開數(shù)據(jù)訪問,數(shù)據(jù)庫包括SQL和NOSQL,SQL是指關(guān)系型數(shù)據(jù)庫,常見的有SQL Server,Oracle,MySQL(開源),NOSQL是泛指非關(guān)系型數(shù)據(jù)庫,常見的有MongoDB,Redis。
用spring開發(fā)時我們常用的ORM框架有JDBC、Mybatis,Hibernate,現(xiàn)在最常用的應(yīng)該是Mybatis。
在Springboot中對于數(shù)據(jù)訪問層,無論是SQL還是NOSQL,都默認(rèn)采用整合Spring Data的方式進(jìn)行統(tǒng)一處理,Springboot會幫我們添加大量自動配置,屏蔽了很多設(shè)置。并引入各種xxxTemplate,xxxRepository來簡化我們對數(shù)據(jù)訪問層的操作。對我們來說只需要進(jìn)行簡單的設(shè)置即可。這篇就來學(xué)習(xí)springboot整合JDBC,mybatis、JPA。
我們需要用什么數(shù)據(jù)訪問,就引入相關(guān)的start進(jìn)行開發(fā)。

二、JDBC
jdbc是我們最先學(xué)習(xí)的一個數(shù)據(jù)庫框架,SpringBoot也進(jìn)行了相應(yīng)整合.
2.1、 引入依賴
<!--JDBC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--mysql 驅(qū)動-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2.2、數(shù)據(jù)源配置
我們可以做個測試:
@Autowired
private DataSource dataSource;
@Test
public void test() throws SQLException {
System.out.println(dataSource.getClass());
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
輸出為:com.zaxxer.hikari.HikariDataSource
說明默認(rèn)數(shù)據(jù)源是com.zaxxer.hikari.HikariDataSource,而在springboot 2.0之前為org.apache.tomcat.jdbc.pool.DataSource。我們也可以通過改變spring.datasource.type 屬性來更改我們想自定義的數(shù)據(jù)源。數(shù)據(jù)源的相關(guān)配置都在DataSourceProperties,我們可以參考這個類進(jìn)行配置。
2.3、DataSourceInitializer
DataSourceInitializer這里面有兩個方法runSchemaScripts()可以運行建表語句,runDataScripts()可以運行插入數(shù)據(jù)的sql語句。
默認(rèn)使用schema-.sql創(chuàng)建建表語句,用data-.sql插入數(shù)據(jù)語句,當(dāng)然我們也可以自己配置:
spring:
datasource:
schema:
- classpath:department.sql
2.4、操作數(shù)據(jù)庫
由于spingboot已經(jīng)幫我們自動配置了,那我們可以直接使用JdbcTemplate進(jìn)行數(shù)據(jù)庫操作:
@Autowired
JdbcTemplate jdbcTemplate;
@Test
public void jdbcTest(){
List<Map<String, Object>> mapList = jdbcTemplate.queryForList("select * from user ");
System.out.println(mapList.get(0));
}
結(jié)果:{id=1, username=王五, birthday=null, sex=2, address=null}
三、整合Druid數(shù)據(jù)源
上面講到我們有默認(rèn)的數(shù)據(jù)源,但一般情況我們還是會使用阿里提供的Druid數(shù)據(jù)源,因為Druid提供的功能更多,并且能夠監(jiān)控統(tǒng)計,這個時候我們需要先引入pom依賴,然后將spring.datasource.type 修改:
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
Druid的常用配置如下:
type: com.alibaba.druid.pool.DruidDataSource
# 數(shù)據(jù)源其他配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置監(jiān)控統(tǒng)計攔截的filters,去掉后監(jiān)控界面sql無法統(tǒng)計,'wall'用于防火墻
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;
druid.stat.slowSqlMillis=500
配置之后不會立刻生效,我們還需要編寫配置類:
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druid(){
return new DruidDataSource();
}
}
再次運行上面查詢數(shù)據(jù)源的方法,可以得到如下結(jié)果:

注:必須引入日志依賴,否則會報錯
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
我們在加上Druid的監(jiān)控配置:
//配置Druid的監(jiān)控
//1、配置一個管理后臺的Servlet
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
Map<String,String> initParams = new HashMap<>();
initParams.put("loginUsername","admin");
initParams.put("loginPassword","123456");
initParams.put("allow","");
//默認(rèn)就是允許所有訪問
initParams.put("deny","192.168.15.21");
bean.setInitParameters(initParams);
return bean;
}
//2、配置一個web監(jiān)控的filter
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
Map<String,String> initParams = new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");
bean.setInitParameters(initParams);
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
這樣我們可以直接通過后臺監(jiān)控數(shù)據(jù)源訪問情況。
四、Mybatis
第一步也是引入依賴:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
也導(dǎo)入Druid數(shù)據(jù)源,并加入之前學(xué)習(xí)Mybatis時用到的實體,而后就可以進(jìn)行測試,Mybatis的使用也有兩種方法,注解版和配置文件版,注解版用的很少,一般都是配置文件。
4.1、注解版
@Mapper
public interface DepartmentMapper {
@Select("select * from department where id=#{id}")
Department getDeptById(Integer id);
@Delete("delete from department where id=#{id}")
int deleteDeptById(Integer id);
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into department(departmentName) values(#{departmentName})")
int insertDept(Department department);
@Update("update department set departmentName=#{departmentName} where id=#{id}")
int updateDept(Department department);
}
測試:
@Autowired
UserMapper userMapper;
@Autowired
DepartmentMapper departmentMapper;
@Test
public void mybatisTest(){
Department deptById = departmentMapper.getDeptById(1);
System.out.println(deptById);
}
結(jié)果:Department(id=1, departmentName=AA)
4.2、配置文件版
使用配置文件版方式也很簡單,也是先新增一個接口:
@Mapper
public interface UserMapper {
User queryUserById(Integer id);
}
然后新增一個全局配置文件:SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
</configuration>
里面暫時什么配置都不需要,然后再引入相應(yīng)的XXXMapper.xml文件,最后在配置文件中加上掃描文件配置即可
mybatis:
config-location: classpath:mybatis/SqlMapConfig.xml
mapper-locations: classpath:mybatis/mapper/*.xml

UserMapper.xml內(nèi)容:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yuanqinnan.mapper.UserMapper">
<select id="queryUserById" parameterType="int" resultType="com.yuanqinnan.model.User">
SELECT * FROM `user`where id=#{id}
</select>
</mapper>
測試:
@Test
public void mybatisTest(){
Department deptById = departmentMapper.getDeptById(1);
System.out.println(deptById);
User userById = userMapper.queryUserById(1);
System.out.println(userById);
}
Mybatis的配置就是這么簡單,基本不需要額外配置。
五、JPA
JDBC和Mybatis我們之前都學(xué)習(xí)過,SpringBoot只不過是幫我們整合配置,而JPA我們之前沒有接觸過,所以還是要先解釋下,了解JPA之前我們先了解Spring Data:
Spring Data 項目的目的是為了簡化構(gòu)建基于Spring 框架應(yīng)用的數(shù)據(jù)訪問技術(shù),包括非關(guān)系數(shù)據(jù)庫、Map-Reduce 框架、云數(shù)據(jù)服務(wù)等等;另外也包含對關(guān)系數(shù)據(jù)庫的訪問支持。

Spring Data 主要特點是:
SpringData為我們提供使用統(tǒng)一的API來對數(shù)據(jù)訪問層進(jìn)行操作;這主要是Spring Data Commons項目來實現(xiàn)的。Spring Data Commons讓我們在使用關(guān)系型或者非關(guān)系型數(shù)據(jù)訪問技術(shù)時都基于Spring提供的統(tǒng)一標(biāo)準(zhǔn),標(biāo)準(zhǔn)包含了CRUD(創(chuàng)建、獲取、更新、刪除)、查詢、排序和分頁的相關(guān)操作。
SpringData幫我們封裝了數(shù)據(jù)庫操作,我們只需要進(jìn)程接口,就可以進(jìn)行操作,SpringData有如下統(tǒng)一的接口
Repository<T, ID extends Serializable>:統(tǒng)一接口 RevisionRepository<T, ID extends Serializable, N extends Number & Comparable<N>>:基于樂觀鎖機制 CrudRepository<T, ID extends Serializable>:基本CRUD操作 PagingAndSortingRepository<T, ID extends Serializable>:基本CRUD及分頁
我們要使用JPA,就是繼承JpaRepository,我們只要按照它的命名規(guī)范去對命名接口,便可以實現(xiàn)數(shù)據(jù)庫操作功能,這樣說有些抽象,還是用一個例子來說明:
第一步:引入依賴
<!-- springdata jpa依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
第二步:編寫表對應(yīng)實體:
//使用JPA注解配置映射關(guān)系
@Entity //告訴JPA這是一個實體類(和數(shù)據(jù)表映射的類)
@Table(name = "order") //@Table來指定和哪個數(shù)據(jù)表對應(yīng);order;
@Data
public class Order {
@Id //這是一個主鍵
@GeneratedValue(strategy = GenerationType.IDENTITY)//自增主鍵
private Integer id;
@Column(name = "user_Id")
private Integer userId;
//這是和數(shù)據(jù)表對應(yīng)的一個列
@Column(name="number",length = 32)
private String number;
// 訂單創(chuàng)建時間,省略默認(rèn)列名就是屬性名
private Date createtime;
// 備注
private String note;
}
第三步:編寫倉庫接口:
@Repository
public interface OrderRepository extends JpaRepository<Order, Integer> {
}
這個時候OrderRepository 已經(jīng)有了很多實現(xiàn)好的方法,我們只要跟著調(diào)用即可
測試:
@Autowired
OrderRepository orderRepository;
@Test
public void jpaTest(){
List<Order> all = orderRepository.findAll();
System.out.println(all);
}
一個簡單的JPA實現(xiàn)完成,當(dāng)然JPA的內(nèi)容很多,這里只是一個非常簡單的例子,要進(jìn)一步的學(xué)習(xí)的話還是要去看官方文檔。