(8)Spring Boot 与数据访问
简介
对于数据访问层,无论是 SQL
还是 NOSQL
,Spring Boot
默认都采用整合 Spring Data
的方式进行统一处理 ,添加大量自动配置,屏蔽了很多设置;
引入各种 xxxTemplate,xxxRepository
来简化我们对数据访问层的操作,对我们来说,只需要进行简单的设置即可。
整合基本的JDBC与数据源
-
引入启动器
Spring Boot
有许多的场景启动器,这里就提供了spring-boot-starter-jdbc
;<!--引入 JDBC--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!--引入 mysql 驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
-
配置
application.yml
然后在配置文件里面,告诉
Spring Boot
数据库地址、用户名、密码# 配置数据库 spring: datasource: username: root password: Myis03571 url: jdbc:mysql:///cms?charset=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true driver-class-name: com.mysql.cj.jdbc.Driver
测试下数据源:
@Autowired private DataSource dataSource; @Test public void contextLoads() throws SQLException { Connection connection = dataSource.getConnection(); System.out.println(" ---- "+dataSource.getClass()); System.out.println(" ---- "+connection); connection.close(); }
打印结果:
---- class com.zaxxer.hikari.HikariDataSource ---- HikariProxyConnection@668754554 wrapping com.mysql.cj.jdbc.ConnectionImpl@570ba13
Spring Boot
2.0
版本以后,默认选择的数据源是HikariDataSource
,也可以在配置文件里面制定自定义的数据源类型 :spring.datasource.type
,指定数据源类型; -
初始化数据库
可以将
sql
语句放在类路径下面,其中默认的命名规则:建表语句文件起名叫schema.sql
,插入语句文件起名叫data.sql
;也可以设置后缀,比如你想在项目启动的时候,执行
schema-mysql.sql
,则需要在配置文件里面进行配置:spring.datasource.platform = mysql
,指定下;或者也可以完全自定义这些规则,在配置文件里面配置,指定位置及文件名称 :
spring: datasource: schema: - classpath:xxx.sql
需要注意的事:每次应用重新启动,都会执行一次这些
sql
语句,也就是表会被重建,这样里面数据会丢失; -
自动配置了
JdbcTemplate
我们可以直接使用注入,获取到它,然后操控数据库;
可以向下面这样使用:
@Autowired private JdbcTemplate jdbcTemplate ; @ResponseBody @GetMapping("/users") public List<Map<String, Object>> getUser(){ List<Map<String, Object>> mapList = jdbcTemplate.queryForList("select * from DEPARTMENT"); return mapList; }
-
坑点
如果这时候你启动项目,你会发现,你的
sql
语句死活都得不到执行,数据库没有任何表生成,控制台也看不到任何sql
的日志,调试了半天;博主也只是个搬运工啊,看的视频,然后自己写的教程,视频老师使用
Spring Boot
的版本是2.0 ↓
,最后一路查到官网(2.0 ↑
),发现有下面一段话:大概意思就是说:
Spring Boot
能够自动的执行schema
文件,根据配置的数据源,这种自动的行为,可以通过spring.datasource.initialization-mode
控制,然后重点的一句话:比如你可以使用spring.datasource.initialization-mode=always
控制Spring Boot
永远的执行上述操作,而不管其具体类型;这句话的潜台词,可能是想告诉我,
Spring Boot
在某些情况下,会不执行schema
文件,好像我们遇到了这种情况,但是啥情况它也没说,或者说了我没看见,甭管,直接配置下属性spring.datasource.initialization-mode=always
再说:启动,然后控制台,我还是没找到对应的日志,真的迷,我都打开了终极日志输出了:
logging.level.* = trace debug=true
好在,数据库里面表已经创建出来了;
总结:记得配上
spring.datasource.initialization-mode=always
,如果你使用的是2.0 ↑
;
整合 druid 数据源
虽然 Spring Boot
默认使用 HikariDataSource
,可能这也是它推荐 HikariDataSource
的一种手段,但是我们由于一些原因,不接受它的推荐;
HikariDataSource
性能是要优于 druid
的,但是 druid
有一整套的方案,可以监控许多东西,还有后台管理界面;
-
引入
Druid
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.8</version> </dependency>
我靠,
IDEA
莫名其妙,引入以后,pom
文件也没爆红,然后jar
包也下载到本地,但是IDEA
依赖里面找不到,重启下才找到。 -
修改依赖的数据源
# 配置数据库 spring: datasource: username: root password: Myis03571 url: jdbc:mysql:///any?charset=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true driver-class-name: com.mysql.cj.jdbc.Driver schema: - classpath:ssasa.sql # 修改数据源,改为 马云 家 的 type: com.alibaba.druid.pool.DruidDataSource
启动之前的测试,这次打印出的数据源是:
---- class com.alibaba.druid.pool.DruidDataSource
-
配置数据源
Druid 配置讲解 ,这篇写的不错,可以看下,主要看他,那些配置项的意思;
# 配置数据库 spring: datasource: username: root password: Myis03571 url: jdbc:mysql:///any?charset=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true driver-class-name: com.mysql.cj.jdbc.Driver schema: # - 可以写多个,是个列表 # - classpath:ssasa.sql type: com.alibaba.druid.pool.DruidDataSource # 配置下数据源 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 # 配置监控统计拦截的 filters,去掉以后监控界面的 sql 无法统计,'wall' 用于防火墙 filters: stat,wall,log4j maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
然后,在配置里面,加载下
spring.datasource
下面的属性,进行属性的绑定:@ConfigurationProperties(prefix = "spring.datasource") @Bean public DataSource dataSource(){ return new DruidDataSource(); }
然后运行,哐!报错:
Caused by: java.lang.NoClassDefFoundError: org/apache/log4j/Priority at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:264) at com.alibaba.druid.util.Utils.loadClass(Utils.java:203) at com.alibaba.druid.filter.FilterManager.loadFilter(FilterManager.java:104) at com.alibaba.druid.pool.DruidAbstractDataSource.addFilters(DruidAbstractDataSource.java:1286) at com.alibaba.druid.pool.DruidAbstractDataSource.setFilters(DruidAbstractDataSource.java:1275) ... 107 more Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Priority at java.net.URLClassLoader.findClass(URLClassLoader.java:382) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 113 more
一通搜索以后,找到原因所在: 由于
Spring Boot 2.xxx
版本,底层将日志框架的组件换了个小零件,log4j-over-slf4j
被换成了log4j-to-slf4j
,但是logback + sl4j
这套组合又需要log4j-over-slf4j
,不然就报错,因此添加下log4j-over-slf4j
,它是个中间层,承上启下,上承log4j
,然后做个转换,换成logback
;(切忌,不要直接添加 log4j 包,那样就打破了整个系统使用同一套日志的机制):
<dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>1.7.24</version> </dependency>
打断点,再次运行,看下数据源:
属性已经注入到其中; -
配置监控
/** * 配置 Druid 的监控 * 1、先配置一个管理后台的 servlet * 2、配置一个监控后台的 filter * * 备注,方法名字,不可随意写,spring Boot 是根据这些去覆盖某些bean的 * @return */ @Bean public ServletRegistrationBean statViewServlet() { // 后面的参数,设置进入管理页面的url,可以随便写,但是最好写成 /druid/* // 因为,当没有登陆以后,访问其他监控页面的时候,会自动的跳转到 ,/druid/login.html // 如果你这里配置成其他的,则跳转发生错误了 ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); // 配置 StatViewServlet 的属性 Map<String, String> initParameters = new HashMap<>(); // 配置后台登陆的用户名和密码 initParameters.put("loginUsername", "admin"); initParameters.put("loginPassword", "123456"); // 配置允许谁登陆,默认允许任何人使用配置的用户名和密码登陆,配置成localhost,就仅仅本机能登陆了 initParameters.put("allow", ""); // 配置拒绝谁访问 initParameters.put("deny", "192.168.111.1"); bean.setInitParameters(initParameters); return bean; } @Bean public FilterRegistrationBean webStatFilter() { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new WebStatFilter()); // 同样可以配置初始化参数 Map<String, String> initParas = new HashMap<>(); // 配置排除项,排除哪些资源,排除静态资源 initParas.put("exclusions","*.js,*.css,/druid/*"); bean.setInitParameters(initParas); // 配置拦截的 url bean.setUrlPatterns(Arrays.asList("/*")); return bean ; }
然后在浏览器里面,输入你配置的进入监控页面的路径:
输入配置的用户名和密码,来到管理页面:感觉可以拿去充当毕业设计了,后台管理系统,哈哈哈。。阿里给力啊;页面广告被 ABP 插件屏蔽了,不然每个页面都是阿里云的广告;
整合 mybatis
引入 mybatis
依赖:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
可以看到是由 mybatis
打头的,它是由 mybatis
官方开发的,来支持 Spring
的,也就是其实 Spring
官方根本没看上 Mybatis
,其实也就是国内在大规模使用 mybatis
,国外反而使用 hibernate
为主流;其实 hibernate
也没有那么不堪,你逃不过的,如果想要玩 JPA
,hibernate
就是绕不过去的一关 ;
-
使用
mybatis
基于注解-
创建一个
mapper
接口,然后在接口方法上使用注解,直接写sql
:@Mapper public interface DepartmentMapper { @Options(useGeneratedKeys = true,keyProperty = "id") @Insert("insert into DEPARTMENT(name) values(#{name})") public int insertDepartment(Department department); @Select("select * from DEPARTMENT where id = #{id}") public Department getDeptById(Integer id); @Update("update DEPARTMENT set name = #{name} where id = #{id}") public int updateDeptById(Department department); @Delete("delete from DEPARTMENT where id = #{id}") public int deleteDeptById(Integer id); }
-
然后,控制层代码,
restful
风格:@RestController public class DepartmentController { @Autowired private DepartmentMapper departmentMapper; @GetMapping("/dept/{id}") public Department getDeptById(@PathVariable("id") Integer id) { return departmentMapper.getDeptById(id); } @GetMapping("/dept") public Department insertDept(Department department) { departmentMapper.insertDepartment(department); return department; } }
-
在配置类里面,进行自定义
mybatis
配置,比如开启驼峰命名法:/** * 自定义mybatis的配置 * * @return */ @Bean public ConfigurationCustomizer configurationCustomizer() { return new ConfigurationCustomizer() { @Override public void customize(org.apache.ibatis.session.Configuration configuration) { // 开启驼峰命名法 configuration.setMapUnderscoreToCamelCase(true); } }; }
也可以使用
@MapperScan(value = "cn.hyc.demo.mapper")
注解批量扫描mapper
接口 ;
-
-
使用配置文件版本
跟以前学的时候,没啥差别;
这里,仅仅记录下不一样的地方;
-
在类路径下面创建一个
mybatis
的全局配置文件,内容如下(暂时没做任何配置):<?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>
-
在
spring Boot
配置文件配置下mybatis
的相关配置,让mybatis
知道mapper
文件在哪# 配置 mybatis 的相关配置 mybatis: config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xml
-