一、SQL
- 导入数据库开发的相关场景 + 配置数据库依赖
- SpringBoot对数据访问层的整合,都是 spring-boot-data 开头
1、数据源的自动配置
(1)导入JDBC场景
<!--数据库相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
- 我们需要确保数据库版本和驱动版本一致,为什么官方导入JDBC场景不包含驱动呢
- 因为数据库有很多种,官方不知道我们要使用的是哪种数据库
- 数据库驱动的默认版本:<mysql.version>8.0.22</mysql.version>
- 我们如何将驱动指定为我们需要的版本呢?
- 方法一:在pom.xml中直接引入具体版本的依赖【maven的就近依赖原则】
- 方法二:通过在pom.xml的properties标签中指定驱动版本 【maven属性的就近优先原则】
<properties>
<java.version>1.8</java.version>
<mysql.version>5.1.49</mysql.version>
</properties>
(2)分析自动配置
- DataSourceAutoConfiguration: 数据源的自动配置
- 修改数据源相关的配置:spring.datasource
- 数据库连接池的配置,是自己容器中没有DataSource才自动配置的
- 底层配置好的连接池是:HikarDataSource
@Configuration(proxyBeanMethods = false)
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration
- DataSourceTransactionManagerAutoConfiguration:事务管理器的自动配置
- JdbcTemplateAutoConfiguration:JdbcTemplate的自动配置,可以来对数据库进行增删改查
- 可以修改这个配置项 @ConfigurationProperties(prefix = “spring.jdbc”) 来修改 JdbcTemplate
- @Bean@Primary JdbcTemplate, 容器中有这个组件 【我们通过@Autowire注解直接注入使用即可】
- JndiDataSourceAutoConfiguration: jndi 的自动配置
- XADataSourceAutoConfiguration: 分布式事务相关的
(3)修改配置项 【就是我们需要对我们操作的数据库进行配置】
- 我们的application.yml 一般是完成与数据相关的配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/smbms
username: root
password: 111111
driver-class-name: com.mysql.jdbc.Driver
(4)我们测试是否可以成功操作数据库
- 测试方法直接写在主程序测试类中,这个是我们通过模版快速创建的
package com.atguigu.admin;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
@SpringBootTest
@Slf4j
class Boot05WebAdminApplicationTests {
@Autowired
JdbcTemplate jdbcTemplate;
@Test
void contextLoads() {
//查询表中的数据
// jdbcTemplate.queryForObject("select * from smbms_user");
// jdbcTemplate.queryForList("select * from smbms_user");
Long aLong = jdbcTemplate.queryForObject("select count(*) from smbms_user", Long.class);
log.info("记录总数: {}", aLong);
}
}
2、使用Druid数据源
- 整合阿里提供的第三方数据源
- 方法一:自定义
- 方法二:找官方提供的场景(starter)
(1)自定义方式
创建数据源
- 引入德鲁伊连接池的依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.17</version>
</dependency>
- 下面这张图我想说明:如果我们在容器中没有自定义数据源,那么系统会给我们创建HikariDataSource数据源
- 之前我们在Spring自定义数据源时,需要通过bean标签配置,或者采用set方法设置
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxActive" value="20" />
<property name="initialSize" value="1" />
<property name="maxWait" value="60000" />
<property name="minIdle" value="1" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="poolPreparedStatements" value="true" />
<property name="maxOpenPreparedStatements" value="20" />
- 在SpringBoot中,我们只需要通过 @ConfigurationProperties 指向我们的配置文件,就可以实现属性自动绑定
@Configuration
public class MyDataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource")
public DataSource dataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
}
StatViewServlet
- StatViewServlet 的用途包括:
- 提供监控信息展示的html页面
- 提供监控信息的JSON API
<servlet>
<servlet-name>DruidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DruidStatView</servlet-name>
<url-pattern>/druid/*</url-pattern>
</servlet-mapping>
- 配置Druid的监控页功能
/**
* 配置druid的监控页功能
* @return
*/
@Bean
public ServletRegistrationBean statViewServlet() {
StatViewServlet statViewServlet = new StatViewServlet();
ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>(statViewServlet, "/druid/*");
// 监控页账号密码
registrationBean.addInitParameter("loginUsername", "admin");
registrationBean.addInitParameter("loginPassword"," 123456");
return registrationBean;
}
StatFilter
- 用于统计监控信息:如果SQL监控、URI监控
需要给数据源中配置如下属性;可以允许多个filter,多个用,分割;如:
<property name="filters" value="stat,slf4j" />
慢SQL记录配置:
<bean id="stat-filter" class="com.alibaba.druid.filter.stat.StatFilter">
<property name="slowSqlMillis" value="10000" />
<property name="logSlowSql" value="true" />
</bean>
使用 slowSqlMillis 定义慢SQL的时长
(2)使用官方 starter 方式
引入 德鲁伊数据源的starter
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
我们查看场景中的配置,分析一下SpringBoot为我们完成了哪些自动配置
- 先定位到自动配置类
@Configuration
@ConditionalOnClass({DruidDataSource.class})
@AutoConfigureBefore({DataSourceAutoConfiguration.class})
@EnableConfigurationProperties({DruidStatProperties.class, DataSourceProperties.class})
@Import({DruidSpringAopConfiguration.class, DruidStatViewServletConfiguration.class, DruidWebStatFilterConfiguration.class, DruidFilterConfiguration.class})
public class DruidDataSourceAutoConfigure {
- ConditionalOnClass 说明容器中有DruidDataSource的组件才会生效
- 这个配置文件在默认的数据源自动配置类之前生效,为的是让我们自定义的数据源代替默认的数据源
- EnableConfigurationProperties 的作用是与我们的配置文件关联上,实现属性的绑定
- DruidStatProperties.class 对应**@ConfigurationProperties(“spring.datasource.druid”)**
- DataSourceProperties.class 对应**@ConfigurationProperties(prefix = “spring.datasource”)**
- 又利用 @Import 注解导入四个配置 【把类加入Spring IOC容器】
- DruidSpringAopConfiguration.class
- 通过spring.datasource.druid.aop-patterns进行配置
- 作用是监控Spring的组件的
- DruidStatViewServletConfiguration.class
- 通过spring.datasource.druid.stat-view-servlet进行配置
- 作用是完成监控页的配置
- DruidWebStatFilterConfiguration.class
- 通过spring.datasource.druid.web-stat-filter进行配置
- 作用是web监控配置
- DruidFilterConfiguration.class
- Druid 自己的filter配置
private static final String FILTER_STAT_PREFIX = "spring.datasource.druid.filter.stat";
private static final String FILTER_CONFIG_PREFIX = "spring.datasource.druid.filter.config";
private static final String FILTER_ENCODING_PREFIX = "spring.datasource.druid.filter.encoding";
private static final String FILTER_SLF4J_PREFIX = "spring.datasource.druid.filter.slf4j";
private static final String FILTER_LOG4J_PREFIX = "spring.datasource.druid.filter.log4j";
private static final String FILTER_LOG4J2_PREFIX = "spring.datasource.druid.filter.log4j2";
private static final String FILTER_COMMONS_LOG_PREFIX = "spring.datasource.druid.filter.commons-log";
private static final String FILTER_WALL_PREFIX = "spring.datasource.druid.filter.wall";
private static final String FILTER_WALL_CONFIG_PREFIX = "spring.datasource.druid.filter.wall.config";
接下来我们要演示具体是如何进行配置以及使用的
- 下面这个文件是我在项目的 application.yml 中进行配置的
spring:
datasource:
url: jdbc:mysql://localhost:3306/smbms
username: root
password: 111111
driver-class-name: com.mysql.jdbc.Driver
druid:
filters: stat,wall # 指定开启哪些功能[此处分别为 sql监控、防火墙]
stat-view-servlet: # 监控页功能
enabled: true
login-password: admin # 监控登录密码
login-username: admin # 监控登录账号
reset-enable: false
web-stat-filter: # web监控和uri监控
enabled: true
exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # 不指定默认就是这个
url-pattern: /*
aop-patterns: com.atguigu.admin.* # 监控这个包下的所有组件
filter: # 对于上面拦截器/过滤器的详细配置
stat:
slow-sql-millis: 1000 # 指定超过1s的查询都是慢查询
log-slow-sql: true # 是否开启慢查询日志记录功能
enabled: true
wall:
enabled: true
config:
delete-allow: false # 禁止删表操作
jdbc:
template:
query-timeout: 3
- 如果我们想来到druid的监控页
- 在浏览器的地址栏输入:
localhost:8080/druid/login.html
- 然后输入我们配置好的德鲁伊连接池的账号和密码
- 给出Druid官方配置手册:
- 点击跳转Druid Spring Boot Starter中文手册
3、整合MyBatis操作
- JdbcTemplate 是Spring内置的简单版数据库操作工具,在平时工作的时候我们会使用第三方提供的数据库操作工具,例如:MyBatis
- 使用MyBatis之前,先引入对应的starter的依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
(1)配置模式
- SpringBoot 底层为我们做了什么?
- SqlSessionFactory 自动配置好了
- SqlSession 中自动配置了 SqlSessionTemplate 并组合了SqlSession
- 通过 @Import(AutoConfiguredMapperScannerRegistrar.class) 导入对应组件
- 我们编写的Mapper接口,通过**@Mapper**扫描进来
- 通过 @EnableConfigurationProperties注解实现与配置文件的绑定
@EnableConfigurationProperties(MybatisProperties.class) : MyBatis配置项绑定类。
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration{}
@ConfigurationProperties(prefix = "mybatis")
public class MybatisProperties
- 先看下一目录结构,了解都创建了哪些文件
- Account 代表封装数据库字段的POJO类
- 我们把请求的处理写在了 IndexController 控制器中
- mapper.AccountMapper 接口设置了操作数据库的方法,此处为 getAcct
- service.AccountService 类调用了接口对象,创建了一个业务方法调用接口方法实现功能
- 在resources目录下的mybatis目录专门存放于mybatis相关的
- mybatis-config.xml 是mybatis的核心配置文件,后期可以省略直接在springboot的yaml文件中进行配置
- AccountMapper.xml 来完成具体的映射
- 接下来描述一下整体通过配置MyBatis操作数据库的流程:
- 导入mybatis官方starter
- 编写mapper接口并使用@Mapper注解
- 编写sql映射文件并绑定到mapper接口上
- 在application.yaml 中指定Mapper核心配置文件位置、sql映射文件位置
- yaml中的配置 【对于采取配置文件和configuration配置只能选取一种】
# 配置mybatis的规则
mybatis:
# config-location: classpath:mybatis/mybatis-config.xml # 指定mybatis全局文件的位置
mapper-locations: classpath:mybatis/mapper/*.xml # 指定mybatis的sql映射文件位置
configuration:
map-underscore-to-camel-case: true # 通过配置文件的方式开启驼峰映射
接下来附上我们的各个文件
//AccountMapper 接口
package com.atguigu.admin.mapper;
import com.atguigu.admin.bean.Account;
import org.apache.ibatis.annotations.Mapper;
/**
* @author Bonbons
* @version 1.0
*/
@Mapper
public interface AccountMapper {
public Account getAcct(Long id);
}
//AccountService类
package com.atguigu.admin.service;
import com.atguigu.admin.bean.Account;
import com.atguigu.admin.mapper.AccountMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author Bonbons
* @version 1.0
*/
@Service
public class AccountService {
//注入操作数据库的对象
@Autowired
AccountMapper accountMapper;
public Account getAcctById(Long id){
return accountMapper.getAcct(id);
}
}
<!--AccountMapper.xml 映射文件-->
<?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.atguigu.admin.mapper.AccountMapper">
<!--根据id查询用户信息-->
<select id="getAcct" resultType="com.atguigu.admin.bean.Account">
select * from account_tbl where id = #{id}
</select>
</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>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
- 一些补充知识点:
- 当我们的@Bean注解用于方法上,参数类型如果在容器中有对应组件,那么就会从容器中取
(2)注解模式
- 不需要编写mybatis的核心配置文件与sql映射文件
- 整体流程
- 第一步,仍然需要导入 mybatis 的 starter
- 第二步,编写我们的POJO类,此处为 City
- 第三步,编写我们的mapper接口,此处和我们以往不同,直接通过注解来指明对应的SQL语句
- 第三步,编写我们的 CityServer(业务层),在业务里调用mapper层的方法
- 第四步,在我们的控制器(此处为 IndexController)中编写方法,处理我们的请求
- 接下来附上我们的文件代码
// City类
package com.atguigu.admin.bean;
import lombok.Data;
/**
* @author Bonbons
* @version 1.0
*/
@Data
public class City {
private Long id;
private String name;
private String state;
private String country;
}
// CityMapper接口
package com.atguigu.admin.mapper;
import com.atguigu.admin.bean.City;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
/**
* @author Bonbons
* @version 1.0
*/
@Mapper
public interface CityMapper {
//不去编写sql映射文件了,而是直接在我们接口方法的上方通过注解来指定
@Select("select * from city where id = #{id}")
public City getById(Long id);
}
// CityService类
package com.atguigu.admin.service;
import com.atguigu.admin.bean.City;
import com.atguigu.admin.mapper.CityMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author Bonbons
* @version 1.0
*/
@Service
public class CityService {
//注入我们的mapper
@Autowired
CityMapper cityMapper;
public City getById(Long id){
return cityMapper.getById(id);
}
}
//控制器方法
//纯注解的方式
@Autowired
CityService cityService;
@GetMapping("/city")
@ResponseBody
public City getCityById(@RequestParam("id") Long id){
return cityService.getById(id);
}
(3)混合模式
- 什么情况下会混合 配置文件 + 注解的形式呢?
- 就是当我们的SQL很复杂的时候
- 就是不使用注解代替sql映射文件【对于我们采取配置文件的部分】
- 可以参考下面的这几部分代码:
// CityMapper接口
package com.atguigu.admin.mapper;
import com.atguigu.admin.bean.City;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
/**
* @author Bonbons
* @version 1.0
*/
@Mapper
public interface CityMapper {
//不去编写sql映射文件了,而是直接在我们接口方法的上方通过注解来指定
@Select("select * from city where id = #{id}")
public City getById(Long id);
//这个不采用注解的方式,与配置文件结合使用完成插入功能
public void insert(City city);
}
// CityService类
package com.atguigu.admin.service;
import com.atguigu.admin.bean.City;
import com.atguigu.admin.mapper.CityMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author Bonbons
* @version 1.0
*/
@Service
public class CityService {
//注入我们的mapper
@Autowired
CityMapper cityMapper;
public City getById(Long id){
return cityMapper.getById(id);
}
public void saveCity(City city){
cityMapper.insert(city);
}
}
<!--CityMapper.xml-->
<?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.atguigu.admin.mapper.AccountMapper">
<!--插入City数据-->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into city(`name`, `state`, `country`) values(#{name}, #{state}, #{country})
</insert>
</mapper>
//IndexController控制器
//纯注解的方式 >> 查询
@Autowired
CityService cityService;
@GetMapping("/city")
@ResponseBody
public City getCityById(@RequestParam("id") Long id){
return cityService.getById(id);
}
//注解+配置文件 >> 添加
@ResponseBody
@PostMapping("/city")
public City saveCity(City city){
cityService.saveCity(city);
return city;
}
//普通Java对象类
package com.atguigu.admin.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Bonbons
* @version 1.0
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class City {
private Long id;
private String name;
private String state;
private String country;
}
我们也可以将第二种配置方式转为注解方式【内含配置项的注解用法】
@Insert("insert into city(`name`, `state`, `country`) values(#{name}, #{state}, #{country})")
@Options(useGeneratedKeys = true, keyProperty = "id")
public void insert(City city);
- 补充知识点:
- useGeneratedKeys、keyProperty 代表设置自增键
- 用@Options注解指定选项
- 主程序类使用@MapperScan(“com.atguigu.admin.mapper”) 注解扫描所有mapper,代替每个接口上使用@mapper注解
- 总结注解和配置方式使用Mybatis的最佳实战:
- 引入 mybatis-starter 的场景
- 在SpringBoot的核心配置文件 application.yaml 中,指定 mapper-location 的位置 【sql映射文件】
- 编写Mapper接口并标注@Mapper注解 【尽管上面可以通过包扫描代替标记@Mapper,但还是推荐使用@Mapper注解】
- 对于接口中的写法有两种方式
- 简单写法就是直接通过注解代替sql映射文件
- 复杂写法就是编写sql文件,然后与我们的mapper接口方法关联上 【大多用于比较复杂的SQL】
4、整合MyBatis-Plus 完成CRUD
(1)什么是 MyBatis-Plus
- 是MyBatis的增强工具,可以简化开发、提升效率
- IDEA中有相关的插件:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 mybatisx 搜索并安装
- 具体的开发指南可以参考我们的 MyBatisPlus 官网
(2)整合MyBatis-Plus
整体流程说明:
- 准备数据库表【我使用的是mysql的navicat】
- 创建表的脚本
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
- 创建几组对应数据的脚本
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
- 引入mybatisPlus的starter
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
- 编写Mapper接口
package com.atguigu.admin.mapper;
import com.atguigu.admin.bean.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author Bonbons
* @version 1.0
* 让我们的接口直接继承MyBatisPlus提供的BaseMapper
* 泛型为我们要操作的数据类型
*/
public interface UserMapper extends BaseMapper<User> {
}
- 编写我们数据库表对应的POJO类
- 此处为什么不直接删掉userName、password属性呢?
- 因为在登录验证的时候要使用
package com.atguigu.admin.bean;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Bonbons
* @version 1.0
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
/**
* 正常所有的属性都应该与数据库表中的字段对应上
* 但是上面的userName和 password 我们暂时用不到,所以就通过注解暂时让他俩不在表中
*/
@TableField(exist = false)
private String userName;
@TableField(exist = false)
private String password;
//MyBatisPlus整合用的User对象为下面四个字段
private Long id;
private String name;
private Integer age;
private String email;
}
- 编写测试方法【这个方法是写在我们的 主程序测试类中的】
@Autowired
UserMapper userMapper;
@Test
void testUserMapper(){
User user = userMapper.selectById(1L);
log.info("用户信息: {}", user);
}
- 其实还应该配置数据源,我们在之前已经配置了 Druid 数据源此处使用的就是【直接贴上我的 application.yml】
spring:
datasource:
url: jdbc:mysql://localhost:3306/smbms
username: root
password: 111111
driver-class-name: com.mysql.jdbc.Driver
druid:
filters: stat,wall # 指定开启哪些功能[此处分别为 sql监控、防火墙]
stat-view-servlet: # 监控页功能
enabled: true
login-password: admin # 监控登录密码
login-username: admin # 监控登录账号
reset-enable: false
web-stat-filter: # web监控和uri监控
enabled: true
exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'
url-pattern: /*
aop-patterns: com.atguigu.admin.* # 监控这个包下的所有组件
filter: # 对于上面拦截器/过滤器的详细配置
stat:
slow-sql-millis: 1000 # 指定超过1s的查询都是慢查询
log-slow-sql: true # 是否开启慢查询日志记录功能
enabled: true
wall:
enabled: true
config:
delete-allow: false # 禁止删表操作
jdbc:
template:
query-timeout: 3
# 配置mybatis的规则
mybatis:
# config-location: classpath:mybatis/mybatis-config.xml # 指定mybatis全局文件的位置
mapper-locations: classpath:mybatis/mapper/*.xml # 指定mybatis的sql映射文件位置
configuration:
map-underscore-to-camel-case: true # 通过配置文件的方式开启驼峰映射
接下来我们对 mybatis-plus 场景的自动配置进行分析
- 在starter中,自动配置是从 spring.factories 里面获取EnableAutoConfiguration 以启动要加载的类
- 项目一启动 MybatisPlusAutoConfiguration 的自动配置就会生效
- MybatisPlusProperties 配置项绑定【mybatis-plus:xxx 就是对mybatis-plus的定制】
- SqlSessionFactory 自动配置好,在底层使用的是容器中默认的数据源
- mapperLocations 自动配置好的。有默认值为 classpath*:/mapper/**/*.xml;【任意包的类路径下的所有mapper文件夹下任意路径下的所有xml都是sql映射文件】
- 容器中也自动配置好了 SqlSessionTemplate
- @Mapper 标注的接口也会被自动扫描;建议直接 @MapperScan(“com.atguigu.admin.mapper”) 批量扫描就行
补充的其他知识点:
- @Bean标记一个方法,如果参数是一个对象,这个参数就会从容器中自动确定这个组件
- Ctrl + F12 查看类中有哪些方法 【IDEA快捷键】
- 只需要我们的Mapper继承 BaseMapper 就可以拥有crud能力 【当然我们如果有特殊的需求,也可以使用sql映射文件自定义】
- 以下是BaseMapper中为我们提供的一些基本方法
(3)CRUD功能
- 零散知识点:
- 对于我们定义的Mapper接口,继承BaseMapper之后,它如何知道我们关联的是数据库中的那张表呢?
- 默认将泛型参数首字母小写为数据库中对应的表,比如此处为
BaseMapper<User>
默认对应数据库中的 user 表 - 当然,我们也可以指定POJO类对应的表名,在我们的POJO类上添加注解@TableName(“实际表名”)即可【此处为User】
- 遍历状态: stat.count 可以充当编号 直接用id也行
- UserService
/**
* 继承顶级 Service
*/
public interface UserService extends IService<User> {
}
- UserServiceImpl
package com.atguigu.admin.service.impl;
import com.atguigu.admin.bean.User;
import com.atguigu.admin.mapper.UserMapper;
import com.atguigu.admin.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* @author Bonbons
* @version 1.0
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
- Controller
@GetMapping("/dynamic_table")
public String dynamic_table(Model model) {
// 从数据库中查出user表中的用户进行展示
List<User> list = userService.list();
model.addAttribute("users", list);
return "table/dynamic_table";
}
- 修改前端页面
<tr>
<th>#</th>
<th>id</th>
<th>name</th>
<th>ages</th>
<th>email</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr class="gradeX" th:each="user,stat:${users}">
<td th:text="${stat.count}">Trident</td>
<td th:text="${user.id}">id</td>
<td th:text="${user.name}">Internet
Explorer 4.0
</td>
<td th:text="${user.age}"></td>
<td class="center hidden-phone">[[${user.email}]]</td>
<td class="center hidden-phone">X</td>
</tr>
- 效果演示
演示分页功能的使用:
- 编写一个分页插件的配置类
@Configuration
public class MyBatisConfig {
/**
* MybatisPlusInterceptor
* @return
*/
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// MyBatis-plus3.4版本以后的分页拦截器
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
paginationInnerInterceptor.setOverflow(true);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
paginationInnerInterceptor.setMaxLimit(500L);
mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);
return mybatisPlusInterceptor;
}
}
- 在Controller中增加分页功能
@GetMapping("/dynamic_table")
public String dynamic_table(@RequestParam(value = "pn", defaultValue = "1") Integer pn, Model model) {
// 从数据库中查出user表中的用户进行展示
List<User> list = userService.list();
//model.addAttribute("users", list);
// 分页查询数据
Page<User> userPage = new Page<>(pn, 2);
// 分页查询的结果
Page<User> page = userService.page(userPage, null);
model.addAttribute("page", page);
return "table/dynamic_table";
}
- 修改前端页面,演示分页效果
<div class="row-fluid">
<div class="span6">
<div class="dataTables_info" id="dynamic-table_info">
当前第 [[${page.current}]] 页
总计 [[${page.pages}]] 页
共 [[${page.total}]] 条记录
</div>
</div>
<div class="span6">
<div class="dataTables_paginate paging_bootstrap pagination">
<ul>
<li class="prev disabled"><a href="#">← 前一页</a></li>
<li th:class="${num == page.current?'active':''}"
th:each="num:${#numbers.sequence(1,page.pages)}">
<a th:href="@{/dynamic_table(pn=${num})}">[[${num}]]</a>
</li>
<li class="next disabled"><a href="#">下一页 → </a></li>
</ul>
</div>
</div>
</div>
实现删除功能
- 增加删除的按钮:
<td>
<a
th:href="@{/user/delete/{id}(id=${user.id},pn=${page.current})}"
class="btn btn-danger btn-sm"
type="button">
删除
</a>
</td>
- 设置控制器方法:
@GetMapping("/user/delete/{id}")
public String deleteUser(@PathVariable("id") Long id,
@RequestParam(value = "pn", defaultValue = "1") Integer pn,
RedirectAttributes ra) {
userService.removeById(id);
ra.addAttribute("pn", pn);
return "redirect:/dynamic_table";
}
二、NoSQL
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
1、Redis自动配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 分析一下Redis-start在底层为我们完成了哪些配置
- 自动配置类为 RedisAutoConfiguration,指明了RedisProperties属性类(属性绑定)
- 通过 spring.redis.xxx 完成对 redis 的配置 【在application.xml 中食用】
- LettuceConnectionConfiguration、JedisConnectionConfiguration连接工厂也是准备好的
- 为我们自动注入了两个操作Redis的模版:
-
RedisTemplate<Object, Object>
、StringRedisTemplate
【区别就是kv的类型不同,后者专门用于String】 - 底层只要我们通过@Autowire注入了 StringRedisTemplate或RedisTemplate就可以操作Redis
- 为了掩饰操作Redis,推荐去阿里云申请一个按时计费的Redis
- 阿里云按量付费redis。经典网络
- 申请redis的公网连接地址
- 修改白名单 允许0.0.0.0/0 访问
2、RedisTemplate 与 Lettuce
- 在我们SpringBoot的核心配置文件: application.properties 中对redis进行配置:
spring:
redis:
host: r-bp1nc7reqesxisgxpipd.redis.rds.aliyuncs.com
port: 6379
password: lfy:Lfy123456
- 然后编写测试方法,看是否能连接上我们的阿里云Redis
@Autowired
StringRedisTemplate redisTemplate;
@Test
void testRedis() {
ValueOperations<String, String> operations = redisTemplate.opsForValue();
operations.set("hello", "world");
String hello = operations.get("hello");
System.out.println(hello);
}
- 上面采用的是系统默认的 lettuce 客户端,用于连接 RedisServer 的
- 我们还可以通过jedis客户端连接我们的Redis
- 那么我们该如何切换客户端呢?
3、切换到jedis
- 导入Jedis的依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
- 通过核心配置文件,将redis的客户端类型设置为 jedis
spring:
redis:
host: r-bp1nc7reqesxisgxpipd.redis.rds.aliyuncs.com
port: 6379
password: lfy:Lfy123456
client-type: jedis
- 通过测试方法,输出一下当前的客户端类型
@Autowired
RedisConnectionFactory redisConnectionFactory;
@Test
void testRedis(){
// org.springframework.data.redis.connection.jedis.JedisConnectionFactory
System.out.println(redisConnectionFactory.getClass());
}
4、利用Redis实现URL访问次数统计功能
- 创建一个URL统计拦截器 【在控制器方法执行前执行】
@Component
public class RedisUrlCountInterceptor implements HandlerInterceptor {
@Autowired
StringRedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String uri = request.getRequestURI();
// 默认每次访问当前uri就会计数+1
redisTemplate.opsForValue().increment(uri);
return true;
}
}
- 在配置类中将我们定义的拦截器注册到IOC容器中
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
@Autowired
RedisUrlCountInterceptor redisUrlCountInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(redisUrlCountInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**",
"/js/**","/aa/**");
}
}
- 在我们的控制器方法中,利用 StringRedisTemplate 统计数据
@Slf4j
@Controller
public class IndexController {
@Autowired
StringRedisTemplate redisTemplate;
@GetMapping("/main.html")
public String mainPage(HttpSession session, Model model) {
log.info("当前方法是:{}", "mainPage");
ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
String s = opsForValue.get("/main.html"); // 获取main.html页面访问的次数
String s1 = opsForValue.get("/sql"); // 获取sql请求访问的次数
model.addAttribute("mainCount", s);
model.addAttribute("sqlCount", s1);
return "main";
}
}
- 修改对应页面的前端表单
<div class="col-md-6 col-xs-12 col-sm-6">
<div class="panel purple">
<div class="symbol">
<i class="fa fa-gavel"></i>
</div>
<div class="state-value">
<div class="value" th:text="${mainCount}">230</div>
<div class="title">/main.html</div>
</div>
</div>
</div>
<div class="col-md-6 col-xs-12 col-sm-6">
<div class="panel red">
<div class="symbol">
<i class="fa fa-tags"></i>
</div>
<div class="state-value">
<div class="value" th:text="${sqlCount}">3490</div>
<div class="title">/sql</div>
</div>
</div>
</div>
- 补充知识点:Filter 和 Interceptor 几乎有相同的功能,那么有什么区别呢?
- Filter 是Servlet的原生组件,脱离Spring应用也能使用
- Interceptor 是Spring定义的接口,可以使用Spring的自动装配功能 [@Autowired]