可变参数
java中方法参数的位置支持一中语法
方法名([类型]… 变量名)
上面的写法就是可变参数
//声明带有可变参数的方法
public void sum(int... nums){
//参数...表示这个参数指定的变量按照数组来处理
//这种声明方式每个方法只能出现一个
// 而且必须是最后一个参数
//将nums中所有元素的和输出
int sum=0;
for(int i=0;i<nums.length;i++){
sum+=nums[i];
}
System.out.println(sum);
}
@Test
void param(){
//调用可变参数的方法,直接传入多个类型匹配的参数即可
//参数数量不限0~多个都可以
sum(5,9,7,6);
sum();
}
使用可变参数的注意事项
定义方法时:
可变参数必须是方法所有参数的最后一个
方法中将可变参数看做一个数组来操作
方法调用时:
调用可变参数的方法时,可以传入的参数数量不限,类型匹配即可
参数数量不限表示不传参数也可以
直接传入一个类型匹配的数组也可以
Mybatis实现动态删除操作
我们项目中有一个需求,需求一次性删除指定的多个id的行
比如我们要删除id为2,4,7,11的行
一次性删除效率高sql代码如下 delete from t_user where id in(?,?,?,?)
但是每次删除不一定是4个
那么我们就需要根据用户传入的要删除的id的数组生成同样数量的?
这样的需求我们就只能通过xml文件中的动态sql生成实现了
下面我们在UserMapperPlus接口中添加一个方法来对应这个动态的删除
可以采用上面学习的可变参数来声明
代码如下
//实现动态删除的方法
Integer deleteByIds(Integer... ids);
回到UserMapperPlus.xml文件中编写对应这个删除的代码
<!--
删除操作使用 delete标签 id对应接口中的方法名
因为是增删改操作,不需要声明返回值类型resultType,默认就是int
至于参数类型,系统常用的参数都能自动识别 基本数据类型,String,数组等
-->
<!--
collection指定要遍历的数组 array表示参数接收到的数组
item表示遍历的过程中数组中的单个元素,id是这个元素的名称
separator指定循环过程中每次循环间隔出现的分隔符
foreach标签中编写#{}占位符,占位符中的内容是item属性指定的"id"
-->
<delete id="deleteByIds">
delete from t_user where id in(
<foreach collection="array" item="id" separator=",">
#{id}
</foreach>
)
</delete>
测试类开启日志
private static Logger log=
LoggerFactory.getLogger(MybatisPlusTest.class);
测试类
@Autowired
UserMapperPlus userMapper;
@Test
void deleteIds(){
int num=userMapper.deleteByIds(2,4,7,11);
System.out.println(num);
}
Mybatis实现动态修改操作
在开发项目的过程中可能有如下需求:
修改用户信息
用户可能指定某些信息进行修改
可能修改用户名,年龄
也可能修改电话和email,
这个需求可能修改用户的任意一行
如果使用全行修改需要先查询再修改,是比较消耗性能的,我们需要针对用户输入的属性动态生成只修改用户输入属性的sql语句
分析:
如果什么都可以修改参数最好还是User类型
我们可以判断User类型对象有哪些属性被赋值,哪些属性就需要修改,如果为null就不修改
先声明接口中的方法
代码如下
//实现动态修改的方法
Integer updateUserInfo(User user);
xml文件中添加动态修改的代码
<!-- 动态修改方法 -->
<!-- 因为这个方法的参数不是系统提供的常用类型
需要使用parameterType来指定User的全类名 -->
<!-- if标签中需要使用test来指定一个boolean类型结果
如果结果为true 就会将if标签中间的内容生成在sql语句中
这里的具体逻辑是:只要user对象的某个属性不是空,
就生成修改这个属性的sql语句-->
<!-- <set>标签的作用
1.在<set>标签的位置生成set关键字
2.<set>标签会删除最后一个多余的","完成sql语句的生成
-->
<update id="updateUserInfo"
parameterType="cn.tedu.mybatis.model.User">
update t_user
<set>
<if test="username != null">
username=#{username},
</if>
<if test="password != null">
password=#{password},
</if>
<if test="age != null">
age=#{age},
</if>
<if test="phone != null">
phone=#{phone},
</if>
<if test="email != null">
email=#{email}
</if>
</set>
where id=#{id}
</update>
测试类
@Test
void update(){
User user=new User();
user.setId(16);
//user.setUsername("天蓬元帅");
user.setPassword("666");
user.setAge(800);
int num=userMapper.updateUserInfo(user);
System.out.println(num);
}
Mybatis实现动态查询
实际开发中我们经常会遇到这个或类似这样的需求
有如下几种情况
1.不输入条件直接查询
select * from t_user
2.输入某一个条进行查询
select * from t_user where username like ?
3.输入某两个条进行查询
select * from t_user where username like ? and age=?
4.输入三个条进行查询
select * from t_user where username like ? and age=? and phone like ?
实际上上面的查询也是一个根据用户输入的条件动态生成sql语句的过程
UserMapperPlus接口中添加动态查询的方法
代码如下
List<User> findUsersByParam(
@Param("username") String username,
@Param("age") Integer age,
@Param("phone") String phone);
xml文件代码如下
<!-- 动态查询的方法 -->
<!-- 查询是必须声明返回值类型的resultType -->
<!-- Mybatis中一个查询返回一个对象或一个集合返回值的类型
都指定具体的实体类类型 -->
<!-- <where>标签和<set>标签类似
当没有任何条件是where关键字不会出现
当有条件是<where>标签负责处理多余的and-->
<select id="findUsersByParam"
resultType="cn.tedu.mybatis.model.User" >
select
id,username,password,age,phone,email
from
t_user
<where>
<if test="username != null">
username like #{username}
</if>
<if test="age != null">
and age = #{age}
</if>
<if test="phone != null">
and phone like #{phone}
</if>
</where>
</select>
测试类
@Test
void select(){
List<User> users=userMapper.findUsersByParam(
null,24,null);
for(User u:users){
System.out.println(u);
}
}
parameterType和resultType的使用
resultType是指定当前方法的返回值的属性
所有select标签既查询操作必须指明
如果是增删改操作不需要指明默认int
parameterType是指定当前方法参数类型的属性
任何增删改查操作都可能需要
如果参数类型不是基本数据类型不是String,不是数组或集合
那就必须编写,比如我们自己声明创建的实体类就需要编写出来
Mybatis实现关联查询
数据库中的关联关系
关系型数据库表与表之间的关系存在如下几种
一对一
一对多(多对一)
多对多
以一对多为例我们来讲解一下Mybatis框架中处理关联查询的解决方案
我们将t_user表看做是一个员工表
我们再设计一个部门表,让部门和员工表建立一个一对多的关系
既一个部门有多个员工,部门是一的一方,每个员工只能属于一个部门员工是多的一方
要想实现这样的关系我们先要在数据库中建立这样的结构
依次进行如下操作
-- 创建 t_dept表 部门表
create table t_dept(
id int primary key auto_increment comment '部门id',
name varchar(50) not null comment '部门名'
)default charset=utf8
-- t_user表需要添加一个dept_id列表示自己的部门
alter table t_user add column dept_id int
也可以这样: ALTER TABLE t_user ADD COLUMN dept_id INT NOT NULL AFTER email
-- 部门表中添加3行数据表示3个部门
insert into t_dept(name) values('java'),('c++'),('linux')
-- 将id小于10的user的dept_id赋值为1
update t_user set dept_id=1 where id<10
-- 将id大于等于10的user的dept_id赋值为2
update t_user set dept_id=2 where id>=10
两张表的关系依靠t_user表的dept_id列来表示
这个列的值如果是1,表示他是java部门的
但是这个值现在可以随意修改如果随意修改,就不能保证用户的dept_id列的值能够对应一个真实存在的部门了这样是不行的
要想设置dept_id列的取值只能在存在的部门中,那么就需要设置外键约束
-- 创建外键约束
-- 约束t_user表的dept_id列只能从t_dept表的id列中取值
alter table t_user
add constraint dept_user foreign key (dept_id)
references t_dept(id)
-- constraint(约束) references(引用)
外键的创建会使数据引用时不会出现错误数据
使数据库中的数据正确性更高更可靠
但是由于外键带来了很多维护操作,是比较麻烦的
现在有些公司在开发软件时不创建外键,获得更简便的维护
实现连接查询的sql语句
如果我们想查询的结果如下
上面查询的sql语句要这样写
– 查询user的id user的username 和dept的name
select
u.id,username,name
from t_dept d
join t_user u
on d.id=u.dept_id
java中如果想执行这样的连接查询并返回结果的话需要怎么做
最简单的办法就是新建一个实体类来完成这个连接查询
创建一个UserVo类代码如下(VO: Value Object)
@Data
public class UserVo {
private Integer id;
private String username;
private String deptname;
}
mapper包中新建一个接口XmlMapper代码如下
@Repository
public interface XmlMapper {
//连接查询的方法
List<UserVo> findUserDept();
}
这个接口要对应一个新的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="cn.tedu.mybatis.mapper.XmlMapper">
<select id="findUserDept"
resultType="cn.tedu.mybatis.vo.UserVo">
select
u.id,username,name deptname 别名要对应pojo中的名字
from t_dept d
join t_user u
on d.id=u.dept_id
</select>
</mapper>
测试代码
@Autowired
XmlMapper xmlMapper;
@Test
void join(){
List<UserVo> users=xmlMapper.findUserDept();
for(UserVo user: users){
System.out.println(user);
}
}
使用Mybatis查询返回关联查询结果
实际开发中如果遇到较多的连接查询
每个连接查询都创建不同的Vo类的话,Vo类的数量就会比较多
看一下这个图的结构
这个图的含义是我们可以创建一个Dept类型的实体类对应t_dept表
在这个实体类中我们可以声明一个集合保存若干user\员工的信息
Dept类的代码如下
@Data
public class Dept {
private Integer id;
private String name;
//声明一个保存员工对象的集合
private List<User> users;
}
我们编写一个根据指定部门id 查询部门信息和这个部门包含的所有员工的信息的sql语句
代码如下
select
*
from
t_dept d
left join
t_user u
on
d.id=u.dept_id
where d.id=1
要实现上面的查询我们就需要在接口中添加一个方法
继续在XmlMapper接口中添加方法
//查询部门关联部门员工的方法
Dept findDeptWithUserById(Integer id);
在XmlMapper.xml文件中添加代码如下
注意resultMap的使用
<!-- 我们需要一个结构的声明
这个结构是一个Dept类型的结构,其中包含Dept中的id和name
还要包含Dept中保存的List<User>users的信息
这里还要对User的每个列(包括sql语句中设置的别名列)
都做出对应关系的声明
这样才能让Mybatis在返回一个Dept对象时也能将Dept中的User集合中
的每个员工赋上值
-->
<!-- resultMap就是专门来设置每个列和对象中每个属性的映射关系的
它支持映射一个对象中的集合中的列
id是resultMap的唯一标识,哪个查询需要哪个查询指定
type指定这个结果返回值的载体,这里指包含着员工信息的Dept对象-->
<resultMap id="deptMap" type="cn.tedu.mybatis.model.Dept">
<!-- 一个result标签表示一条对应关系,
指java中的哪个属性对应数据库中的哪个列
column指定数据库查询结果的列名,对应数据库 ,property指定实例类中的属性名-->
<result column="id" property="id" />
<result column="name" property="name"/>
<!-- collection是集合的意思,表示当前Dept类
除了id和name之外还有一个集合
property指定集合的属性名
ofType指定集合的泛型的类型-->
<collection property="users"
ofType="cn.tedu.mybatis.model.User">
<!-- 这里来指定本次查询的哪个列对应user对象的哪个属性 -->
<result column="userId" property="id" />
<result column="username" property="username" />
<result column="password" property="password" />
<result column="age" property="age" />
<result column="phone" property="phone" />
<result column="email" property="email" />
</collection>
</resultMap>
<select id="findDeptWithUserById"
resultMap="deptMap">
select
d.id,
name,
u.id userId,
username,
password,
age,
phone,
email
from
t_dept d
left join
t_user u
on
d.id=u.dept_id
where d.id=#{id}
</select>
测试代码
@Test
void dept(){
Dept d=xmlMapper.findDeptWithUserById(3);
System.out.println(d);
}
代码
查询示意图