目录
工欲善其事必先利其器。
码字不易,喜欢就点个关注❤,持续更新技术内容。
接上一篇:
第一篇:SpringBoot项目的创建和开发_Maxlec的博客-CSDN博客
1 MybatisPlus
介绍完如何接收和处理前端各种请求并响应结果后,接下来就是如何与数据库打交道了。如:如何通过Mybatis和MybatisPlus对数据库表的进行各种操作(CRUD),并了解其中的原理。
1.1 ORM介绍
ORM(Object Relational Mapping,对象关系映射)是为了解决面向对象与关系数据库存在的互不匹配现象的一种技术。通过使用描述对象和数据库之间映射的元数据将程序中的对象自动持久化到关系数据库中。ORM框架的本质是简化编程中操作数据库的编码。
1.2 MybatisPlus
Mybatis是一款优秀的数据持久层ORM框架,被广泛地应用于应用系统。Mybatis能够非常灵巧地实现动态SQL,可以使用xml或注解来配置和映射原生信息,能够轻松地将Java的POJO(Plain Ordinary Java Object,普通Java对象)与数据库中的表和字段进行映射关联。
Mybatis提供基于JDBC的数据库连接。通常使用数据库连接池(如德鲁伊)来管理数据库连接的复用和性能优化。
在结果映射阶段,MyBatis可以根据Java类的定义和映射文件中的配置,使用反射技术动态地创建对象实例并设置属性值,将查询结果映射为Java对象。
Mybatis-Plus是Mybatis的增强工具,在Mybatis的基础上做了简化和增强。
首先在pom.xml中添加mybatis-plus的依赖坐标,其中下载mybatis-plus依赖的同时也对mybatis的依赖进行了引入,后续也可以进行mybatis开发。我要连接的数据库是sqlserver,所以添加上sqlserver连接驱动的依赖坐标。以及管理数据库连接的复用和性能优化的连接池德鲁伊:(注意druid版本)
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc4</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
然后在application.properties中配置数据库连接以及数据源的相关信息:
我们要清楚的就是Spring Boot默认的数据源是org.apache.tomcat.jdbc.pool.DataSource,
实际开发中我们可能需要使用我们比较熟悉的数据源或者性能比比较高的数据源,
spring.datasource.type属性的存在能够使我们快速的指定需要的数据源,比如Druid。
#指定我们需要的数据源
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# sqlServer链接驱动
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
# 指定Sqlserver服务端口和数据库
# 可以新建查询执行exec sys.sp_readerrorlog 0,1,'listening';查看端口,也可以在SQLServer配置管理器修改
# Mysql可以运行show variables like 'port';语句查看
spring.datasource.url=jdbc:sqlserver://localhost:1434;DatabaseName=xxx
spring.datasource.username=xxx
spring.datasource.password=xxx
最后在启动类中添加@MapperScan注解,配置的包路径,扫描所有mapper接口,注册到Spring容器中,为后续Bean初始化做准备:
@SpringBootApplication
@MapperScan("com.xxx.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
1.3 Mybatis注解开发
所有的依赖下载和相关配置完成后,就可以通过Mybatis和MybatisPlus对数据库表的进行各种操作了(CRUD)。
在进行Mybatis开发我们先了解Mybatis的开发。以下是常用的Mybatis注解:
注解 | 功能 |
---|---|
@insert | 实现插入语句的发送 |
@Update | 实现更新语句的发送 |
@Delete | 实现删除语句的发送 |
@Select | 实现查询语句的发送 |
@Results | 封装多个结果集 |
@Result | 实现查询结果集的封装 |
@One | 实现一对一结果集封装 |
@Many | 实现一对多结果集封装 |
查询返回用户
定义一个与数据库表对应的类,其中的成员变量与数据库表中的字段一一对应。
@TableName("t_user")
public class User {
//主键建议用Integer
@TableId(type=IdType.AUTO)
private Integer id;
private String uname;
private String pwd;
private String birthday;
Setter and Getter;
toString(){...};
}
在mapper包中新建用户接口,添加@Mapper注解,使得@MapperScan可以扫描到,注册到Spring容器中,当使用的时候会动态初始化出接口实现类对象,我们要使用接口中定义操作方法时只需进行注入调用即可。
@Mapper
public interface userMapper {
@Select("select * from user")
//注意一定要写映射的类,如果映射的类的类名与数据库表不一致,
//需要在类的定义上添加@TableName("表名")指定该类要映射的表。
//且在MybatisPlus注解开发中,自动生成sql会查询所有类下的成员,
//所以类中的成员变量一定要与数据库表字段一一对应。
public List<User> queryUser();
}
在控制器中注入mapper中的接口UserMapper,初始化出接口实现类对象userMapper,并调用其中的操作方法,客户端发送请求,查询返回并成功响应给前端:
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/getUser")
public String getUser(){
List<User> users = userMapper.queryUser();
users.forEach(s -> System.out.println(s));
return "请求成功:"+ users;
}
}
查询返回结果:
添加用户
@Mapper
public interface UserMapper {
//在Mybatis注解开发中,手动写sql语句可以只查询或插入部分字段,
//只需要保证查询或插入的字段与类中成员变量一一对应即可。
@Insert("insert into t_user values(#{uname}, #{pwd}, #{birthday})")
public int insertUser(User user);
}
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@PostMapping("/insertUser")
public String insertUser(User user){
int i = userMapper.insertUser(user);
if (i > 0) {
return "插入成功";
}else {
return "插入失败";
}
}
}
插入结果:
1.4 MybatisPlus注解开发
Mybatis-Plus是Mybatis的增强工具,在Mybatis的基础上做了简化和增强。但当关系映射的实现比较复杂时,如进行多表查询时,就需要通过Mybatis手动配置相关的注解和写sql语句来完成。但在大多数情况MybatisPlus还是相当快捷、方便和实用的。
常用注解:
@TableName(value="t_xxx"):表名注解,如果类名与表名不一致,可以指定该类映射的数据库表。
@TableField(exist = boolean / "表名"):字段注解(非主键),第一个属性是否映射为数据库表字段,第二个属性是如果类的属性与表的字段不一致,可以指定该类的属性映射的数据库表中的字段。
@TableId(type=IdType.AUTO):主键注解,说明数据库主键自增,插入时回显主键。
@Version:乐观锁注解、标记在字段上。
@EnumValue:普通枚举类注解(注解在枚举字段上)。
以上只是描述了部分常用注解的部分属性,还有很多的其他注解功能可以参考文档开发。
查询用户
在MybatisPlus开发中,查询用户相当简单,只需让原用户类对应的接口继承MybatisPlus的mapper下的BaseMapper<User>接口,注意添加泛型:
@Mapper
public interface UserMapper extends BaseMapper<User> {
//注意一定要在继承的BaseMapper泛型上写上要映射的类;
//另外,在MybatisPlus注解开发中,
//因为可以直接在控制器中调用自动生成查询或插入等sql的方法,会涉及到类中所有成员变量
//所以类中的成员变量一定要与数据库表字段一一对应。
}
然后在UserController中,就可以直接调用BaseMapper接口中定义的自动生成sql操作的指定方法进行查询了:
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/getUser")
public String getUser(){
List<User> users = userMapper.selectList(null);
users.forEach(s -> System.out.println(s));
return "请求成功:"+ users;
}
}
查询返回结果:
条件查询
因为MybatisPlus不用手动写sql查询语句,所有当需要进行条件查询时,要通过条件构造器QueryWrapper进行条件的定义,然后传入给查询方法,查询方法会根据传入的条件对象自动生成sql查询语句:
注意:因为不用手动写sql后,生成的sql查询语句会涉及到类中所有属性,若其中一个属性不存在于表中,mysql会报未知字段的错误。需要在对应类中属性上添加@TableField(exist = false)注解。
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/getUser")
public String getUser(){
// 初始化条件对象
QueryWrapper<User> queryWrap = new QueryWrapper();
queryWrap.eq("uname","Mingwan");
List<User> users = userMapper.selectList(queryWrap);
users.forEach(s -> System.out.println(s));
return "请求成功:"+ users;
}
}
查询返回结果:
添加用户
注意:因为我使用的是Sqlserver数据库,设置主键id为自增时是不能显示插入id值的,正规插入新建查询语句如下:
set IDENTITY_INSERT t_user ON --打开显示插入
INSERT INTO t_user(id, uname, pwd, birthday) VALUES(6, 'Mingwan' , '1234567', '2002-11-11')
set IDENTITY_INSERT t_user OFF --关闭显示插入
而在springboot的MybatisPlus注解开发中如果在对应的类中添加id变量,直接在控制器中调用自动生成查询或插入等sql的方法,会涉及到类中所有成员变量,那么无论如何是会出现不能显示插入的错误。
解决办法:
在定义实体类时定义除了主键以外的成员变量,在控制器中调用自动生成查询或插入等sql的方法时就不会涉及到主键id,主键id的自增由Sqlserver数据库自己完成。
使用Mybatis注解开发,手动写sql语句可以只查询或插入部分字段,只需要保证查询或插入的字段与类中成员变量一一对应即可。
@Mapper
public interface UserMapper extends BaseMapper<User> {
//注意一定要在继承的BaseMapper泛型上写上要映射的类;
//另外,在MybatisPlus注解开发中,
//因为可以直接在控制器中调用自动生成查询或插入等sql的方法,会涉及到类中所有成员变量
//所以类中的成员变量一定要与数据库表字段一一对应。
}
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@PostMapping("/insertUser")
public String insertUser(User user) {
int i = userMapper.insert(user);
if (i > 0) {
return "插入成功";
} else {
return "插入失败";
}
}
}
插入结果:
2 Mybatis多表查询和分页查询
2.1 查询用户并返回用户所有订单
由于涉及多表查询,需要在查询表的类中定义了非字段的属性,MybatisPlus自动生成sql的方法查询不到值,不适合用多表查询。需要通过Mybatis手动配置相关的注解和写sql语句来完成。
MybatisPlus可以使用Mybatis提供的@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置。
注解 | 说明 |
---|---|
@Results | 代替<resultMap>标签,表示查询的结果集。该注解中可以加入单个或多个@Result注解 |
@Result | 代替<id>标签,@Result中可以使用以下属性: column:数据表的字段名称 property:类中对应的属性名 one:与@One注解配合,进行一对一的映射 many:与@Many注解配合,进行一对多的映射 |
@One | 代替<assocation>标签,用于指定查询中返回的单一对象 通过select属性指定用于多表查询的方法 使用格式:@Result(column="xx", property="xx", one=@One(select="xx")) |
@Many | 代替<conllection>标签,用于指定查询中返回的集合对象 使用格式:@Result(column="xx", property="xx", many=@Many(select="xx")) |
需求分析
在数据库中建立如下两张表:
查询用户的同时,查询出用户的订单情况,所以在建表时需要有让两张表产生关联的标识,那t_order表中uid字段就是用来描述订单对应的用户,当查询返回该用户信息时可以通过对应的uid查询返回所有订单。
代码编写和逻辑分析
所以编写多表查询代码时在原用户类的基础上增加一个订单属性orders,查询返回该用户信息时也能返回所有对应的订单信息。增加的这个属性在用户表里是不存在对应字段的,所以要通过对应的uid查询返回所有订单。
public class User {
//主键建议用Integer
@TableId(type=IdType.AUTO)
private Integer id;
private String uname;
private String pwd;
private String birthday;
//1.描述该用户所以订单
//2.还是那个问题,避免当要使用MybatisPlus提供的方法时,自动生成sql的方法,将其映射为数据库表字段。
private List<Order> orders;
Setter and Getter;
toString(){...};
}
因为在用户类中定义了非字段的属性orders,MybatisPlus自动生成sql的方法查询不到值。所以MybatisPlus对于多表查询是无能为力的,要使用Mybatis自定义查询方法。在用户类接口方法中使用Mybatis提供的@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置:
@Mapper
public interface UserMapper extends BaseMapper<User> {
@Select("select * from t_user")
@Results(
{
@Result(column = "id", property = "id"),
@Result(column = "uname", property = "uname"),
@Result(column = "pwd", property = "pwd"),
@Result(column = "birthday", property = "birthday"),
// 将id作为参数传递给selectOrders方法,然后该方法通过uid=#{id}查询所有的用户订单
@Result(column = "id", property = "orders", javaType = List.class,
many = @Many(select = "com.bree.mapper.OrderMapper.selectOrders"))
}
)
List<User> selectAllUsersAndOrder();
}
在订单类接口方法中定义通过uid查询的方法selectOrders():
@Mapper
public interface OrderMapper {
@Select("select * from t_order where uid = #{uid}")
List<Order> selectOrders(int uid);
}
在UserController中调用查询方法,并将返回的结果打印和响应:
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/selectAllUsersAndOrder")
public String selectAllUsersAndorder(){
List<User> users = userMapper.selectAllUsersAndOrder();
users.forEach(s-> System.out.println(s+"\r\n"));
return "请求成功:"+users;
}
}
多表查询返回结果:
2.2 查询订单并返回其对应的用户
需求分析
查询出订单的同时,查询出该订单对应的用户,t_order表中uid字段是让两张表产生关联的标识,就是用来描述订单对应的用户,当查询返回该订单信息时可以通过对应的uid查询返回订单对应的用户。
代码编写和逻辑分析
在原订单类的基础上增加一个用户属性users,查询返回该订单信息时也能返回其对应的用户信息。增加的这个属性在订单表里是不存在对应字段的,所以要通过对应的uid查询返回订单对应的用户。
public class Order {
@TableId(type=IdType.AUTO)
private Integer id;
private String total ;
private String uid;
@TableField("order_time")
private String ordertime;
//1.描述该订单对应的用户
//2.避免当要使用MybatisPlus提供的方法时,自动生成sql的方法,将其映射为数据库表字段。
private List<User> users;
Setter and Getter;
toString(){...};
}
同样的,在订单类接口方法中使用Mybatis提供的@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置:
@Mapper
public interface OrderMapper {
@Select("select * from t_order")
@Results(
{
@Result(column = "id", property = "id"),
@Result(column = "total", property = "total"),
@Result(column = "uid", property = "uid"),
@Result(column = "ordertime", property = "ordertime"),
// 将uid作为参数传递给queryUser方法,然后该方法通过id=#{uid}查询订单对应的用户
@Result(column = "uid", property = "users", javaType = List.class,
many = @Many(select = "com.bree.mapper.UserMapper.queryUser"))
}
)
List<Order> selectAllOrdersAndUser();
}
在OrderController中调用查询方法,并将返回的结果打印和响应:
@RestController
public class OrderController {
@Autowired
OrderMapper orderMapper;
@GetMapping("/selectAllOrdersAndUser")
public String selectAllOrdersAndUser(){
List<Order> orders = orderMapper.selectAllOrdersAndUser();
orders.forEach(System.out::println);
return "请求成功";
}
}
多表查询结果,如下结果示例是查询到的五条订单中的两条:
2.3 分页查询
分页查询类似于条件查询,进行分页查询只需调用分页查询方法时要传入分页规则对象page和唯一字段排序条件wrapper,不过在这之前需要在配置类中定义一个MybatisPlusInterceptor的分页拦截器,当我们进行Sql查询时都会进入这个拦截器。我使用的是SQLserver,所以定义为对Sqlserver数据库进行的分页查询。
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor Interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.SQL_SERVER);
Interceptor.addInnerInterceptor(paginationInnerInterceptor);
return Interceptor;
}
}
完成拦截器定义和配置后就可以调用分页查询的方法,传入分页规则对象page和唯一字段排序条件wrapper:
@RestController
public class OrderController {
@Autowired
OrderMapper orderMapper;
//分页查询
@GetMapping("/order/findByPage")
public IPage findByPage(){
//设置分页规则,分页起始值和每页条数
Page<Order> page = new Page<>(0,3);
//Sqlserver中需要加一个唯一字段排序,否则系统排序结果不唯一,报
QueryWrapper<Order> wrapper = new QueryWrapper();
wrapper.orderByDesc("id");
//接收分页结果集
IPage iPage = orderMapper.selectPage(page,wrapper);
return iPage;
}
}
查询返回结果: