1.SpringBoot整合Mybatis说明
1.1 Mybatis介绍
1、MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
2、MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL语句 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索以及释放资源等jdbc繁杂的过程代码。
3、Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
4、总之,Mybatis对JDBC访问数据库的过程进行了封装,简化了JDBC代码,解决JDBC将结果集封装为Java对象的麻烦。
1.2 ORM思想
对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
核心知识:
宗旨:利用对象操作数据库
1、要求查询的结果集可以自动封装为对象(查-读)
2、利用对象封装数据,之后(自动)动态的生成SQL语句,进行CRUD操作(写)
1.3 @SpringBootTest注解
说明:@SpringBootTest注解是SpringBoot自1.4.0版本开始引入的一个用于测试的注解
/**
* 要求:1、注解类所在的包要与启动类在相同包下或者在其子包下
* 2、从Spring容器中获取对象调用
*/
@SpringBootTest
public class ControllerTest {
/**
* 调用由spring容器管理的 Controller Service UserMapper 接口中的方法
*/
@Autowired
private UserMapper userMapper;//代理对象
@Test
public void test1(){
List<User> list = userMapper.selectAllUser();
for (User user:list) {
System.out.println(user);
}
}
}
1.4 Mybatis的调用过程
1、Spring容器为接口创建实例对象或者代理对象
2、根据@Autowired注解为接口注入实例化对象/代理对象
3、用户通过Mapper接口,调用接口中的方法
4、接口根据全限定路径去对应XXX.xml文件中的namespace从而映射到.xml文件
5、再根据接口中的方法名去对应XXX.xml文件中的SQL语句的ID,从而执行SQL语句
6、将返回的结果集读入到用来封装数据的对象中去
1.5 Mybatis的动态SQL语句
引用:
<sql id="col">
id,name,age,sex
</sql>
1.5.1 if语句
<select id="selectUserByUsernameAndSex" resultType="User">
select <include refid="col"></include> from demo_user
<if test="name!=null">
name=#{name}
</if>
<if test="sex!=null">
and sex=#{sex}
</if>
</select>
这样写我们可以看到,如果 sex 等于 null,那么查询语句为 select * from user where name=#{name},但是如果name 为空呢?那么查询语句为 select * from demo_user where and sex=#{sex},这是错误的 SQL 语句,如何解决呢?请看下面的 where 语句
1.5.2 where语句
<select id="selectUserByUsernameAndSex" resultType="User">
select <include refid="col"></include> from demo_user
<where>
<if test="name!=null">
name=#{name}
</if>
<if test="sex!=null">
and sex=#{sex}
</if>
</where>
</select>
这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。
1.5.3 if+set语句
<update id="updateUserById">
update demo_user
<set>
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="sex!=null and sex!=''">
sex=#{sex}
</if>
</set>
where id=#{id}
</update>
如果第一个条件 username 为空,那么 sql 语句为:update demo_user set sex=? where id=?
如果第一个条件不为空,那么 sql 语句为:update demo_user set name = ? ,sex = ? where id=?
1.5.4 choose(when,otherwise) 语句
<select id="selectUserByChoose" resultType="User">
select <include refid="col"></include> from demo_user
<where>
<choose>
<when test="id!=null and id!=''">
id=#{id}
</when>
<when test="name!=null and name!=''">
and name =#{name}
</when>
<otherwise>
and sex=#{sex}
</otherwise>
</choose>
</where>
</select>
有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句
1.5.4 trim 语句
trim标记是一个格式化的标记,可以完成set或者是where标记的功能
①、用 trim 改写上面第二点的 if+where 语句
prefix:前缀
prefixoverride:去掉第一个and或者是or
<select id="selectUserByUsernameAndSex" resultType="User">
select <include refid="col"></include> from demo_user
<trim prefix="where" prefixOverrides="and | or">
<if test="name!=null">
and name=#{name}
</if>
<if test="sex!=null">
and sex=#{sex}
</if>
</trim>
</select>
分析:
1、当name与sex都满足if语句时,此时去除第一个if判断句的and,此时sql语句为 select * from demo_user where name=#{name} and sex=#{sex}
2、当name不满足if语句,sex满足时,那么第二个if语句prefixoverride生效,第二个if语句中的and被去除,此时sql语句为:select * from demo_user where sex=#{sex}
3、相反当name满足,sex不满足时,sql语句为:select * from demo_user where name=#{name}
②、用 trim 改写上面第三点的 if+set 语句
suffix:后缀
suffixoverride:去掉最后一个逗号(也可以是其他的标记,就像是上面前缀中的and一样)
<update id="updateUserById" >
<trim prefix="set" suffixOverrides=",">
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="sex!=null and sex!=''">
sex=#{sex},
</if>
</trim>
</update>
1.5.4 foreach 语句
/**查询ID=1,3,4,6,7的数据
*/
@Test
public void test6(){
int [] ids={1,3,4,6,7};
List<User> list = userMapper.selectByIds(ids);
for (User user:list) {
System.out.println(user);
}
}
<select id="selectByIds" resultType="User">
select <include refid="col"></include> from demo_user
<where>
id in
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</where>
</select>
2. MybatisPlus
2.1 MP介绍
特性
无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
2.2 MP入门案例
2.2.1导入jar包
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
❌注意:mybatis-plus包含mybatis的功能,因此需要将原来安装的mybatis的jar包删除
2.2.2配置对象关系映射
对象关系映射配置:
1、需要将对象与表名一一对应
2、主键绑定,属性名与字段名绑定
/**
* 对象关系映射配置:
* 1、需要将对象与表名--对应
* 2、主键绑定,属性绑定
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@TableName("demo_user")//对象与表名映射
public class User implements Serializable {
//主键自增
@TableId(type=IdType.AUTO)
private Integer id;
/**如果属性与字段同名,注解可以省略*/
//@TableField("name")
private String name;
// @TableField("age")
private Integer age;
// @TableField("sex")
private String sex;
}
2.2.3继承公共API接口
**注意事项:**继承接口时必须添加泛型对象,否则映射表失败
2.2.4 配置映射yml文件
#springboot整合了MP
mybatis-plus:
mapper-locations: classpath:/mapper/*.xml
type-aliases-package: com.jt.pojo
configuration:
map-underscore-to-camel-case: true
# 打印sql日志
logging:
level:
com.jt.dao: debug
2.2.5 API测试
@SpringBootTest
public class ControllerTest {
@Autowired
private UserMapper userMapper;
/**MP实现插入信息
*/
@Test
public void test2(){
User user=new User();
user.setId(2).setName("如来佛祖").setAge(200).setSex("男");
userMapper.insert(user);
}
}
2.3 MP原理
1、用户调用User插入操作 userMapper.insert(User 对象)
2、接口方法中需要传递泛型对象,可以根据用户配置的注解找到泛型对象
3、根据用户的接口获取Mapper接口的父级接口BaseMapper,根据BaseMapper中的反向获取User.class的类型
4、根据User.class获取@TableName(“demo_user”)从而获取表名,再根据属性注解 @TableField(“name”)从而获取表中的字段
5、根据上述操作,然后动态的拼接SQL语句
6、最后Mybatis执行SQL语句进行数据库操作
2.4 MP用法
2.4.1 MP根据ID查询
/**MP根据Id查询
*/
@Test
public void test3(){
User user = userMapper.selectById(1);
System.out.println(user);
}
2.4.2 根据age=18 sex=“女”
sql:select * from demo_user where age=? and sex=?
@Test
public void test4() {
User user = new User();
user.setAge(18).setSex("女");
//构建条件构造器--根据user中不为null的属性拼接成条件,默认都是and
QueryWrapper queryWrapper = new QueryWrapper(user);
List<User> list = userMapper.selectList(queryWrapper);
for (User user1 : list) {
System.out.println(user1);
}
}
2.4.3 gt、eq(age>18 sex=“女”)
sql:select * from demo_user where age>18 and sex='女’
@Test
public void test5(){
//queryWrapper进行连着加'.'时,需要为添加泛型 QueryWrapper<User>
QueryWrapper<User> queryWrapper=new QueryWrapper();
queryWrapper.gt("age",18)
.eq("sex","女");
List<User> list = userMapper.selectList(queryWrapper);
for (User user1 : list) {
System.out.println(user1);
}
}
2.4.4 like、likeLeft、likeRight(用模糊查询: 查询name包含"君"的数据)
sql :select * from demo_user where name like '%君%'
@Test
public void test6(){
QueryWrapper<User> queryWrapper=new QueryWrapper();
queryWrapper.like("name", "君");
List<User> list = userMapper.selectList(queryWrapper);
for (User user1 : list) {
System.out.println(user1);
}
}
注意:queryWrapper.likeLeft() / queryWrapper.likeRight() 指的是%所在的位置
sql: select * from demo_user where name like '君%'
//此处的left和right指的是%的位置
@Test
public void test7(){
QueryWrapper queryWrapper=new QueryWrapper();
queryWrapper.likeLeft("name", "君");
List<User> list = userMapper.selectList(queryWrapper);
for (User user1 : list) {
System.out.println(user1);
}
}
2.4.5 notLike(查询名字中不包含“君”子的信息)
sql:select * from demo_user where name not like '%君%'
@Test//查询名字中不包含“君”子的信息
public void test8(){
QueryWrapper queryWrapper=new QueryWrapper();
queryWrapper.notLike("name", "君");
List<User> list = userMapper.selectList(queryWrapper);
for (User user1 : list) {
System.out.println(user1);
}
}
2.4.6 orderByDesc(查询age>18 (按照年龄降序排序),如果年龄相同,按照性别排序)
sql:select * from demo_user order by age,sex
@Test
public void test9(){
QueryWrapper<User> queryWrapper=new QueryWrapper();
queryWrapper.gt("age", 18)
.orderByDesc("age","sex");
List<User> list = userMapper.selectList(queryWrapper);
for (User user1 : list) {
System.out.println(user1);
}
}
2.4.7 in(查询id in 1,3,5,7;)
拓展:in 和 or:
* 在单表中查询 in与or差不多
* 在多表查询中 or的效率更高
sql:select * from demo_user where id in (1,3,5,7)
@Test
public void test10(){
//1、条件构造器
QueryWrapper<User> queryWrapper=new QueryWrapper();
queryWrapper.in("id", 1,3,5,7);
List<User> list = userMapper.selectList(queryWrapper);
for (User user1 : list) {
System.out.println(user1);
}
//2、Mp的特殊方法:尽可能使用对象类型(对象类型中含有方法)
//int[]ids={1,2,3,4,5,6};会报错,因为基本类型中不含方法
Integer [] ids=new Integer[]{1,2,3,4,5,6};
List idList= Arrays.asList(ids);//数组转集合
List<User> list1 = userMapper.selectBatchIds(idList);
for (User user1 : list1) {
System.out.println(user1);
}
}
2.4.8 StringUtils.hasLength() 、eq(condition,column,val)
高级用法:根据name和age动态查询数据
sql:
select <include refid="col"/> from demo_user
<where>
<if test="name!=null">
name=#{name}
</if>
<if test="age!=null">
and age=#{age}
</if>
</where>
````
Condition 判断:当字符串不为空且长度大于0时,会拼接where条件,否则不拼接
```java
@Test
public void test11(){
String name=null;
String sex="女";
QueryWrapper<User> queryWrapper=new QueryWrapper();
//判断是否有值
Boolean nameFlag=StringUtils.hasLength(name);
Boolean sexFlag=StringUtils.hasLength(sex);
queryWrapper.eq(nameFlag,"name", name)
.eq(sexFlag, "sex", sex);
List<User> list1 = userMapper.selectList(queryWrapper);
for (User user1 : list1) {
System.out.println(user1);
}
}
分析:当name=null时,此时的sql语句是:select * from demo_user where sex=?
name条件被省略;
2.4.8 deleteById(Integer x)
/**删除ID=x的语句*/
@Test
public void test12(){
Integer i = userMapper.deleteById(234);
if(i!=null)
{
System.out.println("删除成功!");
}
}
2.4.9 deleteBatchIds(Collection x)
/**删除id in(x,x,x,....)*/
@Test
public void test13(){
Integer [] ids=new Integer[]{50,51,52,53};
List<Integer> list = Arrays.asList(ids);//数组转集合
Integer i=userMapper.deleteBatchIds(list);
if(i!=null)
{
System.out.println("删除成功!");
}
}
2.4.10 删除 name=** and age=**
/**删除name=”小法“ and age=20 的信息
*/
@Test
public void test14(){
QueryWrapper<User> queryWrapper=new QueryWrapper();
queryWrapper.eq("name", "小法")
.eq("age", 20);
Integer i = userMapper.delete(queryWrapper);
if(i!=null)
{
System.out.println("删除成功!");
}
}
2.4.11 修改信息,name=,age=
/**修改 name=”猪八戒“的信息,将name改为”祝君好运“,age=100
*/
@Test
public void test15(){
QueryWrapper<User> queryWrapper=new QueryWrapper();
User user=new User();
user.setName("祝君好运").setAge(100);
queryWrapper.eq("name", "猪八戒");
Integer i = userMapper.update(user, queryWrapper);
if(i!=null)
{
System.out.println("更改成功!");
}
}