Chapter7: SpringBoot与数据访问
尚硅谷SpringBoot顶尖教程
1. JDBC
1.1 依赖及配置
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope><version>8.0.12</version>
</dependency>
全局配置文件配置数据源基础参数
## 数据源
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
数据源的配置属性封装在DataSourceProperties里面,支持在全局配置文件配置spring.datasource.xxx的属性。
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourcePropertiesimplements BeanClassLoaderAware, EnvironmentAware, InitializingBean {private Class<? extends DataSource> type;private String driverClassName;private String url;private String username;private String password;// ...// 构建数据源public DataSourceBuilder initializeDataSourceBuilder() {return DataSourceBuilder.create(getClassLoader()).type(getType()).driverClassName(determineDriverClassName()).url(determineUrl()).username(determineUsername()).password(determinePassword());}// ...
}
1.2 数据源自动配置原理
数据源的自动配置查看自动配置类DataSourceAutoConfiguration, 导入了DataSourceConfiguration数据源配置类, 数据源实例化的相关配置都在这个类中;
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {// ...@Configuration@Conditional(PooledDataSourceCondition.class)@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })@Import({ DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Hikari.class,DataSourceConfiguration.Dbcp.class, DataSourceConfiguration.Dbcp2.class,DataSourceConfiguration.Generic.class })@SuppressWarnings("deprecation")protected static class PooledDataSourceConfiguration {}// ...
}
上面的自动配置类中导入了配置类DataSourceConfiguration, web模块自动导入了spring-boot-starter-tomcat, 默认使用org.apache.tomcat.jdbc.pool.DataSource作为数据源, 可以使用spring.datasource.type指定数据源类型。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e7uqYZUV-1686468913853)(SpringBoot学习笔记-atguigu.assets/1686146719144.png)]
abstract class DataSourceConfiguration {@SuppressWarnings("unchecked")protected <T> T createDataSource(DataSourceProperties properties,Class<? extends DataSource> type) {// 根据导入的数据源类型type,实例化数据源return (T) properties.initializeDataSourceBuilder().type(type).build();}/*** Tomcat Pool DataSource configuration.*/@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true)static class Tomcat extends DataSourceConfiguration {@Bean@ConfigurationProperties(prefix = "spring.datasource.tomcat")public org.apache.tomcat.jdbc.pool.DataSource dataSource(DataSourceProperties properties) {// 创建数据库连接池org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(properties, org.apache.tomcat.jdbc.pool.DataSource.class);DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(properties.determineUrl());String validationQuery = databaseDriver.getValidationQuery();if (validationQuery != null) {dataSource.setTestOnBorrow(true);dataSource.setValidationQuery(validationQuery);}return dataSource;}}/*** Hikari DataSource configuration.*/@ConditionalOnClass(HikariDataSource.class)@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)static class Hikari extends DataSourceConfiguration {@Bean@ConfigurationProperties(prefix = "spring.datasource.hikari")public HikariDataSource dataSource(DataSourceProperties properties) {return createDataSource(properties, HikariDataSource.class);}}/*** DBCP DataSource configuration.** @deprecated as of 1.5 in favor of DBCP2*/@ConditionalOnClass(org.apache.commons.dbcp.BasicDataSource.class)@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp.BasicDataSource", matchIfMissing = true)@Deprecatedstatic class Dbcp extends DataSourceConfiguration {@Bean@ConfigurationProperties(prefix = "spring.datasource.dbcp")public org.apache.commons.dbcp.BasicDataSource dataSource(DataSourceProperties properties) {org.apache.commons.dbcp.BasicDataSource dataSource = createDataSource(properties, org.apache.commons.dbcp.BasicDataSource.class);DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(properties.determineUrl());String validationQuery = databaseDriver.getValidationQuery();if (validationQuery != null) {dataSource.setTestOnBorrow(true);dataSource.setValidationQuery(validationQuery);}return dataSource;}}/*** DBCP DataSource configuration.*/@ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class)@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp2.BasicDataSource", matchIfMissing = true)static class Dbcp2 extends DataSourceConfiguration {@Bean@ConfigurationProperties(prefix = "spring.datasource.dbcp2")public org.apache.commons.dbcp2.BasicDataSource dataSource(DataSourceProperties properties) {return createDataSource(properties,org.apache.commons.dbcp2.BasicDataSource.class);}}/*** Generic DataSource configuration.*/@ConditionalOnMissingBean(DataSource.class)// 使用spring.datasource.type指定数据源类型@ConditionalOnProperty(name = "spring.datasource.type")static class Generic {@Beanpublic DataSource dataSource(DataSourceProperties properties) {return properties.initializeDataSourceBuilder().build();}}
}
DataSourceBuilder#build()方法实例化数据源, 默认支持的数据源类型有:org.apache.tomcat.jdbc.pool.DataSource
org.apache.commons.dbcp.BasicDataSource
org.apache.commons.dbcp2.BasicDataSource
com.zaxxer.hikari.HikariDataSource
public class DataSourceBuilder {private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {"org.apache.tomcat.jdbc.pool.DataSource","com.zaxxer.hikari.HikariDataSource","org.apache.commons.dbcp.BasicDataSource", // deprecated 过时了"org.apache.commons.dbcp2.BasicDataSource" };private Class<? extends DataSource> type;// ...public DataSource build() {// 返回的就是当前builder的数据源类型type//type出处: DataSourceProperties#initializeDataSourceBuilder().type(type)Class<? extends DataSource> type = getType();DataSource result = BeanUtils.instantiate(type);maybeGetDriverClassName();bind(result);return result;}public DataSourceBuilder type(Class<? extends DataSource> type) {this.type = type;return this;}// ...
}
1.3 数据源数据初始化
数据源自动配置类中实例化DataSourceInitializer,数据源的一些初始化工作在这里面完成。
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {// ...@Bean@ConditionalOnMissingBeanpublic DataSourceInitializer dataSourceInitializer(DataSourceProperties properties,ApplicationContext applicationContext) {return new DataSourceInitializer(properties, applicationContext);}// ...
}
DataSourceInitializer实现了ApplicationListener接口,重写onApplicationEvent方法, 里面会调用runDataScripts()方法执行指定sql文件中插入数据的sql语句。
class DataSourceInitializer implements ApplicationListener<DataSourceInitializedEvent> {DataSourceInitializer(DataSourceProperties properties,ApplicationContext applicationContext) {this.properties = properties;this.applicationContext = applicationContext;}// 重写ApplicationListener#onApplicationEvent方法@Overridepublic void onApplicationEvent(DataSourceInitializedEvent event) {if (!this.properties.isInitialize()) {logger.debug("Initialization disabled (not running data scripts)");return;}// NOTE the event can happen more than once and// the event datasource is not used hereif (!this.initialized) {// 执行数据库脚本runDataScripts();this.initialized = true;}}// 执行数据库脚本private void runDataScripts() {// 获取spring.datasource.data配置的sql脚本List<Resource> scripts = getScripts("spring.datasource.data",this.properties.getData(), "data");String username = this.properties.getDataUsername();String password = this.properties.getDataPassword();// 运行脚本runScripts(scripts, username, password);}// 运行脚本private void runScripts(List<Resource> resources, String username, String password) {if (resources.isEmpty()) {return;}ResourceDatabasePopulator populator = new ResourceDatabasePopulator();populator.setContinueOnError(this.properties.isContinueOnError());populator.setSeparator(this.properties.getSeparator());if (this.properties.getSqlScriptEncoding() != null) {populator.setSqlScriptEncoding(this.properties.getSqlScriptEncoding().name());}for (Resource resource : resources) {populator.addScript(resource);}DataSource dataSource = this.dataSource;if (StringUtils.hasText(username) && StringUtils.hasText(password)) {dataSource = DataSourceBuilder.create(this.properties.getClassLoader()).driverClassName(this.properties.determineDriverClassName()).url(this.properties.determineUrl()).username(username).password(password).build();}// 获取数据库连接,执行sql语句DatabasePopulatorUtils.execute(populator, dataSource);}
}
DataSourceInitializer中的init方法使用@PostConstruct注解声明,在实例化完成后会执行该方法进行初始化工作,里面通过runSchemaScripts() 运行sql脚本执行了创建表的操作。
class DataSourceInitializer implements ApplicationListener<DataSourceInitializedEvent> {DataSourceInitializer(DataSourceProperties properties,ApplicationContext applicationContext) {this.properties = properties;this.applicationContext = applicationContext;}// 初始化@PostConstructpublic void init() {if (!this.properties.isInitialize()) {logger.debug("Initialization disabled (not running DDL scripts)");return;}if (this.applicationContext.getBeanNamesForType(DataSource.class, false,false).length > 0) {this.dataSource = this.applicationContext.getBean(DataSource.class);}if (this.dataSource == null) {logger.debug("No DataSource found so not initializing");return;}// 运行schema脚本runSchemaScripts();}// 运行schema脚本private void runSchemaScripts() {// 获取spring.datasource.schema配置的schema脚本List<Resource> scripts = getScripts("spring.datasource.schema",this.properties.getSchema(), "schema");if (!scripts.isEmpty()) {String username = this.properties.getSchemaUsername();String password = this.properties.getSchemaPassword();runScripts(scripts, username, password);try {this.applicationContext.publishEvent(new DataSourceInitializedEvent(this.dataSource));// The listener might not be registered yet, so don't rely on it.if (!this.initialized) {runDataScripts();this.initialized = true;}}catch (IllegalStateException ex) {logger.warn("Could not send event to complete DataSource initialization ("+ ex.getMessage() + ")");}}}
}
上面运行的两个脚本都是从DataSourceInitializer#getScripts方法中查找得到的,支持执行类路径下指定的脚本文件,如果没有指定就执行默认的脚本。
spring.datasource.platform配置xxx,那么脚本文件默认命名为schema-xxx.sql 或 data-xxx.sql ;
spring.datasource.platform没有配置,脚本文件默认为schema.sql或schema-all.sql, 可以使用schema属性指定加载sql的位置
// resources=spring.datasource.data or spring.datasource.schema指定的sql脚本
// fallback=data or schame
private List<Resource> getScripts(String propertyName, List<String> resources,String fallback) {if (resources != null) {// 如果spring.datasource.data 或 spring.datasource.schema有配置指定的脚本,就执行此处查找脚本资源。return getResources(propertyName, resources, true);}// 如果spring.datasource.data 或 spring.datasource.schema没有配置,就查找类路径下默认的脚本// platform=allString platform = this.properties.getPlatform();List<String> fallbackResources = new ArrayList<String>();// 默认脚本 schema-all.sql or data-all.sql fallbackResources.add("classpath*:" + fallback + "-" + platform + ".sql");// 默认脚本 schema.sql or data.sqlfallbackResources.add("classpath*:" + fallback + ".sql");return getResources(propertyName, fallbackResources, false);
}
全局配置文件配置执行的脚本, 建表脚本teacher.sql和初始化数据脚本initTeacher.sql
# 初始化执行sql
#spring.datasource.platform=xxx
spring.datasource.schema=classpath*:ddlSql/teacher.sql
spring.datasource.data=classpath*:ddlSql/initTeacher.sql
teacher.sql脚本内容
CREATE TABLE `teacher` (`tid` int(11) NOT NULL AUTO_INCREMENT,`tname` varchar(50) DEFAULT NULL,PRIMARY KEY (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
initTeacher.sql脚本内容
insert into teacher(tid,tname) values (null,'王老师'),(null,'crysw老师');
启动应用,查看启动日志。
[2023-06-07 23:01:36.036] [com.alibaba.druid.pool.DruidDataSource] [main] [923] [INFO ] {dataSource-1} inited
[2023-06-07 23:01:36.036] [org.springframework.jdbc.datasource.init.ScriptUtils] [main]
// 运行sql脚本teacher.sql
[441] [INFO ] Executing SQL script from URL [file:/D:/Develops/IdeaProjects/study-spring-boot/spring-boot-atguigu/spring-boot-02-config/target/classes/ddlSql/teacher.sql]
[2023-06-07 23:01:36.036] [org.springframework.jdbc.datasource.init.ScriptUtils] [main]
// 创建表teacher
[473] [DEBUG] 0 returned as update count for SQL: CREATE TABLE `teacher` ( `tid` int(11) NOT NULL AUTO_INCREMENT, `tname` varchar(50) DEFAULT NULL, PRIMARY KEY (`tid`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
[2023-06-07 23:01:36.036] [org.springframework.jdbc.datasource.init.ScriptUtils] [main] [476] [DEBUG] SQLWarning ignored: SQL state 'HY000', error code '1681', message [Integer display width is deprecated and will be removed in a future release.]
[2023-06-07 23:01:36.036] [org.springframework.jdbc.datasource.init.ScriptUtils] [main] [476] [DEBUG] SQLWarning ignored: SQL state 'HY000', error code '3719', message ['utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous.]
[2023-06-07 23:01:36.036] [org.springframework.jdbc.datasource.init.ScriptUtils] [main] [507] [INFO ] Executed SQL script from URL [file:/D:/Develops/IdeaProjects/study-spring-boot/spring-boot-atguigu/spring-boot-02-config/target/classes/ddlSql/teacher.sql] in 28 ms.
[2023-06-07 23:01:36.036] [org.springframework.jdbc.datasource.DataSourceUtils] [main] [329] [DEBUG] Returning JDBC Connection to DataSource
[2023-06-07 23:01:36.036] [org.springframework.jdbc.datasource.DataSourceUtils] [main] [110] [DEBUG] Fetching JDBC Connection from DataSource
// 运行sql脚本initTeacher.sql
[2023-06-07 23:01:36.036] [org.springframework.jdbc.datasource.init.ScriptUtils] [main] [441] [INFO ] Executing SQL script from URL [file:/D:/Develops/IdeaProjects/study-spring-boot/spring-boot-atguigu/spring-boot-02-config/target/classes/ddlSql/initTeacher.sql]
[2023-06-07 23:01:36.036] [org.springframework.jdbc.datasource.init.ScriptUtils] [main]
// 插入初始化数据到teacher表
[473] [DEBUG] 2 returned as update count for SQL: insert into teacher(tid,tname) values (null,'王老师'),(null,'crysw老师')
[2023-06-07 23:01:36.036] [org.springframework.jdbc.datasource.init.ScriptUtils] [main] [507] [INFO ] Executed SQL script from URL [file:/D:/Develops/IdeaProjects/study-spring-boot/spring-boot-atguigu/spring-boot-02-config/target/classes/ddlSql/initTeacher.sql] in 4 ms.
1.4 数据模板
spring提供了数据库模板JdbcTemplate给我们来操作数据库, 自动配置类JdbcTemplateAutoConfiguration提供了jdbcTemplate组件。
@Configuration
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class JdbcTemplateAutoConfiguration {private final DataSource dataSource;public JdbcTemplateAutoConfiguration(DataSource dataSource) {this.dataSource = dataSource;}@Bean@Primary@ConditionalOnMissingBean(JdbcOperations.class)public JdbcTemplate jdbcTemplate() {return new JdbcTemplate(this.dataSource);}
}
编写controller,使用数据模板jdbcTemplate操作数据库测试。
@Controller
public class HelloController {Logger logger = LoggerFactory.getLogger(this.getClass());@Autowiredprivate JdbcTemplate jdbcTemplate;@ResponseBody@GetMapping("/queryTeacher")public Map<String, Object> queryTeacher() {List<Map<String, Object>> teachers = jdbcTemplate.queryForList("select * from teacher");return teachers.get(0);}
}
访问 http://localhost:8082/boot1/queryTeacher, 返回结果:
{"tid": 1,"tname": "王老师"
}
2. 整合Druid数据源
2.1 依赖及配置
导入依赖
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.8</version>
</dependency>
全局配置文件指定数据库连接池类型(指定数据源)
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
编写配置类,整合Druid数据源
@Configuration
public class DruidConfig {@ConfigurationProperties(prefix = "spring.datasource")@Beanpublic DataSource druidDataSource() {return new DruidDataSource();}// 配置Druid监控// 1. 配置一个管理后台的Servlet@Beanpublic ServletRegistrationBean statViewServlet() {ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");Map<String, String> initParams = new HashMap<>();// 设置Druid监控登录用户和密码initParams.put("loginUsername", "admin");initParams.put("loginPassword", "123456");initParams.put("allow", ""); // 默认允许所有initParams.put("deny", "192.168.1.103"); // 拒绝该主机访问bean.setInitParameters(initParams);return bean;}// 2. 配置一个web监控的filter@Beanpublic FilterRegistrationBean webStatFilter() {FilterRegistrationBean filterBean = new FilterRegistrationBean();filterBean.setFilter(new WebStatFilter());Map<String, String> filterParams = new HashMap<>();filterParams.put("exclusions", "*.js,*.css,/druid/*");filterBean.setInitParameters(filterParams);filterBean.setUrlPatterns(Arrays.asList("/*"));return filterBean;}
}
2.2 druid监控
启动应用,访问 http://localhost:8082/boot1/druid 进入Druid监控登录界面

访问查询请求 , http://localhost:8082/boot1/queryTeacher 查看监控。

2.3 druid自动配置类
上面是自定义的数据源配置类,提供了DruidDataSource实例。还可以使用druid官方提供的启动器提供了自动配置类 DruidDataSourceAutoConfigure, 不用自己编写配置类。
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.3</version>
</dependency>
自动配置类 DruidDataSourceAutoConfigure
@Configuration
@ConditionalOnClass(DruidDataSource.class)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties({DruidStatProperties.class, DataSourceProperties.class})
@Import({DruidSpringAopConfiguration.class,// 监控的servlet配置DruidStatViewServletConfiguration.class,// 监控的filter配置DruidWebStatFilterConfiguration.class,// DruidFilterConfiguration.class})
public class DruidDataSourceAutoConfigure {private static final Logger LOGGER = LoggerFactory.getLogger(DruidDataSourceAutoConfigure.class);@Bean(initMethod = "init")@ConditionalOnMissingBeanpublic DataSource dataSource() {LOGGER.info("Init DruidDataSource");return new DruidDataSourceWrapper();}
}
druid的监控servlet配置中,需要指定监控界面开启为true,才能访问监控界面;
@ConditionalOnWebApplication
@ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true")
public class DruidStatViewServletConfiguration {//...
}
druid监控url请求,需要配置开启webFilter,才能实现请求的拦截监控。
@ConditionalOnWebApplication
@ConditionalOnProperty(name = "spring.datasource.druid.web-stat-filter.enabled", havingValue = "true")
public class DruidWebStatFilterConfiguration {//...
}
在全局配置文件中配置druid监控的相关参数
# 开启druid监控
spring.datasource.druid.stat-view-servlet.enabled=true
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=12345678
spring.datasource.druid.stat-view-servlet.reset-enable=false
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
spring.datasource.druid.web-stat-filter.enabled=true
spring.datasource.druid.web-stat-filter.url-pattern=/*
spring.datasource.druid.web-stat-filter.exclusions=*.js,*.css,/druid/*
注释掉自定义的数据源配置类, 再次启动应用访问 http://localhost:8082/boot1/druid 也成功进入Druid监控登录界面。随机触发几个请求,也可以实现监控。

druid监控博文学习
Spring系列之集成Druid连接池及监控配置 - 掘金
SpringBoot开启Druid监控统计功能(SQL监控、慢SQL记录、Spring监控、去广告)
3. 整合Mybatis
3.1 依赖管理
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.5</version>
</dependency>
依赖关系图

3.2 mybatis核心配置及参数配置
在类路径下添加mybatis核心配置文件mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 全局配置参数,需要时再设置 --><settings><!-- 打开延迟加载开关 --><setting name="lazyLoadingEnabled" value="true"/><!-- 将积极加载改为消极加载,即按需加载 --><setting name="aggressiveLazyLoading" value="false"/><!-- 开启二级缓存 --><setting name="cacheEnabled" value="true"/><!--开启驼峰映射--><setting name="mapUnderscoreToCamelCase" value="true"/></settings>
</configuration>
在全局配置文件application.properties中配置mybatis参数
## mybatis配置
mybatis.config-location=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
mybatis.type-aliases-package=com.aiguigu.springboot02config.entities
3.3 mapper接口开发
注解版mapper接口,不需要mapper映射xml文件,sql直接写在接口方法上。
// 指定这是一个操作数据库的mapper接口
//@Mapper // 注释掉后在启动类上加@MapperScan(value = {"com.aiguigu.spriingboot02config.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 deleteDeptById(Integer id);@Options(useGeneratedKeys = true, keyProperty = "id")@Insert("insert into department(department_name) values(#{departmentName})")public int insertDept(Department department);@Update("update department set department_name=#{departmentName} where id=#{id}")public int updateDept(Department department);
}
mapper接口+mapper映射xml文件的方式
// @Mapper 或 @MapperScan将接口扫描装配到容器中
public interface EmployeeMapper {Employee2 getEmpById(Integer id);void insertEmp(Employee2 employee);
}
EmployeeMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aiguigu.springboot02config.mapper.EmployeeMapper"><select id="getEmpById" resultType="com.aiguigu.springboot02config.entities.Employee2">select * from employee where id = #{id}</select><insert id="insertEmp" useGeneratedKeys="true" keyProperty="id" keyColumn="id">insert into employee(lastName,email,gender,d_id)values(#{lastName},#{email},#{gender},#{d_id})</insert>
</mapper>
4. 整合JPA
4.1 Spring Data简介
Spring Data项目简化了基于Spring框架应用的数据访问技术,包括非关系型数据库、Map-Reduce框架、云数据服务等,另外也包含对关系数据库的访问支持。
Spring Data为我们提供使用统一的API来对数据访问层进行操作;这主要是Spring Data Commons项目来实现的。Spring Data Commons让我们在使用关系型或非关系型数据访问技术时都基于Spring提供的统一标准,标准包含了CRUD(创建、获取、更新、删除)、查询、排序和分页的相关操作。
Repository<T ID extends Serializable> 统一的Repository接口 ;
RevisionRepository<T, ID extends Serializable, N extends Number & Comparable<N>> 基于乐观锁机制;
CrudRepository<T, ID extends Serializable> 基本的CRUD操作;
PagingAndSortingRepository<T, ID extends Serializable> 基本CRUD及分页;
xxxTemplate 数据访问模板类 (JdbcTemplate, RedisTemplate);
JPA与Spring Data
- JpaRepository 基本功能, 编写接口继承JpaRepository, 就有了crud及分页等基本功能;
- 定义符合规范的方法命名, 在接口中只需要声明符合规范的方法, 就拥有对应的功能;

-
@Query 自定义查询, 定制查询SQL;
整合框架图

4.2 使用Spring Data JPA
导入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
编写一个实体类(bean)和数据库表进行映射, 并且配置好映射关系。
// 使用JPA注解配置映射关系
@Entity // 标识这是一个实体类,和数据库表映射
@Table(name = "tb_user") // 指定映射的库表, 如果省略默认表名就是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;public User() {}public User(Integer id, String lastName, String email) {this.id = id;this.lastName = lastName;this.email = email;}// setXXX and getXXX
}
编写一个Dao接口操作, 实体类对应的数据库表(Repository)。
// 继承 JpaRepository 完成对数据库表的操作
public interface UserRepository extends JpaRepository<User, Integer> {
}
基本的配置
## 更新或者创建数据库表结构
spring.jpa.hibernate.ddl-auto=update
## 控制台显示sql
spring.jpa.show-sql=true
编写controller使用repository
@RestController
public class UserController {@AutowiredUserRepository userRepository;@GetMapping("/user/{id}")public User getUser(@PathVariable("id") Integer id) {User user = userRepository.findOne(id);return user;}@GetMapping("/user")public User insertUser(User user) {User _user = userRepository.save(user);return _user; // 封装了自增主键id返回}
}
测试 http://localhost:8082/boot1/user?lastName=admin&email=admin@qq.com

访问 http://localhost:8082/boot1/user/1

相关文章:
Chapter7: SpringBoot与数据访问
尚硅谷SpringBoot顶尖教程 1. JDBC 1.1 依赖及配置 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency><groupId>mysql</groupId…...
【Sqlite3】maraidb和sqlite3部分命令操作区别
maraidb和sqlite3部分命令操作区别记录 1.安装sqlite3 在实现我的视频点播系统项目时,我尝试封装了两种数据库的调用逻辑 mysql(maraidb)sqlite3 这里封装sqlite3的原因是,sqlite3主要针对的就是嵌入式数据库,其性能…...
Linux中新建用户使用sudo问题
文章目录 sudo问题 sudo问题 sudo:权限提示指令,当使用sudo这条指令时,会将普通用户的权限提升为root权限 但是在命令行新建用户,这个用户使用sudo指令对一条指令提权是用不了的 这个用户没有在sudoers file这个文件中ÿ…...
Sentinel源码分析-ProceesorSlotChain调用链及树状资源节点
Sentinel 实现流控,隔离,降级等功能,本质要做两件事: 数据统计: 统计某个资源的访问数据(QPS,RT(响应时间),异常比例)等信息规则判断: 判断流控规…...
springboot 连接 kafka集群(kafka版本 2.13-3.4.0)
springboot 连接 kafka集群 一、环境搭建1.1 springboot 环境1.2 kafka 依赖 二、 kafka 配置类2.1 发布者2.1.1 配置2.1.2 构建发布者类2.1.3 发布消息 2.2 消费者2.2.1 配置2.2.2 构建消费者类2.2.3 进行消息消费 一、环境搭建 1.1 springboot 环境 JDK 11 Maven 3.8.x spr…...
Nacos配置中心使用(Spring Cloud版)
目标 向项目中集成Nacos配置。原项目是一个SpringBoot项目。这里假设我们无法修改原有项目的SpringBoot版本。 注意 在不动SpringBoot版本的前提下,根据SpringBoot的版本,确定Spring Cloud和Nacos版本。Nacos版本其实就是Spring Cloud Alibaba版本。在…...
STM32F407硬件I2C实现MPU6050通讯(CUBEIDE)
STM32F407硬件I2C实现MPU6050通讯 文章目录 STM32F407硬件I2C实现MPU6050通讯cubeide设置写操作与读操作函数实现复位,读取温度,角度等函数封装mpu6050.cmpu6050.h代码分析 DMP移植1.修改头文件路径为自己的头文件路径2.修改I2C读写函数为自己mcu平台的读…...
HTML5 语义元素(一)页面结构
本篇主要介绍HTML5增加的语义元素中关于页面结构方面的,包含: <article>、<aside>、<figure>、<figcaption>、<footer>、<header>、<main>、<nav>、<section>等元素。 目录 1. 语义元素介绍 1.…...
嵌套滚动实践:onInterceptTouchEvent与NestedScrolling【实用为准】
嵌套滚动:内外两层均可滚动,比如上半部分是一个有限的列表,下半部分是WebView,在内层上半部分展示到底的时候,外部父布局整体滚动内部View,将底部WevView拉起来,滚动到顶部之后再将滚动交给内部…...
Redis入门 - 5种基本数据类型
原文首更地址,阅读效果更佳! Redis入门 - 5种基本数据类型 | CoderMast编程桅杆https://www.codermast.com/database/redis/five-base-datatype.html 说明 在我们平常的业务中基本只会使用到Redis的基本数据类型(String、List、Hash、Set、…...
mybatis-plus用法(一)
MyBatis-plus 是一款 Mybatis 增强工具,用于简化开发,提高效率。下文使用缩写 mp来简化表示 MyBatis-plus,本文主要介绍 mp 整合 Spring Boot 的使用。 (5条消息) mybatis-plus用法(二)_渣娃工程师的博客-CSDN博客 1…...
源码安装包管理
1. 源码包基本概述 在linux环境下面安装源码包是比较常见的, 早期运维管理工作中,大部分软件都是通过源码安装的。那么安装一个源码包,是需要我们自己把源代码编译成二进制的可执行文件。 源码包的编译用到了linux系统里的编译器,通常源码包…...
Vue|获取表单数据
在Vue中获取表单数据有多种方式,具体取决于你使用的是哪种表单元素和你的需求。 1. 单个表单元素: 如果你只需要获取单个表单元素的值,可以使用v-model指令将表单元素的值绑定到Vue实例的一个属性上。例如: <input type&quo…...
微信小程序入门学习02-TDesign中的自定义组件
目录 1 显示文本2 自定义组件3 变量定义4 值绑定总结 我们上一篇讲解了TDesign模板的基本用法,如何开始阅读模板。本篇我们讲解一下自定义组件的用法。 1 显示文本 官方模板在顶部除了显示图片外,还显示了一段文字介绍。文字是嵌套在容器组件里…...
【linux kernel】linux media子系统分析之media控制器设备
文章目录 一、抽象媒体设备模型二、媒体设备三、Entity四、Interfaces五、Pad六、Link七、Media图遍历八、使用计数和电源处理九、link设置十、Pipeline和Media流十一、链接验证十二、媒体控制器设备的分配器API 本文基于linux内核 4.19.4,抽象媒体设备模型框架的相…...
Scala--03
第6章 面向对象 Scala 的面向对象思想和Java 的面向对象思想和概念是一致的。 Scala 中语法和 Java 不同,补充了更多的功能。 6.1类和对象详解 6.1.1组成结构 构造函数: 在创建对象的时候给属性赋值 成员变量: 成员方法(函数) 局部变量 代码块 6.1.2构造器…...
【MongoDB】--MongoDB高级功能
目录 一、前言二、聚合管道aggregate1、示例说明2、具体代码实现一、前言 这里主要记录mongodb一些高级功能使用,如聚合。 二、聚合管道aggregate 聚合操作将来自多个文档的值组合在一起,并且可以对分组数据执行各种操作以返回单个结果,主要用于处理数据(诸如统计平均值,…...
C# new与malloc
目录 C# new与malloc C# new与malloc的区别 C# new关键字底层做的操作 C# new与malloc new关键字: new关键字在C#中用于实例化对象,并为其分配内存。它是面向对象编程的基本操作之一。使用new关键字可以在托管堆上分配内存,同时调用对象的构…...
微软MFC技术简明介绍
我是荔园微风,作为一名在IT界整整25年的老兵,今天来看一下微软MFC技术简明介绍 Visual C 与 MFC 微软公司于1992年上半年推出了C/C 7.0 产品时初次向世人介绍了MFC 1.0,这个产品包含了20,000行C原始代码,60个以上的Windows相关类…...
汽车电子Autosar之车载以太网
前言 近些年来,随着为了让汽车更加安全、智能、环保等,一系列的高级辅助驾驶功能喷涌而出。未来满足这些需求,就对传统的电子电器架构带来了严峻的考验,需要越来越多的电子部件参与信息交互,导致对网络传输速率&#x…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
